From: gdb-3.1 Date: Tue, 31 Jan 1989 17:56:40 +0000 (+0000) Subject: gdb-3.1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e91b87a36830d061ef87d67be5f309e4d4ed918f;p=platform%2Fupstream%2Fbinutils.git gdb-3.1 --- diff --git a/gdb/.gdbinit b/gdb/.gdbinit new file mode 100644 index 0000000..c9e6296 --- /dev/null +++ b/gdb/.gdbinit @@ -0,0 +1,13 @@ +b fatal + +b info_command +commands + silent + return +end + +define rr + run +end + +set prompt (top-gdb) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7099697..8a68eed 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,1603 +1,1804 @@ -Sat Sep 3 12:05:36 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) +Tue Jan 31 12:56:01 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * Version 2.8 released. + * values.c (modify_field): Changed test for endianness to assign + to integer and reference character (so that all bits would be + defined). - * valprint.c: include param.h. +Mon Jan 30 11:41:21 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * inflow.c (store_inferior_registers): Fix typo and missing decl. + * news-dep.c: Deleted inclusion of fcntl.h; just duplicates stuff + found in sys/file.h. -Thu Sep 1 13:18:22 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + * i386-dep.c: Included default definition of N_SET_MAGIC for + COFF_FORMAT. - * Version 2.7 released. + * config.gdb: Added checks for several different operating + systems. - * m-hp9k320bsd.h: New file supports BSD on hp9000 series 300. + * coffread.c (read_struct_type): Put in a flag variable so that + one could tell when you got to the end of a structure. -Tue Aug 30 17:54:50 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + * sun3-dep.c (core_file_command): Changed #ifdef based on SUNOS4 + to ifdef based on FPU. - * m-news.h ({EXTRACT,STORE}_RETURN_VALUE): Handle floating pt values. + * infrun.c (restore_inferior_status): Changed error message to + "unable to restore previously selected frame". - * inflow.c (store_inferior_registers) [usual case]: - Handle registers longer than one word. + * 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. -Sat Aug 27 00:19:32 1988 Richard Stallman (rms at spiff) + * coffread.c (unrecrod_misc_function, read_coff_symtab): Added + symbol number on which error occured to error output. - * inflow.c (create_inferior): Use execve to avoid NEWSOS bug in execle. +Fri Jan 27 11:55:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Wed Aug 10 20:36:36 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + * Makefile: Removed init.c in make clean. Removed it without -f + and with leading - in make ?gdb. - * m-news.h: Define READ_DBX_FORMAT, {EXTRACT,STORE}_RETURN_VALUE. - (INVALID_FLOAT): Add 2nd argument. - (vprintf): Define to call _doprnt. +Thu Jan 26 15:08:03 1989 Randall Smith (randy at gluteus.ai.mit.edu) -Tue Jul 26 03:05:28 1988 Peter TerMaat (pete at corn-chex.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. - * symmisc.c: (print_symtabs) Check the status of the fopen and - call perror_with_name if needed. + * coffread.c (read_coff_symtab): Avoided treating typedefs as + external symbol definitions. -Sat Jul 23 00:14:20 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) +Wed Jan 25 14:45:43 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * printcmd.c: (delete_display) Check for existence of display - chain before deleting anything. + * Makefile: Removed reference to alloca.c. If they need it, they + can pull alloca.o from the gnu-emacs directory. -Thu Jul 7 08:47:03 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + * version.c, gdb.texinfo: Updated version to 3.1 (jumping the gun + a bit so that I won't forget when I release). - * main.c: New vars win_argv, win_argc, win_prgm to talk to xgdb. + * 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. -Thu Jul 7 02:05:29 1988 Pete TerMaat (pete at frosted-flakes.ai.mit.edu) + 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: (define_symbol) store static functions ('f') in the - same way as global functions ('F') -- that is, as `function of - type X' rather than as `X'. + * dbxread.c (read_dbx_symtab): Killed PROFILE_SYMBOLS ifdef. -Mon Jul 4 17:07:31 1988 Pete TerMaat (pete at frosted-flakes.ai.mit.edu) + * sparc-dep.c (isabranch): Multiplied offset by 4 before adding it + to addr to get target. - * dbxread.c: (read_dbx_symtab) Avoid reading symbol tables of - libraries by checking for symbols which begin with "-l" (in - addition to those which end with ".o"). + * Makefile: Added definition of SHELL to Makefile. -Mon Jun 27 23:27:51 1988 Pete TerMaat (pete at frosted-flakes.ai.mit.edu) + * 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. - * dbxread.c: (define_symbol) and coffread.c: (process_coff_symbol) - If the current symbol is a function, assign its type to be - `function of type X' rather than `X'. TYPE_TARGET_TYPE (symbol) - is `X' +Tue Jan 24 17:59:14 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * findvar.c: (locate_var_value, read_var_value) got rid of checks - for LOC_BLOCK which called `lookup_function_type'. These checks - are no longer needed because of the change to dbxread.c. + * dbxread.c (read_array_type): Added function. + (read_type): Added call to above instead of inline code. - * infcmd.c: (finish_command) Now uses target_type instead of type - for functions, in keeping with the change to dbxread.c. + * Makefile: Added ${GNU_MALLOC} to the list of dependencies for + the executables. -Sat Jun 25 00:24:09 1988 Pete TerMaat (pete at corn-chex.ai.mit.edu) +Mon Jan 23 15:08:51 1989 Randall Smith (randy at plantaris.ai.mit.edu) - * infrun.c: (normal_stop) Added a check for permissions on the - exec file before printing the "You have encountered a bug in sh" - message. Apparently on some systems an attempt by the shell to - exec an unexecutable file had resulted in the "You have - encountered" message. + * 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. -Wed Jun 22 00:00:02 1988 Pete TerMaat (pete at corn-chex.ai.mit.edu) + * 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. - * config.gdb: installed shell script to make the proper links to - param.h, m-init.h, opcode.h, and pinsn.c, given a machine name. +Sun Jan 22 01:00:13 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Tue Jun 21 23:55:09 1988 Pete TerMaat (pete at corn-chex.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) - * m-suninit.h, m-isi-ov.h, m-news800.h: moved to m-sun3init.h, - m-isi.h, m-news.h for consistency. + * dbxread.c (read_range_type): Fixed assumption that integer was + always type 1. -Fri Jun 17 21:24:48 1988 Pete TerMaat (pete at lucky-charms.ai.mit.edu) + * gdb.texinfo: Fixed spelling mistake and added a note in the + running section making it clear that users may invoke subroutines + directly from gdb. - * m-umax.h: (FIX_CALL_DUMMY): fixed typo (the last `flipped' was - `fliped') + * 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. - * m-pn.h, m-npl.h: added #define gould, since this is needed in - core.c. +Fri Jan 20 12:25:35 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Tue Jun 14 04:07:50 1988 Pete TerMaat (pete at lucky-charms.ai.mit.edu) + * core.c: Added default definition of N_MAGIC for COFF_FORMAT. - * Removed unused variables from m-pn.h, m-npl.h in - FRAME_FIND_SAVED_REGS, PUSH_DUMMY_FRAME, and POP_FRAME. + * xgdb.c: Installed a fix to keep the thing from dying when there + isn't any frame selected. -Mon Jun 13 05:57:47 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + * core.c: Made a change for the UMAX system; needs a different + file included if using that core format. - * inflow.c (create_inferior): Allow two macros SHELL_FILE and - SHELL_COMMAND_CONCAT, if defined, to customize how the shell is run. + * Makefile: Deleted duplicate obstack.h in dbxread.c dependency. -Thu Jun 9 05:42:20 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + * munch: Modified (much simpler) to cover (I hope) all cases. - * breakpoint.c (ignore_command): P was used before initialized. + * 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. -Fri Jun 3 06:52:25 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + * 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. - * dbxread.c (read_dbx_symtab): Change handling of N_NBTEXT (Gould). + * printcmd.c (print_frame_args): Modified to print out register + params in order by .stabs entry, not by register number. -Mon May 30 22:48:48 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + * 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). - * main.c (main, disconnect): Handle SIGHUP by killing inferior. - * inflow.c (kill_inferior_fast): New function used to do that. + * i386-dep.c (i386_get_frame_setup): Replace function with new + function provided by pace to fix bug in recognizing prologue. - * utils.c (printchar): New 3rd arg is the string's delimiter, - which is the char that needs backslashing. - * valprint.c (value_print, val_print): Pass new arg. - * expprint.c (print_subexp): Pass new arg. +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. -Mon May 23 14:54:54 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) +Wed Jan 18 20:09:39 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * source.c (print_source_lines): New arg NOERROR nonzero means - if file is not found just print message and return (don't throw). - Callers changed here and in stack.c. + * value.h: Deleted struct partial_storage; left over from + yesterday. -Sun May 22 14:22:54 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * 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. - * source.c (identify_source_line): Set defaults for `list' command. +Tue Jan 17 13:50:18 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * value.h: Added lval_reg_partsaved to enum lval_type and + commented enum lval_type. Commented value structure. + Added "struct partial_register_saved" to value struct; added + macros to deal with structure to value.h. + * values.c (free_value): Created; special cases lval_reg_partsaved + (which has a pointer to an array which also needs to be free). + (free_all_values, clear_value_history, set_internalvar, + clear_internalvars): Modified to use free_values. + + * m-sunos4.h: Changed name to sun3os4.h. + * m-sun2os4.h, m-sun4os4.h: Created. + * config.gdb: Added configuration entries for each of the above. + * Makefile: Added into correct lists. + + * Makefile: Added dependencies on a.out.encap.h. Made + a.out.encap.h dependent on a.out.gnu.h and dbxread.c dependent on + stab.gnu.h. + + * infrun.c, remote.c: Removed inclusion of any a.out.h files in + these files; they aren't needed. + + * README: Added comment about bug reporting and comment about + xgdb. + + * Makefile: Added note to HPUX dependent section warning about + problems if compiled with gcc and mentioning the need to add + -Ihp-include to CFLAGS if you compile on those systems. Added a + note about needing the GNU nm with compilers *of gdb* that use the + coff encapsulate feature also. * hp-include: Made symbolic link + over to /gp/gnu/binutils. + + * Makefile: Added TSOBS NTSOBS OBSTACK and REGEX to list of things + to delete in "make clean". Also changed "squeakyclean" target as + "realclean". + + * findvar.c (value_from_register): Added assignment of VALUE_LVAL + to be lval_memory when that is appropriate (original code didn't + bother because it assumed that it was working with a pre lval + memoried value). + + * expread.y (yylex): Changed to only return type THIS if the + symbol "$this" is defined in some block superior or equal to the + current expression context block. + +Mon Jan 16 13:56:44 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-*.h (FRAME_CHAIN_VALID): On machines which check the relation + of FRAME_SAVED_PC (thisframe) to first_object_file_end (all except + gould), make sure that the pc of the current frame also passes (in + case someone stops in _start). + + * findvar.c (value_of_register): Changed error message in case of + no inferior or core file. + + * infcmd.c (registers_info): Added a check for inferior or core + file; error message if not. + + * main.c (gdb_read_line): Modified to take prompt as argument and + output it to stdout. + * infcmd.c (registers_info, signals_info), main.c (command_loop, + read_command_lines, copying_info), symtab.c (decode_line_2, + output_source_filename, MORE, list_symbols): Changed calling + convention used to call gdb_read_line. + + * infcmd.c, infrun.c, main.c, symtab.c: Changed the name of the + function "read_line" to "gdb_read_line". + * breakpoint.c: Deleted external referenced to function + "read_line" (not needed by code). + +Fri Jan 13 12:22:05 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * i386-dep.c: Include a.out.encap.h if COFF_ENCAPSULATE. + (N_SET_MAGIC): Defined if not defined by include file. + (core_file_command): Used N_SET_MAGIC instead of assignment to + a_magic. + (exec_file_command): Stuck in a HEADER_SEEK_FD. + + * config.gdb: Added i386-dep.c as depfile for i386gas choice. + + * munch: Added -I. to cc to pick up things included by the param + file. + + * stab.gnu.def: Changed name to stab.def (stab.gnu.h needs this name). + * Makefile: Changed name here also. + * dbxread.c: Changed name of gnu-stab.h to stab.gnu.h. + + * gnu-stab.h: Changed name to stab.gnu.h. + * stab.gnu.def: Added as link to binutils. + * Makefile: Put both in in the distribution. + +Thu Jan 12 11:33:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c: Made which stab.h is included dependent on + COFF_ENCAPSULATE; either or "gnu-stab.h". + * Makefile: Included gnu-stab.h in the list of files to include in + the distribution. + * gnu-stab.h: Made a link to /gp/gnu/binutils/stab.h + + * Makefile: Included a.out.gnu.h and m-i386gas.h in list of + distribution files. + * m-i386gas.h: Changed to include m-i386.h and fiddle with it + instead of being a whole new file. + * a.out.gnu.h: Made a link to /gp/gnu/binutils/a.out.gnu.h. + + Chris Hanson's changes to gdb for hp Unix. + * Makefile: Modified comments on hpux. + * hp9k320-dep.c: #define'd WOPR & moved inclusion of signal.h + * inflow.c: Moved around declaratiosn of and + inside of USG depends and deleted all SYSV ifdef's + (use USG instead). + * munch: Modified to accept any number of spaces between the T and + the symbol name. + + Pace's changes to gdb to work with COFF_ENCAPSULATE (robotussin): + * config.gdb: Added i386gas to targets. + * default-dep.c: Include a.out.encap.h if COFF_ENCAPSULATE. + (N_SET_MAGIC): Defined if not defined by include file. + (core_file_command): Used N_SET_MAGIC instead of assignment to a_magic. + (exec_file_command): Stuck in a HEADER_SEEK_FD. + * infrun.c, remote.c: Added an include of a.out.encap.h if + COFF_ENCAPSULATE defined. This is commented out in these two + files, I presume because the definitions aren't used. + * m-i386gas.h: Created. + * dbxread.c: Included defintions for USG. + (READ_FILE_HEADERS): Now uses HEADER_SEEK_FD if it exists. + (symbol_file_command): Deleted use of HEADER_SEEK_FD. + * core.c: Deleted extra definition of COFF_FORMAT. + (N_MAGIC): Defined to be a_magic if not already defined. + (validate_files): USed N_MAGIC instead of reading a_magic. - * dbxread.c (sort_syms): If not sorting the block, reverse it, so - that for a parm declared register the register comes before the parm. +Wed Jan 11 12:51:00 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * defs.h: declare alloca. + * remote.c: Upped PBUFSIZ. + (getpkt): Added zeroing of c inside loop in case of error retry. -Fri May 20 15:02:50 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * 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. - * values.c (value_of_internalvar): `return' stmt was missing. + * gdb.texinfo: Added the fact that the return value for a function + is printed if you use return. -Tue May 10 23:03:29 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + * 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. - * source.c ({forward,reverse}_search_command, print_source_lines): - Line number symtab->nlines is just barely in range. - (find_source_lines): Newline as last char in file doesn't start a line. +Tue Jan 10 17:04:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Thu May 5 15:04:40 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * xgdb.c (xgdb_create_window): Removed third arg (XtDepth) to + frameArgs. - * Version 2.6. + * 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. - * printcmd.c (do_one_display): New fn, display one auto-display. - (do_displays): Use that fn. - (display_command): If cmd is from tty, display the new display now. + * 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). - * printcmd.c (do_display): Record # of display being displayed. - (delete_current_display): New fn: delete that display (if any). - * main.c (return_to_top_level): Call delete_current_display. - * infrun.c (normal_stop): Likewise. +Fri Jan 6 17:57:34 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * main.c (catch_error): New fn: like list `errset'. - * breakpoint.c (breakpoint_cond_eval): Eval an expression and - return 1 if the expression is zero. - (breakpoint_stop_status): Use those two fcns; avoid lossage on error - in evalling a breakpoint condition. + * 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. - * infcmd.c (jump_command): Typo in call to `query'. + * i386-dep.c (i386_get_frame_setup): Added codestream_get() to + move codestream pointer up to the correct location in "subl $X, + %esp" case. -Tue May 3 10:52:08 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) +Sun Jan 1 14:24:35 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * core.c (exec_file_command): If no file, pass 0 to display-hook. + * valprint.c (val_print): Rewrote routine to print string pointed + to by char pointer; was producing incorrect results when print_max + was 0. - * core.c (get_exec_file): New arg ERR says whether to err if no file. - All callers changed. +Fri Dec 30 12:13:35 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * main.c (print_prompt): New fn to print the prompt string. + * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Put + everything on the misc function list. - * xgdb.c: Numerous changes. It now semi-works but the text display - often gets messed up. + * Checkpointed distribution. -Sun May 1 12:12:43 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * Makefile: Added expread.tab.c to the list of things slated for + distribution. - * wait.h [HAVE_WAIT_STRUCT] (WSETSTOP): Fix typos. +Thu Dec 29 10:06:41 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Sat Apr 30 10:18:56 1988 Richard Stallman (rms at frosted-flakes.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. - * expread.y: BLOCK::NAME action called copy_name in wrong place. +Wed Dec 28 11:43:09 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Fri Apr 15 01:01:40 1988 Chris Hanson (cph at kleph) + * 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. - * inflow.c [! TIOCGPGRP]: Do not call `setpgrp' for inferior. - Instead, disable SIGINT and SIGQUIT while the inferior is running. - Unfortunately this means that C-c typed while GDB is running will - cause the inferior to receive SIGINT when it is resumed. - * utils.c (quit) [! TIOCGPGRP]: Cause quit message to remind user - that the inferior will see SIGINT. + * gdb.texinfo: Documented changes to "backtrace" and "commands" + commands. -Thu Apr 14 23:38:02 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * 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. - * infrun.c (wait_for_inferior): If step into a function, and - immediately arrive at start of first line of user code, - don't step: stop immediately. - Set prev_pc before, not after, calling `resume'. + * breakpoint.c (commands_command): Altered so that "commands" with + no argument would refer to the last breakpoint set. + (_initialize_breakpoint): Modified help documentation. - * source.c (identify_source_line): New 3rd arg controls additional - output datum: `beg' or `middle', saying whether pc is at beg of line. - * stack.c (print_frame_info): Pass that argument. + * 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. - * main.c (cd_command): Convert any relative pathname to absolute. - Simplify if `.' or `..' appear. + * sparc-dep.c (single_step): Fixed typo; "break_insn" ==> "sizeof + break_insn". -Thu Apr 14 21:17:11 1988 Chris Hanson (cph at kleph) + * 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. - * infrun.c: Add new flag `trap_expected_after_continue' to - compensate for spurious trace trap generated by HP-UX after - running a stack dummy. + * dbxread.c (read_dbx_symtab): Check to make sure we don't add a + psymtab to it's own dependency list. - * inflow.c (term_status_command) [HAVE_TERMIO]: Show all available - terminal status information. + * dbxread.c (read_dbx_symtab): Modified check for duplicate + dependencies to catch them correctly. -Tue Apr 12 19:11:00 1988 Chris Hanson (cph at kleph) +Tue Dec 27 17:02:09 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * stack.c (print_frame_info): When -fullname is given and - `identify_source_line' succeeds, do not print real pc even if it - differs from the start pc for the source line. This information - is not very useful and tends to screw up gdb-mode in emacs. + * 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. -Mon Apr 11 14:22:10 1988 Chris Hanson (cph at kleph) + * 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. - * dbxread.c (define_symbol): Don't forget to terminate - SYMBOL_NAME. + * 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-hp9k320.h (CALL_DUMMY): Fix bug -- breakpoint instruction is - TRAP #1 not TRAP #15. + * m-sparc.h: Cosmetic changes; reordered some macros and made sure + that nothing went over 80 lines. - * inflow.c (store_inferior_register_1) [HP9K320]: Ignore `errno', - as there is a bug in HP-UX which (mistakenly) causes errno to be - non-zero when writing fp7. +Thu Dec 22 11:49:15 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Sat Apr 9 01:04:23 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * Version 3.0 released. - * dbxread.c (symbol_file_command): Check stringtab size by doing `stat' - and, if it is ridiculous, complain and don't call alloca. - Don't discard existing symtab until after that check. + * README: Deleted note about changing -lobstack to obstack.o. -Fri Apr 8 16:39:11 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) +Wed Dec 21 11:12:47 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * Makefile: Delete `-lg' entirely; not needed now that linking is done - with $(CC). + * m-vax.h (SKIP_PROLOGUE): Now recognizes gcc prologue also. -Fri Apr 8 13:41:46 1988 Chris Hanson (cph at kleph) + * blockframe.c (get_prev_frame_info): Added FUNCTION_START_OFFSET + to result of get_pc_function_start. + * infrun.c (wait_for_inferior): Same. - * m68k-opcode.h: Fix operand-string of fmovel insns. + * gdb.texinfo: Documented new "step" and "next" behavior in + functions without line number information. - * Makefile: Put "-lg" in CLIBS because there is no such library in - HPUX. Update the comment for HPUX. +Tue Dec 20 18:00:45 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Fri Apr 8 03:30:23 1988 Richard Stallman (rms at frosted-flakes.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. - * findvar.c (locate_var_value): For &FCN, do lookup_function_type. + * symtab.c (find_pc_line): Zero "end" subsection of returned + symtab_and_line if no symtab found. - * valprint.c (val_print): Fix typo testing whether ptr is a string. +Mon Dec 19 17:44:35 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Thu Apr 7 21:11:00 1988 Chris Hanson (cph at frosted-flakes.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. + - * m-hp9k320.h: New file. +Sun Dec 18 11:15:03 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * main.c (stop_sig, read_line): #ifdef SIGTSTP around uses of SIGTSTP. + * 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. - * wait.h: Fix bug in WSETEXIT. + * 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. - * remote.c: If HAVE_TERMIO, use termio and fake it to look like stty. - Include wait.h - (remote_wait): Use the wait.h interface. + * main.c (copying_info): Seperated the last printf into two + printfs. The 386 compiler will now handle it. - * utils.c (quit): Need HAVE_TERMIO conditional. Also include param.h. + * 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. - * inflow.c: If HAVE_TERMIO, use termio and fake it to look like stty. - Define TERMINAL for data type of terminal data. - Use of tchars, ltchars, pgrp conditional on existence of the - ioctls that handle them. - (terminal_init_inferior, terminal_inferior, terminal_ours, - term_status_command, initialize): - Conditionals for HAVE_TERMIO and existence of various ioctls. - ({fetch,store}_inferior_registers): Separate versions for HP9K320. +Sat Dec 17 15:31:38 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * m68k-pinsn.c (convert_{to,from}_68881): Alternate asms for HPUX_ASM. + * 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. - * core.c (register_addr): Change #ifdef to REGISTER_U_ADDR - (core_file_command) [HP9K320]: Special code to get regs from HPUX - core file. + * 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. -Thu Apr 7 01:15:56 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * values.c (value_static_field): Fixed dereferencing of null + pointer. - * dbxread.c (add_symbol_to_list, finish_block, read_enum_type): - Symbol-lists now hold up to 20 symbols in each `struct pending' - to save time in malloc. When a `struct pending' becomes free, - don't call `free'; put it on a free-list `free_pendings'. - (really_free_pendings): Call `free' for each `struct pending' - on the free-list, and others that are easily found. - (symbol_file_command): Set up `really_free_pendings' as a cleanup. + * i386-dep.c (i386_follow_jump): Modified to deal with + unconditional byte offsets also. - * dbxread.c (start_symtab, end_symtab, process_one_symbol): - Context_stack is now contiguous, to save malloc-time. + * dbxread.c (read_type): Fixed typo in function type case of switch. - * dbxread.c (read_enum_type): Allocate the enum const syms - in the symbol_obstack. - (obsavestring): New fn, like savestring but alloc in symbol_obstack. - (obconcat): New fn, like concat but etc. - Most calls to savestring and concat changed to call these fns. - (define_symbol): Open-code bcopy; don't bother to zero the symbol. - (compare_symbols): Compare 1st char of name before calling strcmp. + * infcmd.c (run_command): Does not prompt to restart if command is + not from a tty. - * Do explicit buffering to read symtab--don't use stdio. - Variables symbuf... hold the buffer and indices. - * dbxread.c (fill_symbuf): Fill the buffer, record how much was read. - (read_dbx_symbols, next_symbol_text): Fetch data direct from buffer; - call fill_symbuf when necessary. +Fri Dec 16 15:21:58 1988 Randy Smith (randy at calvin) - * dbxread.c (sort_syms): Don't sort blocks with < 40 syms. - * symtab.c (lookup_block_symbol): Don't binary search such blocks. - Compare 1st char of name before calling strcmp, and other speedups. + * gdb.texinfo: Added a third option under the "Cannot Insert + Breakpoints" workarounds. - * symtab.c (sort_block_syms): New fn, sort one block's syms. - (list_symbols): If block not normally sorted, sort it here. + * printcmd.c (display_command): Don't do the display unless there + is an active inferior; only set it. - * dbxread.c (define_symbol): Ignore sym if name is empty. - (process_one_symbol): Ignore N_ENTRY sym if no N_SO seen yet. - (read_dbx_symtab): Recognize N_NBTEXT like N_TEXT (if it's defined). - Set end_of_text_addr from END_OF_TEXT_DEFAULT (if it's defined). - (NUMBER_OF_SYMBOLS): New macro for # entries in symtab. - (SYMBOL_TABLE_OFFSET): New macro for file-offset of symtab. - (STRING_TABLE_OFFSET): New macro for file-offset of string tab. - (READ_STRING_TABLE_SIZE): New macro to store size of string tab. - (DECLARE_FILE_HEADERS): New macro to declare vars to hold header info. - (READ_FILE_HEADERS): New macro to read that info from a descriptor. - All these macros can be overriden by the m-....h file. - (symbol_file_command): These macros replace open code. + * 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. - * values.c (unpack_double): When fetching `double' from memory, - make it double-aligned, since some machines need that. + * config.gdb: Added reminder about modifying REGEX in the + makefile for the 386. - * core.c (exec_file_command): Insert conditionals for `gould'. + * i386-pinsn.c, i386-dep.c: Moved m-i386.h helper functions over + to i386-dep.c.b - * m-sun[23].h, m-isi-ov.h, m-news800.h (ABOUT_TO_RETURN): - Fix typo in opcode number. +Thu Dec 15 14:04:25 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * main.c (read_line): Ignore backslash-newline. + * README: Added a couple of notes about compiling gdb with itself. -Fri Apr 1 17:37:25 1988 Richard M. Stallman (rms at frosted-flakes.ai.mit.edu) + * breakpoint.c (set_momentary_breakpoint): Only takes FRAME_FP of + frame if frame is non-zero. - * main.c (main): New -c switch specifies current directory. - Discard trailing slash from arg. - (pwd_command): Call getwd. Print its result as well as - current_directory if they differ. - (cd_command): Leave user's form of path in current_directory. - Discard trailing slash from arg. + * 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. - * source.c (init_source_path, directory_command): - Use current_directory rather than calling getwd. +Wed Dec 14 13:27:04 1988 Randall Smith (randy at gluteus.ai.mit.edu) -Fri Mar 25 14:51:39 1988 Richard M. Stallman (rms at frosted-flakes.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. - * dbxread.c (read_struct_type): Only ints and enums can be bit-fields. + * symmisc.c (free_all_psymtabs): Reinited partial_symtab_list to 0. + (_initialize_symmisc): Initialized both symtab_list and + partial_symtab_list. - * command.c (lookup_command): Allow 0 in command name. + * 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. - * valprint.c (value_print): New arg FORMAT. Most callers pass 0. - Pass FORMAT to val_print. - (val_print): New arg FORMAT. Most callers pass 0. - When FORMAT is nonzero, use `print_scalar_formatted' to print a scalar - and inhibit special treatment of char-pointers and arrays. + * 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. - * printcmd.c (print_scalar_formatted): Guts of `print_formatted' - broken out, except for `i', `s' and 0 formats. - Type and data-address passed separately. + * symmisc.c (free_psymtab, free_all_psymtabs): Deleted + free_psymtab subroutine. - * valprint.c (val_print): Any array of 1-byte ints is a string; - any 1-byte int is a character. + * 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. -Thu Mar 24 23:01:24 1988 Richard M. Stallman (rms at frosted-flakes.ai.mit.edu) +Tue Dec 13 14:48:14 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * coffread.c: - Make read_coff_symtab interruptible. - Use obstack rather than xmalloc for blocks, blockvectors and symbols. - Fix error checking for reading the stringtab. + * i386-pinsn.c: Reformatted entire file to correspond to gnu + software indentation conventions. - * ns32k-pinsn.c (fbit_extract): New function. - (print_insn_arg): Use it for immediate floating args. - Also print float reg args as `f', not `r'. + * sparc-dep.c (skip_prologue): Added capability of recognizign + stores of input register parameters into stack slots. - * m68k-opcode.h: mulu and muluw had wrong arg-format-string. + * 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. - * valprint.c (value_print): Any pointer to 1-byte ints - is printed as a string. + * 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). - * inflow.c (attach, detach): Change conditional on these to - ATTACH_DETACH. In a UMAX_PTRACE conditional, define the Sun - attach/detach names in terms of the Umax ones. + * 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. - * m-umax.h: Define ATTACH_DETACH. + * symtab.c (output_source_filename): Included "more" emulation hack. - * infcmd.c (attach_command): `remote' was not being initialized. + * 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. - * m-umax.h: Include defs.h if nec so that CORE_ADDR is defined. + * 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. - * m-umax.h, m-vax.h: Define vprintf to use _doprnt. - * m-isi-ov.h, m-merlin.h: Likewise. + * Makefile: Took removal of expread.tab.c out of make clean entry + and put it into a new "squeakyclean" entry. - * inflow.c [UMAX_PTRACE]: Don't include user.h; do include sys/ptrace.h +Mon Dec 12 13:21:02 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * m-umax.h: Rename `n32k...' to `ns32k...'. - * ns32k-pinsn.c: Likewise. + * sparc-pinsn.c (skip_prologue): Changed a struct insn_fmt to a + union insn_fmt. - * stack.c (print_block_frame_locals): Mention static locals as well. + * inflow.c (terminal_inferior): Checked *all* return codes from + ioctl's and fcntl's in routine. - * main.c (validate_comname): Allow 0 in a command name. + * inflow.c (terminal_inferior): Added check for sucess of + TIOCSPGRP ioctl call. Just notifies if bad. - * core.c (myread): If successful, return # chars read. + * dbxread.c (symbol_file_command): Close was getting called twice; + once directly and once through cleanup. Killed the direct call. - * blockframe.c (find_pc_misc_function): Don't die due to index -1 - if there are no misc functions. +Sun Dec 11 19:40:40 1988 & Smith (randy at hobbes.ai.mit.edu) -Sun Mar 20 17:52:00 1988 Richard M. Stallman (rms at frosted-flakes.ai.mit.edu) + * valprint.c (val_print): Deleted spurious printing of "=" from + TYPE_CODE_REF case. - * m-isiinit.h: New file needed on ISI machines. - Symbol BSD43_ISI40D controls choice of system version. +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. - * m-isi-ov.h: BSD43_ISI40D affects REGISTER_U_ADDR. +Fri Dec 9 10:33:24 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Sat Mar 19 17:56:02 1988 Richard M. Stallman (rms at frosted-flakes.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). - * dbxread.c (symbol_file_command): Clear global_sym_chain here - before read_symsegs - (read_dbx_symtab): instead of clearing it here. + * Makefile: Cleaned up some more. - * valprint.c (type_print_base): Handle if TYPE is 0. - (type_print_varspec_{prefix,suffix}): Do nothing if TYPE is 0. + * valops.c, m-*.h (FIX_CALL_DUMMY): Modified to take 5 arguments + as per what sparc needs (programming for a superset of needed + args). - * main.c (copyright_info): Fix typo in string. - * symseg.h: Fix typo in struct. + * 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. -Fri Mar 18 01:07:10 1988 Chris Hanson (cph at kleph) + * inferior.h, infrun.c: Added fields to save in inferior_status + structure. - * breakpoint.c (commands_command): Flush stdout after printing - message for benefit of terminals which are pipes. + * maketarfile: Deleted; functionality is in Makefile now. -Tue Feb 16 18:28:24 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * 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 (process_one_symbol): Ignore some Fortran symbol types. + * dbxread.c (read_dbx_symtab): Made sure that the IGNORE_SYMBOL + macro would be checked during initial readin. -Wed Feb 10 15:48:30 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * 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.". - * Version 2.5. +Thu Dec 8 11:46:22 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * symtab.h: Delete free_explicit. - * symmisc.c (free_all_symtabs): Delete free_explicit case. + * m-sparc.h (FRAME_FIND_SAVED_REGS): Cleaned up a little to take + advantage of the new frame cache system. - * symseg.h (struct source): It contains a linetable. Define linetable. - * symtab.h: Don't define linetable here. + * 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. - * symmisc.c (relocate_source): Relocate the linetable it contains. - * dbxread.c (symbol_file_command): Convert each symseg to one or - more symtabs according to its sourcevector. Give each symtab - a linetable that comes from the sourcevector. + * blockframe.c (get_prev_frame): Simplified this by a direct call + to get_prev_frame_info. - Free old symtabs and Print "Reading..." before reading symsegs. + * 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. - * dbxread.c (start_symtab): If find a current_symseg, return - doing nothing more. - * dbxread.c (end_symtab): If have a current_symseg, - just zero a couple of variables and return. Delete the rest - of the if-statement for current_symseg != 0. + * infcmd.c, sparc-dep.c: Implemented a new mechanism for + re-selecting the selected frame on return from a call. -Sat Feb 6 12:59:29 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * 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. - * findvar.c (locate_var_value): Remove space from middle of `+ ='. + * 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. - * symtab.h (struct symtab): New field `fullname'. - * source.c: Callers of `openp' store the `fullname' field. +Wed Dec 7 12:07:54 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * source.c (identify_source_line): New function prints - ^z^zFILENAME:LINENUM:CHARPOS\n. For Emacs interface (gdb.el). + * frame.h, blockframe.c, m-sparc.h, sparc-dep.c: Changed all calls + to get_[prev_]frame_cache_item to get_[prev_]frame_info. - * main.c (main): `-fullname' option sets `frame_file_full_name'. - * stack.c (print_stack_frame): After printing source line, - if `frame_file_full_name', call `identify_source_line'. + * 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. -Fri Feb 5 00:07:44 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * blockframe.c: Put allocation on an obstack and eliminated fancy + reallocation routines, several variables, and various nasty + things. - * core.c (core_file_command): For UMAX, print the core file's - program name. For UMAX and Sun, print the signal number. + * 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. - * printcmd.c (decode_format): Don't let size `g' be used for integers. + * infcmd.c (finish_command): Used proper method of getting from + function symbol to start of function. Was treating a symbol as a + value. - * coffread.c (read_coff_symtab): Don't lose a file - just because it contains only data and types (no text). + * 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. - * source.c: Rename line_info_default_line to last_line_listed. - * source.c (*_search_command): Use that as default place to start. - Set current_source_line so that `list' with no args is centered - on that line. + * 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. -Thu Feb 4 19:32:31 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * 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. - * dbxread.c (end_symtab): Always initialize symtab->free_ptr. + * 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. - * main.c (main, cd_command): Set up `dirbuf' and `current_directory' - * main.c (pwd_command): Use `current_directory'. + * m-i386.h (STORE_STRUCT_RETURN): Decremented sp by sizeof object + to store (an address) rather than 1. -Wed Feb 3 11:49:10 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + * dbxread.c (read_dbx_symtab): Set first_object_file_end in + read_dbx_symtab (oops). - * remote.c: New file, for communication to remote debugger. + * coffread.c (fill_in_vptr_fieldno): Rewrote TYPE_BASECLASS as + necessary. - * defs.h (current_directory): New variable. +Tue Dec 6 13:03:43 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * core.c (core_file_command): Use current_directory instead of getwd. + * 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). - * inflow.c (callers of ptrace): If remote_debugging, call another - function named remote_... instead of ptrace. + * 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. - * infcmd.c (start_inferior): Special things if remote_debugging. + * 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. - * infcmd.c (attach_command): If arg starts with a slash, - call `remote_open' and `start_remote'. + * 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. - * infcmd.c (run_command): if remote_debugging, - don't hassle the args and don't fork. + * symtab.c (lookup_block_symbol): Take parameter type symbols + (LOC_ARG or LOC_REGPARM) after any other symbols which match. - * infrun.c, inferior.h (remote_debugging): New variable. - * infrun.c (wait_for_inferior): If remote_debugging, use remote_wait. - * infrun.c (start_remote): New function. + * 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. - * symtab.c (find_line_common): Find the linetable entry - for a specified source line, of the first following line that has one. - No longer assumes lines are in increasing order. +Mon Dec 5 11:25:04 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * symtab.c (find_line_pc, find_line_pc_range): Use find_line_common. + * 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 dependency list and cleaned it up somewhat + (used macros, didn't make .o files depend on .c files, etc.) + +Fri Dec 2 11:44:46 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * value.h, values.c, infcmd.c, valops.c, m-i386.h, m-sparc.h, + m-merlin.h, m-npl.h, m-pn.h, m-umax.h, m-vax.h, m-hp9k320.h, + m-isi.h, m-news.h, m-sun2.h, m-sun3.h: Cleaned up dealings with + functions returning structures. Specifically: Added a function + called using_struct_return which indicates whether the function + being called is using the structure returning conventions or it is + using the value returning conventions on that machine. Added a + macro, STORE_STRUCT_RETURN to store the address of the structure + to be copied into wherever it's supposed to go, and changed + call_function to handle all of this correctly. + + * symseg.h, symtab.h, dbxread.c: Added hooks to recognize an + N_TEXT symbol with name "*gcc-compiled*" as being a flag + indicating that a file had been compiled with gcc and setting a + flag in all blocks produced during processing of that file. + +Thu Dec 1 13:54:29 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-sparc.h (PUSH_DUMMY_FRAME): Saved 8 less than the current pc, + as POP_FRAME and sparc return convention restore the pc to 8 more + than the value saved. + + * valops.c, printcmd.c, findvar.c, value.h: Added the routine + value_from_register, to access a specific register of a specific + frame as containing a specific type, and used it in read_var_value + and print_frame_args. + +Wed Nov 30 17:39:50 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (read_number): Will accept either the argument passed + as an ending character, or a null byte as an ending character. + + * Makefile, createtags: Added entry to create tags for gdb + distribution which will make sure currently configured machine + dependent files come first in the list. + +Wed Nov 23 13:27:34 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * stack.c, infcmd.c, sparc-dep.c: Modified record_selected_frame + to work off of frame address. + + * blockframe.c (create_new_frame, get_prev_frame_cache_item): + Added code to reset pointers within frame cache if it must be + realloc'd. + + * dbxread.c (read_dbx_symtab): Added in optimization comparing + last couple of characters instead of first couple to avoid + strcmp's in read_dbx_symtab (recording extern syms in misc + functions or not). 1 call to strlen is balanced out by many fewer + calls to strcmp. + +Tue Nov 22 16:40:14 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) + + * dbxread.c (read_dbx_symtab): Took out optimization for ignoring + LSYM's; was disallowing typedefs. Silly me. + + * Checkpointed distribution (mostly for sending to Tiemann). + + * expression.h: Added BINOP_MIN and BINOP_MAX operators for C++. + * symseg.h: Included flags for types having destructors and + constructors, and flags being defined via public and via + virtual paths. Added fields NEXT_VARIANT, N_BASECLASSES, + and BASECLASSES to this type (tr: Changed types from + having to be derived from a single baseclass to a multiple + base class). + * symtab.h: Added macros to access new fields defined in symseg.h. + Added decl for lookup_basetype_type. + * dbxread.c + (condense_addl_misc_bunches): Function added to condense the misc + function bunches added by reading in a new .o file. + (read_addl_syms): Function added to read in symbols + from a new .o file (incremental linking). + (add_file_command): Command interface function to indicate + incrmental linking of a new .o file; this now calls + read_addl_syms and condense_addl_misc_bunches. + (define_symbol): Modified code to handle types defined from base + types which were not known when the derived class was + output. + (read_struct_type): Modified to better handle description of + struct types as derived types. Possibly derived from + several different base classes. Also added new code to + mark definitions via virtual paths or via public paths. + Killed seperate code to handle classes with destructors + but without constructors and improved marking of classes + as having destructors and constructors. + * infcmd.c: Modified call to val_print (one more argument). + * symtab.c (lookup_member_type): Modified to deal with new + structure in symseg.h. + (lookup_basetype_type): Function added to find or construct a type + ?derived? from the given type. + (decode_line_1): Modified to deal with new type data structures. + Modified to deal with new number of args for + decode_line_2. + (decode_line_2): Changed number of args (?why?). + (init_type): Added inits for new C++ fields from + symseg.h. + *valarith.c + (value_x_binop, value_binop): Added cases for BINOP_MIN & + BINOP_MAX. + * valops.c + (value_struct_elt, check_field, value_struct_elt_for_address): + Changed to deal with multiple possible baseclasses. + (value_of_this): Made SELECTED_FRAME an extern variable. + * valprint.c + (val_print): Added an argument DEREF_REF to dereference references + automatically, instead of printing them like pointers. + Changed number of arguments in recursive calls to itself. + Changed to deal with varibale numbers of base classes. + (value_print): Changed number of arguments to val_print. Print + type of value also if value is a reference. + (type_print_derivation_info): Added function to print out + derivation info a a type. + (type_print_base): Modified to use type_print_derivation_info and + to handle multiple baseclasses. + +Mon Nov 21 10:32:07 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * inflow.c (term_status_command): Add trailing newline to output. + + * sparc-dep.c (do_save_insn, do_restore_insn): Saved + "stop_registers" over the call for the sake of normal_stop and + run_stack_dummy. + + * m-sparc.h (EXTRACT_RETURN_VALUE): Put in parenthesis to force + addition of 8 to the int pointer, not the char pointer. + + * sparc-pinsn.c (print_addr1): Believe that I have gotten the + syntax right for loads and stores as adb does it. + + * symtab.c (list_symbols): Turned search for match on rexegp into + a single loop. + + * dbxread.c (psymtab_to_symtab): Don't read it in if it's already + been read in. + + * dbxread.c (psymtab_to_symtab): Changed error to fatal in + psymtab_to_symtab. + + * expread.y (parse_number): Fixed bug which treated 'l' at end of + number as '0'. + +Fri Nov 18 13:57:33 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Was + being foolish and using pointers into an array I could realloc. + Converted these pointers into integers. + +Wed Nov 16 11:43:10 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-sparc.h (POP_FRAME): Made the new frame be PC_ADJUST of the + old frame. + + * i386-pinsn.c, m-hp9k320.h, m-isi.h, m-merlin.h, m-news.h, + m-npl.h, m-pn.h, m-sparc.h, m-sun2.h, m-sun3.h, m-umax.h, m-vax.h: + Modified POP_FRAME to use the current frame instead of + read_register (FP_REGNUM) and to flush_cached_frames before + setting the current frame. Also added a call to set the current + frame in those POP_FRAMEs that didn't have it. + + * infrun.c (wait_for_inferior): Moved call to set_current_frame up + to guarrantee that the current frame will always be set when a + POP_FRAME is done. + + * infrun.c (normal_stop): Added something to reset the pc of the + current frame (was incorrect because of DECR_PC_AFTER_BREAK). + + * valprint.c (val_print): Changed to check to see if a string was + out of bounds when being printed and to indicate this if so. + + * convex-dep.c (read_inferior_memory): Changed to return the value + of errno if the call failed (which will be 0 if the call + suceeded). + +Tue Nov 15 10:17:15 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * infrun.c (wait_for_inferior): Two changes: 1) Added code to + not trigger the step breakpoint on recursive calls to functions + without frame info, and 2) Added calls to distinguish recursive + calls within a function without a frame (which next/nexti might + wish to step over) from jumps to the beginning of a function + (which it generally doesn't). + + * m-sparc.h (INIT_EXTRA_FRAME_INFO): Bottom set correctly for leaf + parents. + + * blockframe.c (get_prev_frame_cache_item): Put in mod to check + for a leaf node (by presence or lack of function prologue). If + there is a leaf node, it is assumed that SAVED_PC_AFTER_CALL is + valid. Otherwise, FRAME_SAVED_PC or read_pc is used. - * symtab.c (lookup_misc_func): New function to return the index - in misc_function_vector of a specified name. + * 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. - * symtab.c (decode_line_1): Use `lookup_misc_func'. + * blockframe.c, frame.h, stack.c: Killed use of + frame_id_from_frame_info; used frame_id_from_addr instead. - * source.c (forward_search_command, reverse_search_command): - New functions to search a source file. + * blockframe.c, frame.h, stack.c, others (oops): Combined stack + cache and frame info structures. - * source.c (openp): Get dir from `current_directory', not getwd. + * 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. - * source.c (line_info): 2nd arg to decode_line_spec was missing. + * 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. - * printcmd.c (printf_command): New command to do printf - with specified string and arguments. Thoroughly rewritten from - Next's version. + * frame.h: Killed use of FRAME_FP_ID. - * eval.c (parse_to_comma_and_eval): New function. + * 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. - * expread.y (parse_c_1): New arg COMMA means stop parsing at a comma. - * breakpoint.c (condition_command, break_command): Pass 0 for COMMA. - * eval.c (parse_and_eval_address_1): Pass 0 for COMMA. +Mon Nov 14 14:19:32 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * printcmd.c (print_formatted): New arg SIZE so hex nums line up. - Changed all callers (all in this file). + * frame.h, blockframe.c, stack.c, m-sparc.h, sparc-dep.c: Added + mechanisms to deal with possible specification of frames + dyadically. - * dbxread.c (symbol_file_command): Error-check result of alloca. - On some systems it seems it can return zero. +Sun Nov 13 16:03:32 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) - * dbxread.c (read_dbx_symtab): Make this interruptable. + * ns32k-opcode.h: Add insns acbw, acbd. - * blockframe.c (find_pc_misc_function): Use binary search. +Sun Nov 13 15:09:58 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Thu Jan 28 08:48:00 1988 Richard Stallman (rms at frosted-flakes.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). - * m68k-pinsn.c (print_insn_arg): For operand type 'd', - operand value is a register-name. +Fri Nov 11 13:00:22 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Sat Jan 23 01:04:51 1988 Richard Stallman (rms at frosted-flakes.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. - * symseg.h: Add `struct sourcevector', etc., for describing - line number info. + * findvar.c (find_saved_register): Altered bactrace loop to work + off of frames and not frame infos. -Fri Jan 15 05:09:18 1988 Richard Stallman (rms at frosted-flakes) + * 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 (...). - * valprint.c [IEEE_FLOAT]: New function `is_nan' checks - whether a double is a nan. +Thu Nov 10 16:57:57 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * printcmd.c (print_formatted) [IEEE_FLOAT]: - Detect nans and print specially. - * valprint.c (val_print) [IEEE_FLOAT]: Same thing. + * 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. - * m68k-pinsn.c (convert_{to,from}_68881): Hand-assemble - all the assembler code. +Wed Nov 9 17:28:14 1988 Chris Hanson (cph at kleph) - * m-newsinit.h, m-news800.h: Two new files. + * 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. -Thu Jan 7 22:25:16 1988 Richard Stallman (rms at frosted-flakes) + * 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. - * valops.c (value_assign): Don't coerce the arg being stored in. - Coercion is not right either for an array or for an enum. +Wed Nov 9 12:11:37 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) -Tue Jan 5 00:59:29 1988 Richard Stallman (rms at frosted-flakes) + * xgdb.c: Killed include of initialize.h. - * symtab.c (decode_line_1): Don't complain about no symtabs loaded - until after trying the misc function table. + * Pulled in xgdb.c from the net. -Sat Jan 2 13:16:08 1988 Richard Stallman (rms at frosted-flakes) + * Checkpointed distribution (to provide to 3b2 guy). - * stack.c (record_selected_frame): New fn to access - the selected frame and its level. - * infcmd.c (run_stack_dummy): Save and restore the selected - frame and its level. + * 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. -Wed Dec 30 18:44:41 1987 Richard Stallman (rms at frosted-flakes) + * command.c: Deleted local copy of savestring; code in utils.c is + identical. - * valprint.c (type_print_varspec_prefix): - Treat arrays just like functions. - * valprint.c (type_print_varspec_{prefix,suffix}): - When passed_a_ptr is handled, pass 0 for it in the recursive call. +Tue Nov 8 11:12:16 1988 Randall Smith (randy at plantaris.ai.mit.edu) -Fri Dec 18 10:24:14 1987 Richard Stallman (rms at frosted-flakes) + * gdb.texinfo: Added documentation for shell escape. - * findvar.c (read_var_value): Share code between values really - in registers and values in saved registers. - Register short on a big-endian machine needs a VALUE_OFFSET. +Mon Nov 7 12:27:16 1988 Randall Smith (randy at sugar-bombs.ai.mit.edu) - * findvar.c (locate_var_value): Offset the address of a - saved register variable that's shorter than the register. + * command.c: Added commands for shell escape. -Thu Dec 17 08:26:31 1987 Richard Stallman (rms at lucky-charms) + * core.c, dbxread.c: Added ROBOTUSSIN mods. - * valprint.c (type_print_base): Print nameless bit fields - to indicate gaps before bit fields. + * Checkpointed distribution. - * source.c (select_source_symtab): Ignore .h files. - Also, if a function `main' exists, make the default listing line - the beginning of `main'. + * printcmd.c (x_command): Yanked error if there is no memory to + examine (could be looking at executable straight). - * breakpoint.c ({get,set}_breakpoint_commands): - Commands to examine or set the pending breakpoint-commands. + * sparc-pinsn.c (print_insn): Amount to leftshift sethi imm by is + now 10 (matches adb in output). - * infcmd.c (run_stack_dummy): Save and restore the breakpoint - commands around the function call. + * printcmd.c (x_command): Don't attempt to set $_ & $__ if there + is no last_examine_value (can happen if you did an x/0). - * stack.c (return_command): Don't query or print if not interactive. +Fri Nov 4 13:44:49 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * value.h (COERCE_ENUM): New macro: if arg is enum, convert to int. - * value.h (COERCE_ARRAY): Do that, as well as old job. + * printcmd.c (x_command): Error if there is no memory to examine. - * valarith.c (value_binop, value_neg, value_lognot): - Use COERCE_ENUM on the arguments. - * valops.c (value_arg_coerce): Likewise. - * valops.c (value_cast): AVOID coercing enums when arrays are. + * gdb.texinfo: Added "cont" to the command index. - * eval.c (evaluate_subexp): In the BINOP_SUB case, - use evaluate_subexp_with_coercion. + * sparc-dep.c (do_save_insn): Fixed typo in shift amount. - * inflow.c (terminal_ours_1, terminal_inferior): - Ignore inferior_thisrun_terminal since our terminal - is the inferior's controlling terminal regardless. + * m68k-opcode.h: Fixed opcodes for 68881. - * m-sun3.h: Fix assembler syntax for kdb macros. + * 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). - * infcmd.c ({attach,detach}_command): New functions from Dave Taylor. - * inflow.c (attach, detach): New functions from Dave Taylor. - * infrun.c (attach_process): New function, middle-level. - Does all the work of attaching a process, assuming there is no - inferior yet, except for printing and querying. + * 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. - * infrun.c (clear_proceed_status): Clear `stop_after_attach'. - * infrun.c (wait_for_inferior): Handle `stop_after_attach'. +Mon Oct 31 16:23:06 1988 Randall Smith (randy at gluteus.ai.mit.edu) -Sat Dec 12 04:36:39 1987 Richard Stallman (rms at corn-chex) + * gdb.texinfo: Added documentation on the "until" command. - * dbxread.c (end_symtab): The free_code for a symseg got - from a file should be free_linetable. +Sat Oct 29 17:47:10 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * dbxread.c: Allocate blockvector, blocks, symbols and symbol names - from the symbol-obstack, and use free_linetable for all files. - The typevector is still malloc'd, so put it in the free_ptr - to get it freed. + * breakpoint.c, infcmd.c: Added UNTIL_COMMAND and subroutines of + it. - * symmisc.c (free_symtab): Always free the `free_ptr' if nonzero. - `free_explicit' therefore now the same as `free_nothing'. + * 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. - * dbxread.c (define_symbol): Handle defn code 'c', used by - fortran, which defines integer and real constant symbols. +Fri Oct 28 17:45:33 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * symseg.h: Define LOC_CONST_BYTES for constants longer than a - word. New `bytes' alternative for the value of a symbol. + * dbxread.c, symmisc.c: Assorted speedups for readin, including + special casing most common symbols, and doing buffering instead of + calling malloc. - * symtab.h (SYMBOL_VALUE_BYTES): Macro to access `bytes'. +Thu Oct 27 11:11:15 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * findvar.c ({read,locate}_var_value): Handle LOC_CONST_BYTES. - * printcmd.c (address_info): Handle LOC_CONST_BYTES. - * symmisc.c (print_symbol): Handle LOC_CONST_BYTES. + * 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. -Tue Dec 8 20:26:37 1987 Richard Stallman (rms at frosted-flakes) + * 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. - * symtab.c (find_line_pc_range): Detection of last line in file - was erroneous. +Wed Oct 26 10:10:32 1988 Randall Smith (randy at gluteus.ai.mit.edu) -Fri Dec 4 21:52:52 1987 Richard Stallman (rms at frosted-flakes) + * valprint.c (type_print_varspec_suffix): Added check for + TYPE_LENGTH(TYPE_TARGET_TYPE(type)) > 0 to prevent divide by 0. - * dbxread.c (read_range_type): Accept the typenums as argument. - Use read_type_number to read the subrange-of type. - A type defined as a subrange of itself is void. + * printcmd.c (print_formatted): Added check for VALUE_REPEATED; + value_print needs to be called for that. -Thu Dec 3 12:45:10 1987 Richard Stallman (rms at frosted-flakes) + * infrun.c (wait_for_inferior): Added break when you decide to + stop on a null function prologue rather than continue stepping. - * inflow.c ({fetch,store}_inferior_registers): Support UMAX_PTRACE. + * m-sun3.h: Added explanatory comment to REGISTER_RAW_SIZE. - * m-umax.h: New file, for Encore machines. + * expread.y (parse_c_1): Initialized paren_depth for each parse. - * core.c (exec_file_command, etc): Decode COFF files. - * core.c (core_file_command): Support UMAX_CORE format. - * core.c (validate_files, exec_file_command): - Set exec_mtime in exec_file_command so that COFF vs non-COFF - differences appear all in one place. +Tue Oct 25 14:19:38 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * coffread.c: New file from Dave Johnson. + * valprint.c, coffread.c, dbxread.c: Enum constant values in enum + type now accessed through TYPE_FIELD_BITPOS. - * core.c (specify_exec_file_hook): New function to specify - a hook to be called by exec_file_command. Last #ifdef X_WINDOWS gone. - * xgdb.c (initialize): Specify a hook. + * dbxread.c (process_symbol_for_psymtab): Added code to deal with + possible lack of a ":" in a debugging symbol (do nothing). - * infrun.c, inferior.h: Replace stop_r0 and stop_r1 with an array - `stop_registers' that will hold ALL the registers. - * infcmd.c (run_stack_dummy): Get the value from `stop_registers' - and copy all of that into BUFFER. - * infcmd.c (finish_command): Specify `stop_registers' - to `value_being_returned'. - * values.c (value_being_returned): Use the new EXTRACT... macros. - * values.c (set_return_value): Use new STORE_RETURN_VALUE macro. - * valops.c (call_function): Allocate retbuf long enough for all regs. - * m-*.h: New macros EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE and - EXTRACT_STRUCT_VALUE_ADDRESS that express machine-dependencies - in where return values are stored. + * symtab.c (decode_line_1): Added check in case of all numbers for + complete lack of symbols. - * valops.c (call_function): Flush default for CALL_DUMMY_START_OFFSET. - Assume it is defined. - * m-vax.h: Define CALL_DUMMY_START_OFFSET. + * source.c (select_source_symtab): Made sure that this wouldn't + bomb on complete lack of symbols. - * ns32k-pinsn.c (ns32k-localcount): Fix decoding of `enter' insn. - * ns32k-pinsn.c (n32k_get_enter_addr): New fn used from m-umax.h. +Mon Oct 24 12:28:29 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * m-*.h: Change INVALID_FLOAT to accept 2nd arg which is length - of the float. - * values.c (unpack_double): Pass the 2nd arg. - * vax-pinsn.c (print_insn_arg): Pass the 2nd arg. - * infcmd.c (registers_info): Pass the 2nd arg. + * 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. -Wed Nov 25 15:06:55 1987 Richard Stallman (rms at frosted-flakes) + * sparc-dep.c (frame_saved_pc): Put PC_ADJUST return back in for + frame_saved_pc. Seems correct. - * Bug fixes by David Johnson (ddj%cs.brown.edu@relay.cs.net). + * 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). - * symtab.c (list_symbols): Print typedef names, and don't call - them `static'. + * sparc-dep.c (core_file_command): Offset target of o & g register + bcopy by 1 to hit correct registers. - * symmisc.c (print_symtabs): Allow immediate quit, and close the - output file if that happens. + * m-sparc.h: Changed STACK_END_ADDR. - * stack.c (frame_command): Declare args `unsigned' so a negative - number is a frame address, not a level number. +Sun Oct 23 19:41:51 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * source.c: Check for error-return from calls to `getwd'. + * 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. - * printcmd.c (address_info): Fix error in case of a function name. +Fri Oct 21 15:09:19 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) - * inflow.c (create_inferior): Return the inferior pid properly. + * 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. - * inferior.h: Define `inferior_io_terminal'. - * infrun.c (tty_command): New command to specify inferior_io_terminal. - * inflow.c (new_tty): Open specified terminal for the inferior. - * inflow.c (terminal_{ours,inferior}): Do nothing if inferior was - started with its own terminal. - * main.c (main): -t switch calls `tty_command'. + * 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). - * expread.y (rule for `block'): `copy_name' was called in wrong - place and with wrong args. + * 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. - * dbxread.c: Entire file #ifdef READ_DBX_FORMAT. - * m-*.h: Define READ_DBX_FORMAT. + * 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. - * breakpoint.c (initialize): Error in doc string of `info breakpoints'. + * 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. -Wed Nov 11 12:57:28 1987 Richard Stallman (rms at frosted-flakes) + * sparc-dep.c (do_save_insn and do_restore_insn): Added comments. - * ns32k-opcode.h, ns32k-pinsn.c: Two new files. - * m-merlin.h: New file, for one 32000 box. + * 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. -Mon Nov 9 10:31:42 1987 Brian Fox (bfox at sugar-smacks) +Thu Oct 20 13:56:15 1988 & Smith (randy at hobbes.ai.mit.edu) - * eval.c (evaluate_subexp): Made the case of OP_FUNCALL use - evaluate_subexp_with_coercion, so that array references would - get converted into pointer references. + * 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. -Mon Nov 9 05:50:24 1987 Richard Stallman (rms at sugar-smacks) + * 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. - * breakpoint.c (ignore_command): Error if no arg. + * 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 Nov 7 13:57:40 1987 Richard Stallman (rms at frosted-flakes) +Sat Oct 15 16:30:47 1988 & Smith (randy at tartarus.uchicago.edu) - * main.c (quit_command): Get rid of execfile before the kill_inferior. + * 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. - * xgdb.c: New file, interface to X windows. +Fri Oct 14 15:10:43 1988 & Smith (randy at tartarus.uchicago.edu) - * main.c (main): Look for flag arguments before - calling the initialization functions. -nw switch sets - `inhibit_windows' which xgdb.c looks at. - * main.c (command_loop): Call the window hook function, if any. + * 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. - * source.c (get_filename_and_charpos): New function - that interfaces to find_source_lines. - * source.c (source_line_charpos, source_charpos_line): - New functions translate source line number to char pos and vice versa. +Tue Oct 11 11:49:33 1988 & Smith (randy at tartarus.uchicago.edu) - * breakpoint.c (describe_other_breakpoints): New subroutine - to list all breakpoints at PC in a message about "other - breakpoints". - * breakpoint.c (break_command_1): Use describe_other_breakpoints. - * breakpoint.c (set_breakpoint): Like break_command_1 - but takes arg predecoded into symtab and line. + * 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. - * core.c (exec_file_command): Call xgdb_display_exec_file. + * 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). - * valprint.c (type_print_base): For struct bitfields, - print the bit size. +Mon Oct 10 15:32:42 1988 Randy Smith (randy at gargoyle.uchicago.edu) -Thu Aug 20 02:46:47 1987 Richard M. Stallman (rms at prep) + * 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. - * Version 2.4. + * source.c: Added code to allocated space to sals.sals in the case + where no line was specified. - * m68k-pinsn.c (print_insn_arg): Implement place = '3'. + * blockframe.c, infrun.c: Modified to cache stack frames requested + to minimize accesses to subprocess. - * findvar.c (write_register_bytes): Arg to - store_inferior_registers should be -1: write all registers. +Tue Oct 4 15:10:39 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) - * dbxread.c (symbol_file_command): If no arg, - just discard all symbols. + * config.gdb: Added sparc. - * core.c (myread): Flush the 4th arg (filename). - * source.c (find_source_lines): Don't pass 4th arg. - * symmisc.c (read_symsegs): Ditto. +Mon Oct 3 23:01:22 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) - * dbxread.c (process_one_symbol): One call to `define_symbol' - lacked 3rd arg. + * 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 (write_inferior_memory): On failure, return the errno value. - * core.c (write_memory): ditto. - * breakpoint.c ({insert,remove}_breakpoints): ditto. - * utils.c (print_sys_errmsg): Like perror_with_name but don't - signal an error; also, the error code is an arg instead of from - `errno'. - * infrun.c : Save the value from insert_breakpoints and pass it to - print_sys_errmsg. + * inflow.c, gdb.texinfo: `tty' now resets the controling terminal. - * main.c (input_from_terminal_p): Put in omitted `return'. +Fri Sep 30 11:31:16 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * Makefile (expread.o): Use $(CC). + * 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). -Sun Jun 7 04:42:51 1987 Richard M. Stallman (rms at prep) +Thu Sep 29 13:30:46 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) - * version.c: Version 2.3. + * 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). - * inflow.c (terminal_ours): Save fcntl flags correctly. - * inflow.c (term_status_command): - Print the tchars and ltchars structures, byte by byte. + * 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. -Mon May 25 14:37:14 1987 Richard M. Stallman (rms at prep) + ** This was eventually taken out, but I didn't mark it in the + ChangeLog. Oops. - * version.c: Version 2.2. + * 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). - * breakpoint.c (do_breakpoint_commands): - Advance breakpoint_commands before executing the command, - in case command is `cont' and it hits another bpt with commands. + * 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). -Sun May 24 20:45:04 1987 Richard M. Stallman (rms at prep) + * dbxread.c: Killed debuginfo stuff with ifdef's. - * value.h: Declare `contents' long and cast its address to char *. +Wed Sep 28 14:31:51 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) - * expread.y (prefixify_expression): Don't call alloca among the decls. + * 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. - * printcmd.c (print_variable_value): Flush unused local `space'. + * 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. - * main.c (execute_command): Barf on "user" like other class names. + * dbxread.c (process_symbol_for_psymtab): Made sure that the class + of the symbol made it into the partial_symbol entry. -Fri May 22 01:34:37 1987 Richard M. Stallman (rms at prep) +Tue Sep 27 15:10:26 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * m68k-pinsn.c (fetch_arg): New arg position 'j', for movec. - (print_insn_arg): New arg syntax 'J', for movec. - * m68k-opcode.h: movec uses 'Jj'. Everything reformatted. - bf... and cas... insns were corrected. + * dbxread.c: Fixed bug; init_psymbol_list was not being called + with the right number of arguments (1). - * inflow.c (create_inferior): Fork and exec with given args and env. - Call close_exec_file. - (inferior_died): Record the fact that the inferior no longer exists. - Call reopen_exec_file. + * dbxread.c: Put ifdef's around N_MAIN, N_M2C, and N_SCOPE to + allow compilation on a microvax. - * core.c (close_exec_file): New fn: Close the execchan if it's open. - (reopen_exec_file): New fn: Reopen execchan if not currently open. + * config.gdb: Modified so that "config.gdb vax" would work. - * infrun.c (wait_for_inferior): Call inferior_died if it exits. + * 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. - * infcmd.c (run_command): Don't fork and exec; call create_inferior. +Thu Sep 22 11:08:54 1988 Randall Smith (randy at gluteus.ai.mit.edu) - * findvar.c (read_var_value): For reg var in a convertable reg, - fetch reg in its own virtual type and then cast to variable's type. + * dbxread.c (psymtab_to_symtab): Removed call to + init_misc_functions. - * symtab.h: Declare xmalloc to return char *. + * dbxread.c: Fixed enumeration type clash (used enum instead of + integer constant). - * dbxread.c (read_dbx_symtab): Record static text syms as - misc-functions. But if an assembler symbol supplies the address - for a debugger symbol, don't record it as a misc-function. + * breakpoint.c: Fixed typo; lack of \ at end of line in middle of + string constant. - * utils.c (query): Do clearerr (stdin) frequently in case of C-d. + * symseg.h: Fixed typo; lack of semicolon after structure + definition. - * dbxread.c (process_one_symbol, define_symbol): - Pass the stab's DESC down to define_symbol. - DESC = 0 means GCC output: if type is "short", believe it. + * 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. - * dbxread.c (read_enum_type): Don't allocate the type here; - take it as an argument. (Like read_struct_type.) - (read_type)): Before call to read_enum_type, allocate the type - or get the one already allocated. +Wed Sep 21 13:34:19 1988 Randall Smith (randy at plantaris.ai.mit.edu) - * printcmd.c (print_frame_args): Print a comma before - every arg except the first. + * breakpoint.c, infcmd.c, gdb.texinfo: Created "unset" as an alias + for delete, and changed "unset-environment" to be the + "environment" subcommand of "delete". -Wed May 13 00:36:00 1987 Richard M. Stallman (rms at prep) + * 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". - * m68k-pinsn.c (convert_{to,from}_68881): - Hand-assemble the fmoved and fmovex insns. + * 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. - * dbxread.c (define_symbol): For case 'p', a parameter, - if specified type is short or char, change it to int. - This is for how PCC handles arguments. - Define new case 'P' that does what 'p' used to do. - Maybe GCC will use this. + * 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). -Mon May 4 21:52:44 1987 Richard M. Stallman (rms at prep) + * infrun.c (wait_for_inferior): Put in ifdef for Sony News in + check for trap by INNER_THAN macro. - * main.c (main): If SET_STACK_LIMIT_HUGE, set the - run-time stack limit as high as it can go. - * m-sun3.h, m-vax.h: define SET_STACK_LIMIT_HUGE. + * eval.c (evaluate_subexp): Put in catch to keep the user from + attempting to call a non function as a function. -Sun May 3 08:46:23 1987 Richard Mlynarik (mly at prep) +Tue Sep 20 10:35:53 1988 Randall Smith (randy at oatmeal.ai.mit.edu) - * command.c, expread.y, findvar.c, infcmd.c, inflow.c, utils.c, - values.c, defs.h: Various ANSI C compatibility changes - (fouts@wilbur.arpa <8705010117.AA13112@wilbur.arpa>) + * 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. - * core.c, inflow.c: Fix calls to supply_register. - * findvar.c (supply_register): Instead of register value as int, - pass address of buffer in core containing contents in raw form. + * dbxread.c: Killed code to check for extra global symbols in the + debugger symbol table. -Sat Apr 18 17:09:42 1987 Richard Mlynarik (mly at prep) + * 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_loop): - Do any cleanups made by a executing a command each time around. + * 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. - * source.c (directory_command): - make_cleanup (free, dirname), not - make_cleanup (free_current_contents, &dirname) - (rlk <8704180416.AA29572@PARIS.MIT.EDU>) +Fri Sep 16 16:51:19 1988 Randall Smith (randy at gluteus.ai.mit.edu) -Mon Apr 13 20:28:26 1987 Leonard H. Tower Jr. (tower at prep) + * 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). - * gdb.1: fixed typo and italicization errors. - ( id AA16470;Sun,12 Apr 87 14:30:07 EST) + * 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. -Sat Apr 11 15:41:01 1987 Richard Mlynarik (mly at prep) + * 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. - * dbxread.c (read_dbx_symtab): - No name for symbol => "" not 0 (avoid referencing memory 0) - (tower <8704081854.AA00135@buit3.bu.edu>) +Wed Sep 14 12:02:05 1988 Randall Smith (randy at sugar-smacks.ai.mit.edu) -Mon Mar 30 22:24:07 1987 Leonard H. Tower Jr. (tower at prep) + * 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.1: Unix style manual page pointing at internal gdb - documentation, and info sub-system in GNU Emacs. + * gdb.texinfo: Added enable display, disable display, and delete + display to manual. -Fri Mar 20 12:07:15 1987 Richard M. Stallman (rms at prep) +Tue Sep 13 16:53:56 1988 Randall Smith (randy at sugar-smacks.ai.mit.edu) - * COPYING: Clarifications about distribution fees and mixing. - * main.c (copying_info): Same changes. + * 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. -Tue Mar 17 17:40:14 1987 Richard M. Stallman (rms at prep) + * valops.c: Fix to value_ind to check for reference before doing a + COERCE_ARRAY. - * values.c (unpack_field_as_long): Avoid >>= operator - since ISI compiler has a bug. +Sun Jul 31 11:42:36 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) -Sat Mar 7 12:19:35 1987 Richard M. Stallman (rms at prep) + * breakpoint.c (_initialize_breakpoint): Clean up doc for commands + that can now apply also to auto-displays. - * GDB version 2.1. + * coffread.c (record_line): Corrected a spazz in editing. + Also removed the two lines that assume line-numbers appear + only in increasing order. - * values.c (unpack-field-as-long): Tests for endianness were broken. - * findvar.c (read_var_value): - Now we initialize the union as an int and test it as a char. +Tue Jul 26 22:19:06 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) -Sun Mar 1 16:16:20 1987 Richard M. Stallman (rms at prep) + * 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. - * main.c (define_command): Command class symbols - must be cast to int. + * symmisc.c: (print_symtab) check the status of the fopen and call + perror_with_name if needed. -Mon Feb 23 02:47:44 1987 Richard M. Stallman (rms at prep) +Thu Jul 21 00:56:11 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * source.c (list_command): Reword error messages. - New message for case of first arg not just a line-number - and no symtab specified by it. + * Convex: core.c: changes required by Convex's SOFF format were + isolated in convex-dep.c. -Sun Feb 22 21:15:19 1987 Richard M. Stallman (rms at prep) +Wed Jul 20 21:26:10 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * dbxread.c (compare_misc_functions): - Compare the addresses as unsigned numbers. + * 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 -Sun Feb 22 13:11:45 1987 Richard Mlynarik (mly at prep) + * printcmd.c, breakpoint.c: New commands to enable/disable + auto-displays. Also `delete display displaynumber' works like + `undisplay displaynumber'. - * main.c (define_command, document_command): - Stuff was being unnecessarily malloced (-and- not freed!) +Tue Jul 19 02:17:18 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * main.c (execute_command): - User-defined commands don't take args. - Don't confuse empty user command with no command. - Replace bogus `etext' test with a comparison against - class_user. + * coffread.c: (coff_lookup_type) Wrong portion of type_vector was + being bzero'd after type_vector was reallocated. - * main.c (define_command): - If the command of the specified name is built-in, note that when - asking whether to redefine it (this is suppressed for class_alias - -- should it not be?) + * printcmd.c: (delete_display) Check for a display chain before + attempting to delete a display. - * main.c (define_command): - If command was previously built-in, don't preserve its - documentation (otherwise could get error later when trying to free - the non-malloced text of built-in documentation strings) + * core.c, *-dep.c (*-infdep moved to *-dep): machine-dependent + parts of core.c (core_file_command, exec_file_command) moved to + *-dep.c. -Tue Feb 17 16:23:57 1987 Richard Mlynarik (mly at prep) +Mon Jul 18 19:45:51 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * main.c (echo_command): Don't die if not given any arg. - * main.c (cd_command): Echo new cwd if interactive. + * 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. -Thu Feb 12 11:22:56 1987 Richard M. Stallman (rms at prep) +Sun Jul 17 22:27:32 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * stack.c (initialize): "bt" now appears in help aliases. + * 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. - * Version 2.0 released. +Fri Jul 15 01:53:14 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) -Wed Feb 11 17:45:45 1987 Richard M. Stallman (rms at prep) + * 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. - * m68k-opcode.h: Errors corrected in several instructions - and reordering done for assembler's sake. + * coffread.c, infrun.c: minor changes for the i386. May be able + to eliminate them with more general code. - * m-vax.h (POP_FRAME): End with call to set_current_frame. + * 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. -Tue Feb 10 15:06:07 1987 Richard M. Stallman (rms at prep) + * core.c main.c, remote,c, source.c, inflow.c: #ifdef SYSTEMV, + include various header files. Usually types.h and fcntl.h. - * infrun.c (wait_for_inferior): Set stop_print_frame to 1 - after checking breakpoint condition. + * utils.c: added queue routines needed by the i386 (and other sys + 5 machines). - * infcmd.c (run_stack_dummy): Save many flags. + * sys5.c, regex.c, regex.h: new files for sys 5 systems. (The + regex files are simply links to /gp/gnu/lib.) -Thu Feb 5 07:12:20 1987 Richard Mlynarik (mly at prep) +Thu Jul 14 01:47:14 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * source.c (directory_command): - Step over `:' + * 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. -Mon Feb 2 23:40:32 1987 Richard M. Stallman (rms at prep) + * news-infdep.c: new file. - * infcmd.c (set_environment_command): Fix stupid error - for case where no "=" appears in the string. + * m-news.h: new version which deals with new bugs in news800's OS. -Mon Jan 26 13:46:52 1987 Richard M. Stallman (rms at prep) +Tue Jul 12 19:52:16 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * printcmd.c (print_frame_args): Round end-of-arg offset - up rather than down to multiple of int. + * 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. -Fri Jan 23 15:11:50 1987 Richard M. Stallman (rms at prep) + * 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. - * source.c (directory_command): If dir is not added cause already - present, print explanation. +Mon Jul 11 00:48:49 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * infrun.c (proceed): Use read_pc (), not stop_pc, - to get current pc to think about. stop_pc could have been - clobbered by call_function. + * core.c (read_memory): xfer_core_file was being called with an + extra argument (0) by read_memory. -Fri Jan 23 15:00:55 1987 Richard Mlynarik (mly at prep) + * 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. - * source.c (directory_command): - If dir is already in source_path, don't append another copy of it. + * inflow.c, -infdep.c: removed all calls to ptrace from + inflow.c and put them in machine-dependent files *-infdep.c. -Thu Jan 22 00:31:03 1987 Richard M. Stallman (rms at prep) +Sun Jul 10 19:19:36 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * Version 2.0. + * 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. - * blockframe.c (get_pc_function_start): - Understand misc functions. + * 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. - * core.c (core_file_command): - Copy all register contents into the array `registers' - Save a.out header of executable file in core_aouthdr. - Print name of executable file that was running, if we know - where to find it. +Fri Jul 8 19:59:49 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * core.c (exec_file_command): - Save a.out header in exec_aouthdr and file's mtime - in exec_mtime. + * breakpoint.c: (break_command_1) Allow `break if condition' + rather than parsing `if' as a function name and returning an + error. - * core.c (validate_files): Check that core file's a.out hdr - matches exec file's. +Thu Jul 7 22:22:47 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * New handling of registers: - Now all registers are fetched once when the program stops or - when a core file is selected. Their contents are kept in - `registers', an array of bytes. This is done by - `fetch_inferior_registers'. `read_register', etc., just look - there. Writing a register works through - `store_inferior_registers' which writes one or all registers - from `registers' back to the inferior. + * C++: valops.c, valprint.c, value.h, values.c: merged code to deal + with C++ expressions. - A register now can have a "raw" data format and a "virtual" - data format, which may require conversion or even be different sizes. - The conversion can be different for different registers. - For example, the 68000 cpu registers need no conversion - and both raw and virtual size is 4, but the 68881 floating point - registers have raw size 12 (for extended fmt) and virtual size 8 - (for double). Macros in the m- file such as REGISTER_BYTES, - REGISTER_BYTE, REGISTER_{RAW,VIRTUAL}_SIZE, and - REGISTER_CONVERT_TO_{RAW,VIRTUAL} control these things. +Wed Jul 6 03:28:18 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - `read_register' and `write_register' are usable only on registers - which hold an int and need no conversion (raw fmt = virtual fmt). - For other registers, `read_register_bytes' is used, or - `read_relative_register_raw_bytes'. + * 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. - * m-sun3.h: Define the 68881 fp registers. - Know how to recognize insns that save them. - Make dummy frames save them. +Tue Jul 5 02:50:41 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * core.c (read_register, write_registers): Functions deleted. - * findvar.c (read_register, write_registers): New functions, - not the same as the old ones of the same name. + * 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. - * findvar.c (supply_register): Function used by - fetch_inferior_registers, etc., to install the register - values fetched from the inferior. +Fri Jul 1 02:44:20 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) - * findvar.c (read_register_bytes, write_register_bytes): - Read spec'd number of bytes from the byte-array `registers'. + * 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. - * findvar.c (read_relative_register_raw_bytes): - Replaces old function `read_relative_register'; accepts - address of where to store the contents; # bytes stored is size - of the specified register in raw format. +Wed Jun 29 01:26:56 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu) - * findvar.c (value_of_register, read_var_value): - Convert register values and values of register variables - from raw format to virtual format. + * 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. - * findvar.c (locate_var_value): Like `read_var_value' but - returns value for variable's address. +Tue Jun 28 02:56:42 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu) - * value.h: Add new field VALUE_REGNO to each value. It holds - register number to control virtual-to-raw conversion - for assignments to the value. - - * valops.c (value_assign): Convert data from virtual to raw format - if value came from a register variable. - Use read_register_bytes and write_register_bytes. - - - * infcmd.c (continue_command): Subtract 1 from arg - before setting breakpoint's ignore-count. - - * infcmd.c (jump_command): Query if spec'd line is outside - of the current function. - - * infcmd.c (finish_command): Now finish the selected frame, - and no arg required. - - * infcmd.c (set_environment_command): Allow space to separate - varname and value. - - * infcmd.c (registers_info): Print both raw and virtual data - format if they differ. Allow register name as arg. - Ask for a Newline each 16 registers. - - * inflow.c (kill_inferior): call mark_breakpoints_out. - * inflow.c ({fetch,store}_inferior_registers for Sun): - Get the fp registers and store them in right places in - `registers'. - * inflow.c ({read,write}_inferior_register): Deleted. - - * infrun.c (wait_for_inferior): Single-stepping is not considered - to have hit a breakpoint unless the pc before the step matches the - address of the breakpoint. Necessary on machines where - breakpoints leave the pc incremented. - - If shell gets SIGSEGV, pass the signal silently to it. - - * m68k-pinsn.c, m68k-opcode.h: - Add the 68881 instructions. New operand codes `F', `I', `s' - and `k' are needed for them. New place codes `78tcik'. - NEXTBYTE now skips a word but fetches just a byte. - Explicit sign-extension removed from NEXTBYTE and NEXTWORD. - NEXTSINGLE, NEXTDOUBLE, NEXTEXTEND and NEXTPACKED defined. - Various changes to implement the new operand and place codes. - print_index changed because displacement-size codes for - word and long displacement were interchanged. - - * m68k-pinsn.c (convert_{from,to}_68881): Functions added - to support REGISTER_CONVERT_TO_{RAW,VIRTUAL} on 68000. - - * main.c (main): Move around calls to setjmp. - * main.c (define_command, document_command): - Accept a from_tty argument instead of calling input_from_terminal_p. - - * printcmd.c (address_info): Print info on class and address - of a specified symbol. For register symbols, gives name of register. - - * printcmd.c (print_command): Remember explicitly whether - `make_cleanup' was called. - - * printcmd.c (print_frame_args): Know how arg-addresses vary with - data type on big-endian machines. - - * source.c (directory_command): Detect `:' in arg and reject it. - Free the old directory-path. Simplify things like `/.' in - dirname. - - * source.c (openp): Simplify `./' in specified name. - - * source.c (find_source_lines): Compare source mtime against - `exec_mtime' and warn if source is newer. - - * source.c (line_info): No arg means use last line listed - or line following last one this command was used on. - If from tty, clear out argument so Return is like `i li' without - arg. - - * stack.c (frame_info): Print addresses registers are saved at. - - * stack.c (return_command): When asking for confirmation, give - name of function that will be made to return. - - * valops.c (call_function): If function type is - pointer-to-function, dereference it to compute return type. - If pointer-to-object, assume function returns int. - If char, assume that the value's address is the function address - (because it's a misc functon). If int, the value itself is the - function address. - - * dbxread.c (compare_symbols): Sort register symbols - before all others. - - * eval.c (evaluate_subexp_for_address): New function like - `evaluate_subexp' but returns a value for the address where - the subexpression's value would be located. - - * eval.c (evaluate_subexp_for_sizeof): New function like - `evaluate_subexp' but returns a value for the size of the subexp. - - * eval.c (evaluate_subexp_with_coercion): Like `evaluate_subexp' - but coerces arrays to pointers (without taking the time to - read the array contents). - - * eval.c (evaluate_subexp): Use the three new functions above - when appropriate instead of calling self recursively. - -Wed Jan 14 17:00:03 1987 Richard Mlynarik (mly at prep) - - * core.c (core_file_command): - Use correct file in calls to perror_with_name - -Mon Jan 12 03:34:35 1987 Richard Mlynarik (mly at prep) - - * breakpoint.c (map_breakpoint_numbers): - Err if no args not supplied, otherwise would get mpv. - - * main.c (main): - Command-line arg "-d dir" adds dir to source-file directory - search-list. - -Sun Jan 11 19:19:52 1987 Richard Mlynarik (mly at prep) - - * symmisc.c (free_all_symtabs): - Don't call free on 0. - - * core.c (exec_file_command): - Use correct name in call to perror_with_name. - Record absolute pathname. - Don't savestring an arg to concat. - - * dbxread.c (symbol_file_command): - Record absolute name of pathname opened. - Print a message if file doesn't have a symbol-table. - Don't savestring an arg to concat. - - * source.c (openp): - Add new arg filename_opened, which if non-zero will be set to a - malloced string of the absolute name of the actual filename opened. - - * breakpoint.c (clear_command): - If from_tty or cleared more than one breakpoint at location, - print which bpts were deleted. - - * breakpoint.c (break_command_1, break_command, tbreak_command): - If from_tty, mention any other breakpoints set at same location. - - * symtab.c (decode_line_1): - If no symtabs, err mentioning `symbol-file' command rather than - saying "function foo not defined" - -Fri Jan 9 01:25:19 1987 Richard Mlynarik (mly at prep) - - * main.c (set_prompt_command): - Add support command "set-prompt" - - * printcmd.c (undisplay_command): - Fix paren error to make "undisplay " work. - -Wed Jan 7 12:06:09 1987 Richard Mlynarik (mly at prep) - - * main.c (print_gdb_version, gdb_version_info): - Add command "info version" to report the version - of gdb for use in bug reports. - - * infcmd.c: - Ensure inferior_args always points to string starting with a space - and is never 0. - - * printcmd.c: (clear_displays, undisplay_command): - Fix bug in clear_displays which led to looping. - Make undisplay_command call it instead of wrong-looking code which - looked at (display->number == 0) instead of (display == 0) to - determine if it were at the end of the chain. - -Mon Dec 15 20:57:06 1986 Richard M. Stallman (rms at prep) - - * utils.c (query): Don't ignore a second line if given a null line. - - * infrun.c (normal_stop): Print "bug in shell" message - only for a segmentation fault. - - * main.c (main): Read init file from home directory if any, - before init file from current directory. - -Thu Dec 4 09:05:35 1986 Richard M. Stallman (rms at prep) - - * source.c (select_source_symtab): Don't ref thru arg if null. - - * m68k.opcode.h: For trap instruction code, use type T. - * m68k-pinsn.c (print_insn_arg): Recognize new arg-code T - and print the trap vector properly. - - * m-sun[23].h (FRAME_FIND_SAVED_REGS): Recognize a movl REG,-(sp) - as a way to save one register. Recognize clrw -(sp); movw -(sp) - after saving regs as a way to save the PS register. Adjust the - way to find the starting pc of a stack dummy frame for the fact - that these frames now save the PS. - - * m-sun[23].h (POP_FRAME): Restore PS register if frame saved it. - - * m-sun[23].h (PUSH_DUMMY_FRAME): Push the old PS register. - - * m-sun[23].h (CALL_DUMMY, etc.): Fix erroneous binary code for - the addl #nnn,sp instruction. Insert clrw -(sp); movw -(sp) - to indicate that the PS has been saved. - - * infrun.c (wait_for_inferior): If inferior exits, call - mark_breakpoints_out so it works to delete breakpoints afterward. - - * infrun.c (normal_stop): After popping a stack dummy frame, - select the frame that we get to. - - * dbxread.c (process_one_symbol): Store new `depth' field - in all context_stack elements created. For N_RBRAC, test - that depth matches that in the context_stack; if not, error. - - * dbxread.c (all callers of error): Make all error messages - start "Invalid symbol data: " and end with value of symnum. - Also change a few aborts to errors. - -Mon Dec 1 20:20:37 1986 Richard M. Stallman (rms at prep) - - * version.c: Version 1.11. - - * breakpoint.c (condition_command): If no condition spec'd, - print "breakpoint N now unconditional". - - * breakpoint.c (commands_command): Give different error messages - for cases of args not containing a breakpoint number - and args containing anything after the breakpoint number. - - * commands.c (lookup_command): Don't store a zero in *p - if have an undefined subcommand that is not an error. - - * commands.c (lookup_command): For recursive call, - pass subcommand list properly. Was passing the address - of the word containing the list. - - * core.c ({core,exec}_file_name): If no arg, tell user - what the effect is. - - * dbxread.c (define_symbol): Accept class code 'v' - for static variable within a function. - - * dbxread.c (read_type): Now allow any plain number or - pair of numbers in parens, with no code letter. This means - define new type same as type with specified number, or define - it as void if specified number's type is not yet mentioned. - - * m68k-pinsn.c (print_insn_arg): Case of general operand - in byte insn that happened to be immediate used wrong arg-size. - - * printcmd.c (set_next_address): Set next_address from arg - and also set value of `$_' from it. - - * printcmd.c (do_examine): Save address in last_examine_address - and value fetched to examine in last_examine_value. - - * printcmd.c (x_command): Copy last_examine_{address,value} - into values of `$_' and `$__'. Change `x' documentation string. - - * source.c (directory_command): Query when no args now says - what new value it wants use for the path. - - * source.c (list_command): Don't die in cases like `list ,+30'. - - * source.c (line_info): Call `set_next_address' to make `x' - display the text of the line. Change `info list' doc string. - -Sat Nov 29 07:59:29 1986 Richard M. Stallman (rms at prep) - - * printcmd.c (undisplay_command): If get no arg, - rather than crashing, query and then delete undisplay everything. - -Fri Nov 28 15:43:52 1986 Richard M. Stallman (rms at prep) - - * dbxread.c (process_one_symbol): If N_LBRAC sym - has a greater value that N_RBRAC, ignore the - N_LBRAC value and give the block zero length. - -Tue Nov 25 03:10:12 1986 Richard M. Stallman (rms at prep) - - * dbxread.c (process_one_symbol): Ignore N_NSYMS symbols - that appear in Ultrix. - -Sat Nov 22 22:49:06 1986 Richard M. Stallman (rms at prep) - - * version.c: version 1.10. - - * valprint.c (type_print*): - SHOW < 0 now means abbreviate struct/union members - or enum values with `...'. SHOW now decremented on - each recursion in type_print_base. Several places - that used to check !show now check show <= 0. - - * valprint.c (val_print): Pass -1 for SHOW to type_print - when printing typename inside parens or braces. - - * printcmd.c (print_command): If no value specified to print, - print the value of $. - - * expression.h, expread.y, eval.c, expprint.c: - OP_MEMVAL renamed UNOP_MEMVAL - and now allows any expression, not just an integer address. - It now has same format as UNOP_CAST and works almost like it. - Each place that referred to it has been rewritten - starting with a copy of the code that handles UNOP_CAST. - Doc for `print' command changed for this. - - * source.c (init_source_path): - Free and zero out any line_charpos's saved in source symtabs. - - * breakpoint.c (condition_command): - Parse the condition in the environment of the code where the - breakpoint is set. This requires finding the breakpoint - before parsing, so code is rearranged. - - * dbxread.c (dbx_alloc_type): - New function given typenums returns the type for those typenums - or allocates a new, empty type for those typenums and returns it. - - * symtab.c (smash_type_to_{pointer,function}): - New functions modify an already-allocated type object - to be a pointer to or function returning some given type. - - * dbxread.c (read_type): Uses dbx_alloc_type in many cases. - Reading a pointer or function type now works by doing that, - then reading the value type or type pointed to, then smashing - it into the type already allocated. This makes some fwd refs win. - Likewise for structs and unions. - - * dbxread.c (read_struct_type): Now receives the type object - as args. Used to get typenums as args and look up the type - itself. - - * dbxread.c (symbol_file_command): - At very end, clear out any type name that `char *' has received. - -Thu Nov 20 16:43:53 1986 Richard M. Stallman (rms at prep) - - * m-sun2.h, m-sun3.h (FIND_FRAME_SAVED_REGS): - Was incrementing address even for regs not saved. - -Sun Nov 16 14:59:07 1986 Richard M. Stallman (rms at prep) - - * values.c (value_field): Was adding in byte offset - before calling unpack_field_as_long, which itself - adds in the offset. Now pass addr of start of structure. - - * infrun.c (normal_stop): Clean up inferior_pid conditionals: - just return early if no inferior. - -Thu Nov 13 15:45:50 1986 Richard M. Stallman (rms at prep) - - * dbxread.c (struct header_file): add new field .instance - to distinguish the various entries for one header file. - - * dbxread.c (process_one_symbol): Use the `value' of - a N_BINCL or N_EXCL as the instance code for the header file. - - * dbxread.c (add_{new,old}_header_file): - Accept an instance code as arg and treat it as if it were - part of the file name for distinguishing and finding entries. - - * dbxread.c (add_new_header_file, read_type): - Turn off the header_file_prev_index feature with #if 0. - - * values.c (unpack_field_as_long, modify_field): - Run-time test to distinguish big and little endian machines - and do shifting accordingly. - -Tue Nov 11 00:31:18 1986 Richard M. Stallman (rms at prep) - - * version.c: version 1.9. - - * breakpoint.c (delete_command): - Don't query if 2nd arg is zero. - - * breakpoint.c (clear_breakpoints): - Pass 2nd arg of zero to delete_command. - -Sat Nov 8 23:29:19 1986 Richard M. Stallman (rms at prep) - - * breakpoint.c (delete_command): - Ask for confirmation when used with no arg (delete all). - -Fri Nov 7 11:23:09 1986 Richard M. Stallman (rms at prep) - - * infrun.c (start_inferior, wait_for_inferior): - Eliminate `stop_in_shell' which was not being maintained right. - New variable `running_in_shell' is set to 1 or 0 when the - expected SIGTRAPs happen, and is simply examined at other times. - - * infrun.c (wait_for_inferior): - If get SIGSEGV with running_in_shell == 1, it is sh - allocating memory. Pass the signal silently to the shell. - - * core.c (exec_file_command): - data_{start,end} are adjusted unconditionally when an - exec file is opened, so closing counter-adjustment is - now unconditional as well. - - * printcmd.c (x_command): - Don't erase the expression from the calling args - if cllaed noninteractively (used to be clobbering - definitions of user-defined commands). - - * source.c (list_command): likewise. - -Wed Nov 5 09:41:00 1986 Richard M. Stallman (rms at prep) - - * Makefile: New variable OBSTACK1 that people can use - to make obstack.o a dependency of gdb. - - * breakpoint.c (initialize): - Define new aliases "br", "bre" and "brea" for "break". - -Sun Nov 2 21:16:06 1986 Richard Mlynarik (mly at prep) - - * symmisc.c (read_symsegs): - Add an extra protection against invalid symbol-file - - * m-vax.h: - Set KERNEL_U_ADDR and STACK_END_ADDR non-4.2-specifically - -Tue Oct 21 13:34:14 1986 Richard Mlynarik (mly at prep) - - * breakpoints.c (initialize): - Delet reference to non-existent command "tenable" from doc of "enable" - -Tue Oct 14 19:58:27 1986 Richard Mlynarik (mly at prep) - - * printcmd.c (display_command, undisplay_command): - * infcmd.c (run_command): - Call dont_repeat. + * C++: Makefile: changed the echo: expect 101 shift/reduce conflicts + and 1 reduce/reduce conflict. Local Variables: diff --git a/gdb/Makefile b/gdb/Makefile index 563de46..b47091c 100644 --- a/gdb/Makefile +++ b/gdb/Makefile @@ -1,109 +1,240 @@ -# Makefile for GDB -# Copyright (C) 1986, 1988 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! - - -# On HPUX, you need to add -Ihpux to CFLAGS. -# The headers in the subdir hpux override system headers +# On HPUX, you need to add -Ihp-include to CFLAGS. +# The headers in the directory hp-include override system headers # and tell GDB to use BSD executable file format. -# You also need to add -lGNU to CLIBS, and perhaps CC = gcc. - -# -I. for "#include " -CFLAGS = -g -I. -# NOTE!!! -O may FAIL TO WORK! See initialize.h for some weird hacks. +# You must also define REGEX & REGEX1 below and ALLOCA & ALLOCA1 (get +# alloca.c from the emacs distribution) to the CLIBS. +# If you compile GDB with GCC on HPUX, you must make sure that the "nm" used +# in "munch" is GNU's nm. This is because gcc uses a different .o +# file format than the native HPUX compiler. + +# On USG (System V) machines, you must make sure to setup REGEX & +# REGEX1 to point at regex.o and use the USG version of CLIBS. +# If your system has a broken alloca() -- most do -- then get +# alloca.c from the GNU Emacs distribution and set ALLOCA & ALLOCA1. +# Also, 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. + +# On Sunos 4.0 machines, make sure to compile *without* shared +# libraries if you want to run gdb on itself. Make sure to compile +# any program on which you want to run gdb without shared libraries. + +# 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 will be +# incorrectly compiled. The "fixincludes" script in the gcc +# distribution will probably fix your include files up. + +CC=cc +SHELL=/bin/sh + +# Set this up with gcc if you have gnu ld and the loader will print out +# line numbers for undefinded refs. +CC-LD=${CC} + +# -I. for "#include ". Possibly regex.h also. +#CFLAGS = -g -pg -I. -O +CFLAGS = -I. -g +#LDFLAGS = -pg -g +LDFLAGS = -g # 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. +# so that the dependencies work right. Similarly with REGEX and "regex.o". +# You must define REGEX and REGEX1 on USG machines. +# If your system is missing alloca(), or, more likely, it's there but it +# doesn't work, define ALLOCA and ALLOCA1. OBSTACK = obstack.o OBSTACK1 = obstack.o +REGEX = regex.o +REGEX1 = regex.o +ALLOCA = alloca.o +ALLOCA1 = alloca.o +ADD_FILES = $(OBSTACK) $(REGEX) $(ALLOCA) $(GNU_MALLOC) +ADD_DEPS = $(OBSTACK1) $(REGEX1) $(ALLOCA1) $(GNU_MALLOC) + +# +# 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 = +#MALLOC_FLAGS = ${CFLAGS} -Drcheck -Dbotch=fatal -DMSTATS + +# for BSD +CLIBS = $(ADD_FILES) +# for USG +#CLIBS= $(ADD_FILES) -lPW + +SFILES = blockframe.c breakpoint.c coffread.c command.c core.c dbxread.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 = convex-dep.c umax-dep.c gould-dep.c default-dep.c sun3-dep.c \ + sparc-dep.c hp9k320-dep.c news-dep.c i386-dep.c + +PINSNS = gld-pinsn.c i386-pinsn.c sparc-pinsn.c vax-pinsn.c m68k-pinsn.c \ + ns32k-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 + +MFILES = m-hp9k320.h m-i386.h m-i386gas.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-sun2os4.h \ + m-sun3os4.h m-sun4os4.h m-umax.h m-vax.h + +POSSLIBS = obstack.h obstack.c regex.c regex.h malloc.c + +TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c -CLIBS = $(OBSTACK) +OTHERS = Makefile createtags munch config.gdb ChangeLog README TAGS \ + gdb.texinfo .gdbinit COPYING expread.tab.c stab.def hp-include -STARTOBS = main.o firstfile.o +TAGFILES = ${SFILES} ${DEPFILES} ${PINSNS} ${HFILES} ${OPCODES} ${MFILES} \ + ${POSSLIBS} +TARFILES = ${TAGFILES} ${OTHERS} -OBS = blockframe.o breakpoint.o findvar.o stack.o source.o \ +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 + 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 -TSOBS = core.o inflow.o +TSOBS = core.o inflow.o dep.o NTSOBS = standalone.o -ENDOBS = lastfile.o command.o utils.o expread.o expprint.o pinsn.o \ - environ.o version.o - TSSTART = /lib/crt0.o NTSSTART = kdb-start.o -gdb+ : $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) $(OBSTACK1) - $(CC) $(LDFLAGS) -o gdb+ $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) $(CLIBS) +gdb : $(OBS) $(TSOBS) $(ADD_DEPS) + -rm -f init.c + ./munch $(OBS) $(TSOBS) > init.c + ${CC-LD} $(LDFLAGS) -o gdb init.c $(OBS) $(TSOBS) $(CLIBS) + +xgdb : $(OBS) $(TSOBS) xgdb.o $(ADD_DEPS) + -rm -f init.c + ./munch $(OBS) $(TSOBS) xgdb.o > init.c + $(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \ + -lXaw -lXt -lX11 $(CLIBS) + +kdb : $(NTSSTART) $(OBS) $(NTSOBS) $(ADD_DEPS) + -rm -f init.c + ./munch $(OBS) $(NTSOBS) > init.c + $(CC-LD) $(LDFLAGS) -c init.c $(CLIBS) + ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o -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 + tar chf gdb.tar dist-gdb + rm -rf dist-gdb -xgdb+ : $(STARTOBS) $(OBS) $(TSOBS) xgdb.o $(ENDOBS) $(OBSTACK1) - $(CC) $(LDFLAGS) -o xgdb+ $(STARTOBS) $(OBS) $(TSOBS) xgdb.o $(ENDOBS) \ - -lXaw -lXt -lX11 $(CLIBS) +gdb.tar.Z: gdb.tar + compress gdb.tar -kdb : $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) $(OBSTACK1) - ld -o kdb $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) -lc $(CLIBS) +clean: + -rm -f ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX} + -rm -f init.c init.o + -rm -f gdb + +realclean: clean + -rm -f expread.tab.c tags TAGS + +xgdb.o : xgdb.c defs.h param.h symtab.h frame.h + $(CC) -c $(CFLAGS) xgdb.c -o $@ -blockframe.o : blockframe.c defs.h initialize.h param.h symtab.h frame.h -breakpoint.o : breakpoint.c defs.h initialize.h param.h symtab.h frame.h -command.o : command.c command.h -coffread.o : coffread.c defs.h initialize.h param.h symtab.h -core.o : core.c defs.h initialize.h param.h -dbxread.o : dbxread.c defs.h initialize.h param.h symtab.h -environ.o : environ.c environ.h -expprint.o : expprint.c defs.h symtab.h expression.h expread.tab.c : expread.y - @echo 'Expect 96 shift/reduce conflicts.' + @echo 'Expect 101 shift/reduce conflicts and 1 reduce/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 -eval.o : eval.c defs.h initialize.h symtab.h value.h expression.h -findvar.o : findvar.c defs.h initialize.h param.h symtab.h frame.h value.h -firstfile.o : firstfile.c initialize.h -infcmd.o : infcmd.c defs.h initialize.h param.h symtab.h frame.h inferior.h environ.h value.h -inflow.o : inflow.c defs.h initialize.h param.h frame.h inferior.h -infrun.o : infrun.c defs.h initialize.h param.h symtab.h frame.h inferior.h wait.h -kdb-start.o : kdb-start.c defs.h param.h -lastfile.o : lastfile.c -main.o : main.c defs.h command.h + +# +# Only useful if you are using the gnu malloc routines. +# +malloc.o : malloc.c + ${CC} -c ${MALLOC_FLAGS} malloc.c + +# +# dep.o depends on ALL the dep files since we don't know which one +# is really being used. +# +dep.o : ${DEPFILES} defs.h param.h frame.h inferior.h obstack.h \ + a.out.encap.h + # pinsn.o depends on ALL the opcode printers # since we don't know which one is really being used. -pinsn.o : pinsn.c defs.h param.h symtab.h \ - vax-opcode.h vax-pinsn.c m68k-opcode.h m68k-pinsn.c sparc-opcode.h sparc-pinsn.c -printcmd.o : printcmd.c defs.h initialize.h param.h symtab.h value.h expression.h -remote.o : remote.c defs.h initialize.h param.h frame.h inferior.h -source.o : source.c defs.h initialize.h symtab.h -stack.o : stack.c defs.h initialize.h param.h symtab.h frame.h -standalone.o : standalone.c defs.h initialize.h param.h symtab.h frame.h inferior.h wait.h -symmisc.o : symmisc.c defs.h initialize.h symtab.h -symtab.o : symtab.c defs.h initialize.h param.h symtab.h -utils.o : utils.c defs.h -valarith.o : valarith.c defs.h initialize.h param.h symtab.h value.h expression.h -valops.o : valops.c defs.h initialize.h param.h symtab.h value.h -valprint.o : valprint.c defs.h initialize.h param.h symtab.h value.h -values.o : values.c defs.h initialize.h param.h symtab.h value.h -version.o : version.c -xgdb.o : xgdb.c defs.h initialize.h param.h symtab.h frame.h - $(CC) -c $(CFLAGS) xgdb.c -o $@ +pinsn.o : ${PINSNS} defs.h param.h symtab.h obstack.h symseg.h frame.h \ + ${OPCODES} -obstack.o : obstack.c +# +# 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. +# +blockframe.o : defs.h param.h symtab.h obstack.h symseg.h frame.h +breakpoint.o : defs.h param.h symtab.h obstack.h symseg.h frame.h +coffread.o : defs.h param.h +command.o : command.h defs.h +core.o : defs.h param.h a.out.encap.h +dbxread.o : param.h 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 symtab.h obstack.h symseg.h value.h expression.h +expprint.o : defs.h symtab.h obstack.h symseg.h param.h expression.h +findvar.o : defs.h param.h symtab.h obstack.h symseg.h frame.h value.h +infcmd.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \ + environ.h value.h +inflow.o : defs.h param.h frame.h inferior.h +infrun.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \ + wait.h +kdb-start.o : defs.h param.h +main.o : defs.h command.h param.h +malloc.o : getpagesize.h +obstack.o : obstack.h +printcmd.o : defs.h param.h frame.h symtab.h obstack.h symseg.h value.h \ + expression.h +regex.o : regex.h +remote.o : defs.h param.h frame.h inferior.h wait.h +source.o : defs.h symtab.h obstack.h symseg.h param.h +stack.o : defs.h param.h symtab.h obstack.h symseg.h frame.h +standalone.o : defs.h param.h 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 obstack.h +utils.o : defs.h param.h +valarith.o : defs.h param.h symtab.h obstack.h symseg.h value.h expression.h +valops.o : defs.h param.h symtab.h obstack.h symseg.h value.h frame.h \ + inferior.h +valprint.o : defs.h param.h symtab.h obstack.h symseg.h value.h +values.o : defs.h param.h 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/gdb/RCS/Makefile,v b/gdb/RCS/Makefile,v new file mode 100644 index 0000000..fd71c1c --- /dev/null +++ b/gdb/RCS/Makefile,v @@ -0,0 +1,367 @@ +head 1.4; +access ; +symbols ; +locks ; strict; +comment @# @; + + +1.4 +date 89.03.27.21.28.33; author gnu; state Exp; +branches ; +next 1.3; + +1.3 +date 89.03.27.18.33.31; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.03.13.19.02.58; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.09.03.15.53; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.4 +log +@More general support for ALLOCA and other local library routines; +other minor cleanup. +@ +text +@# On HPUX, you need to add -Ihp-include to CFLAGS. +# The headers in the directory hp-include override system headers +# and tell GDB to use BSD executable file format. +# You must also define REGEX & REGEX1 below and ALLOCA & ALLOCA1 (get +# alloca.c from the emacs distribution) to the CLIBS. +# If you compile GDB with GCC on HPUX, you must make sure that the "nm" used +# in "munch" is GNU's nm. This is because gcc uses a different .o +# file format than the native HPUX compiler. + +# On USG (System V) machines, you must make sure to setup REGEX & +# REGEX1 to point at regex.o and use the USG version of CLIBS. +# If your system has a broken alloca() -- most do -- then get +# alloca.c from the GNU Emacs distribution and set ALLOCA & ALLOCA1. +# Also, 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. + +# On Sunos 4.0 machines, make sure to compile *without* shared +# libraries if you want to run gdb on itself. Make sure to compile +# any program on which you want to run gdb without shared libraries. + +# 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 will be +# incorrectly compiled. The "fixincludes" script in the gcc +# distribution will probably fix your include files up. + +CC=cc +SHELL=/bin/sh + +# Set this up with gcc if you have gnu ld and the loader will print out +# line numbers for undefinded refs. +CC-LD=${CC} + +# -I. for "#include ". Possibly regex.h also. +#CFLAGS = -g -pg -I. -O +CFLAGS = -I. -g +#LDFLAGS = -pg -g +LDFLAGS = -g + +# 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 system is missing alloca(), or, more likely, it's there but it +# doesn't work, define ALLOCA and ALLOCA1. +OBSTACK = obstack.o +OBSTACK1 = obstack.o +REGEX = regex.o +REGEX1 = regex.o +ALLOCA = alloca.o +ALLOCA1 = alloca.o +ADD_FILES = $(OBSTACK) $(REGEX) $(ALLOCA) $(GNU_MALLOC) +ADD_DEPS = $(OBSTACK1) $(REGEX1) $(ALLOCA1) $(GNU_MALLOC) + +# +# 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 = +#MALLOC_FLAGS = ${CFLAGS} -Drcheck -Dbotch=fatal -DMSTATS + +# for BSD +CLIBS = $(ADD_FILES) +# for USG +#CLIBS= $(ADD_FILES) -lPW + +SFILES = blockframe.c breakpoint.c coffread.c command.c core.c dbxread.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 = convex-dep.c umax-dep.c gould-dep.c default-dep.c sun3-dep.c \ + sparc-dep.c hp9k320-dep.c news-dep.c i386-dep.c + +PINSNS = gld-pinsn.c i386-pinsn.c sparc-pinsn.c vax-pinsn.c m68k-pinsn.c \ + ns32k-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 + +MFILES = m-hp9k320.h m-i386.h m-i386gas.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-sun2os4.h \ + m-sun3os4.h m-sun4os4.h m-umax.h m-vax.h + +POSSLIBS = obstack.h obstack.c regex.c regex.h malloc.c + +TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c + +OTHERS = Makefile createtags munch config.gdb ChangeLog README TAGS \ + gdb.texinfo .gdbinit COPYING expread.tab.c stab.def hp-include + +TAGFILES = ${SFILES} ${DEPFILES} ${PINSNS} ${HFILES} ${OPCODES} ${MFILES} \ + ${POSSLIBS} +TARFILES = ${TAGFILES} ${OTHERS} + +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 + +TSOBS = core.o inflow.o dep.o + +NTSOBS = standalone.o + +TSSTART = /lib/crt0.o + +NTSSTART = kdb-start.o + +gdb : $(OBS) $(TSOBS) $(ADD_DEPS) + -rm -f init.c + ./munch $(OBS) $(TSOBS) > init.c + ${CC-LD} $(LDFLAGS) -o gdb init.c $(OBS) $(TSOBS) $(CLIBS) + +xgdb : $(OBS) $(TSOBS) xgdb.o $(ADD_DEPS) + -rm -f init.c + ./munch $(OBS) $(TSOBS) xgdb.o > init.c + $(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \ + -lXaw -lXt -lX11 $(CLIBS) + +kdb : $(NTSSTART) $(OBS) $(NTSOBS) $(ADD_DEPS) + -rm -f init.c + ./munch $(OBS) $(NTSOBS) > init.c + $(CC-LD) $(LDFLAGS) -c init.c $(CLIBS) + ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o -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 + tar chf gdb.tar dist-gdb + rm -rf dist-gdb + +gdb.tar.Z: gdb.tar + compress gdb.tar + +clean: + -rm -f ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX} + -rm -f init.c init.o + -rm -f gdb + +realclean: clean + -rm -f expread.tab.c tags TAGS + +xgdb.o : xgdb.c defs.h param.h symtab.h frame.h + $(CC) -c $(CFLAGS) xgdb.c -o $@@ + +expread.tab.c : expread.y + @@echo 'Expect 101 shift/reduce conflicts and 1 reduce/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 + +# +# Only useful if you are using the gnu malloc routines. +# +malloc.o : malloc.c + ${CC} -c ${MALLOC_FLAGS} malloc.c + +# +# dep.o depends on ALL the dep files since we don't know which one +# is really being used. +# +dep.o : ${DEPFILES} defs.h param.h frame.h inferior.h obstack.h \ + a.out.encap.h + +# pinsn.o depends on ALL the opcode printers +# since we don't know which one is really being used. +pinsn.o : ${PINSNS} defs.h param.h symtab.h obstack.h symseg.h frame.h \ + ${OPCODES} + +# +# 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. +# +blockframe.o : defs.h param.h symtab.h obstack.h symseg.h frame.h +breakpoint.o : defs.h param.h symtab.h obstack.h symseg.h frame.h +coffread.o : defs.h param.h +command.o : command.h defs.h +core.o : defs.h param.h a.out.encap.h +dbxread.o : param.h 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 symtab.h obstack.h symseg.h value.h expression.h +expprint.o : defs.h symtab.h obstack.h symseg.h param.h expression.h +findvar.o : defs.h param.h symtab.h obstack.h symseg.h frame.h value.h +infcmd.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \ + environ.h value.h +inflow.o : defs.h param.h frame.h inferior.h +infrun.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \ + wait.h +kdb-start.o : defs.h param.h +main.o : defs.h command.h param.h +malloc.o : getpagesize.h +obstack.o : obstack.h +printcmd.o : defs.h param.h frame.h symtab.h obstack.h symseg.h value.h \ + expression.h +regex.o : regex.h +remote.o : defs.h param.h frame.h inferior.h wait.h +source.o : defs.h symtab.h obstack.h symseg.h param.h +stack.o : defs.h param.h symtab.h obstack.h symseg.h frame.h +standalone.o : defs.h param.h 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 obstack.h +utils.o : defs.h param.h +valarith.o : defs.h param.h symtab.h obstack.h symseg.h value.h expression.h +valops.o : defs.h param.h symtab.h obstack.h symseg.h value.h frame.h \ + inferior.h +valprint.o : defs.h param.h symtab.h obstack.h symseg.h value.h +values.o : defs.h param.h 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 +@ + + +1.3 +log +@A/UX changes. Use cc, use local regex.o, use local alloca.o +@ +text +@d4 2 +a5 2 +# You must also define REGEX & REGEX1 below and add alloca.o (from +# the emacs distribution) to the CLIBS. +d12 2 +d26 2 +a27 1 +# incorrectly compiled. +d46 2 +d52 4 +d70 1 +a70 1 +#CLIBS = $(OBSTACK) $(REGEX) $(GNU_MALLOC) +d72 1 +a72 1 +CLIBS= $(OBSTACK) $(REGEX) $(GNU_MALLOC) alloca.o +d122 1 +a122 1 +gdb : $(OBS) $(TSOBS) $(OBSTACK1) $(REGEX1) ${GNU_MALLOC} +d127 1 +a127 1 +xgdb : $(OBS) $(TSOBS) xgdb.o $(OBSTACK1) $(REGEX1) ${GNU_MALLOC} +d133 1 +a133 1 +kdb : $(NTSSTART) $(OBS) $(NTSOBS) $(OBSTACK1) $(REGEX1) ${GNU_MALLOC} +d161 1 +a161 1 + -rm -f init.c +d165 1 +a165 1 + -rm -f expread.tab.c +@ + + +1.2 +log +@All rm's to rm -f's. +@ +text +@d26 1 +a26 1 +CC=gcc +d45 2 +a46 2 +REGEX = +REGEX1 = +d61 1 +a61 1 +CLIBS = $(OBSTACK) $(REGEX) $(GNU_MALLOC) +d63 1 +a63 1 +#CLIBS= $(OBSTACK) $(REGEX) $(GNU_MALLOC) -lPW +@ + + +1.1 +log +@Initial revision +@ +text +@d26 1 +a26 1 +CC=/bin/cc +d114 1 +a114 1 + -rm init.c +d119 1 +a119 1 + -rm init.c +d125 1 +a125 1 + -rm init.c +d151 3 +a153 3 + -rm ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX} + -rm init.c + -rm gdb +d156 1 +a156 1 + -rm expread.tab.c +@ diff --git a/gdb/RCS/blockframe.c,v b/gdb/RCS/blockframe.c,v new file mode 100644 index 0000000..fc64e2f --- /dev/null +++ b/gdb/RCS/blockframe.c,v @@ -0,0 +1,606 @@ +head 1.3; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.3 +date 89.03.16.21.09.52; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.02.09.23.21.53; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.09.15.15.16; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.3 +log +@Don't stop the stack trace until the "next frame pointer" is zero. +@ +text +@/* Get info from stack frames; + convert between frames, blocks, functions and pc values. + Copyright (C) 1986, 1987, 1988 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! +*/ + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" + +/* Address of end of first object file. + This file is assumed to be a startup file + and frames with pc's inside it + are treated as nonexistent. */ + +CORE_ADDR first_object_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); +} + +/* + * 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; +} + +/* Return a structure containing various interesting information + about the frame that called NEXT_FRAME. */ + +struct frame_info * +get_prev_frame_info (next_frame) + FRAME next_frame; +{ + FRAME_ADDR address; + struct frame_info *prev; + int fromleaf = 0; + + /* If we are within "start" right now, don't go any higher. */ + /* This truncates stack traces of things at sigtramp() though, + because sigtramp() doesn't have a normal return PC, it has + garbage or a small value (seen: 3) in the return PC slot. + It's VITAL to see where the signal occurred, so punt this. */ +#if 0 + if (next_frame && next_frame->pc < first_object_file_end) + return 0; +#endif + + /* If the requested entry is in the cache, return it. + Otherwise, figure out what the address should be for the entry + we're about to add to the cache. */ + + if (!next_frame) + { + if (!current_frame) + error ("No frame is currently selected."); + + return current_frame; + } + else + { + /* If we have the prev one, return it */ + if (next_frame->prev) + return next_frame->prev; + + /* There is a questionable, but probably always correct + assumption being made here. The assumption is that if + functions on a specific machine has a FUNCTION_START_OFFSET, + then this is used by the function call instruction for some + purpose. If the function call instruction has this much hair + in it, it probably also sets up the frame pointer + automatically (ie. we'll never have what I am calling a + "leaf node", one which shares a frame pointer with it's + calling function). This is true on a vax. The only other + way to find this out would be to setup a seperate macro + "FUNCTION_HAS_FRAME_POINTER", which would often be equivalent + to SKIP_PROLOGUE modifying a pc value. */ + +#if FUNCTION_START_OFFSET == 0 + if (!(next_frame->next)) + { + /* Innermost */ + CORE_ADDR func_start, after_prologue; + + func_start = (get_pc_function_start (next_frame->pc) + + FUNCTION_START_OFFSET); + after_prologue = func_start; + SKIP_PROLOGUE (after_prologue); + if (after_prologue == func_start) + { + fromleaf = 1; + 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. */ + address = FRAME_CHAIN (next_frame); + if (!FRAME_CHAIN_VALID (address, next_frame)) + return 0; + + /* If frame has a caller, combine the chain pointer and + the frame's own address to get the address of the caller. */ + address = FRAME_CHAIN_COMBINE (address, next_frame); + } + } + + prev = (struct frame_info *) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_info)); + + if (next_frame) + next_frame->prev = prev; + prev->next = next_frame; + prev->prev = (struct frame_info *) 0; + prev->frame = address; + prev->next_frame = prev->next ? prev->next->frame : 0; + +#ifdef INIT_EXTRA_FRAME_INFO + INIT_EXTRA_FRAME_INFO(prev); +#endif + + /* This entry is in the frame queue now, which is good since + FRAME_SAVED_PC may use that queue to figure out it's value + (see m-sparc.h). We want the pc saved in the inferior frame. */ + 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; +{ +#if 1 + FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr); +#else + { + register int regnum; + register int regmask; + register CORE_ADDR next_addr; + register CORE_ADDR pc; + int nextinsn; + bzero (&*saved_regs_addr, sizeof *saved_regs_addr); + if ((frame_info_addr)->pc >= ((frame_info_addr)->frame + - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4) + && (frame_info_addr)->pc <= (frame_info_addr)->frame) + { + next_addr = (frame_info_addr)->frame; + pc = (frame_info_addr)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; + } + else + { + pc = get_pc_function_start ((frame_info_addr)->pc); + /* Verify we have a link a6 instruction next; + if not we lose. If we win, find the address above the saved + regs using the amount of storage from the link instruction. */ + if (044016 == read_memory_integer (pc, 2)) + { + next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 4); + pc += 4; + } + else if (047126 == read_memory_integer (pc, 2)) + { + next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 2); + pc+=2; + } + else goto lose; + + /* If have an addal #-n, sp next, adjust next_addr. */ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) + { + next_addr += read_memory_integer (pc += 2, 4); + pc += 4; + } + } + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ + regmask = read_memory_integer (pc + 2, 2); + + /* But before that can come an fmovem. Check for it. */ + nextinsn = 0xffff & read_memory_integer (pc, 2); + if (0xf227 == nextinsn + && (regmask & 0xff00) == 0xe000) + { + pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ + for (regnum = FP0_REGNUM + 7; + regnum >= FP0_REGNUM; + regnum--, regmask >>= 1) + if (regmask & 1) + (*saved_regs_addr).regs[regnum] = (next_addr -= 12); + regmask = read_memory_integer (pc + 2, 2); + } + if (0044327 == read_memory_integer (pc, 2)) + { + pc += 4; /* Regmask's low bit is for register 0, the first written */ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) + if (regmask & 1) + (*saved_regs_addr).regs[regnum] = (next_addr += 4) - 4; + } + else if (0044347 == read_memory_integer (pc, 2)) + { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) + if (regmask & 1) + (*saved_regs_addr).regs[regnum] = (next_addr -= 4); } + else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) + { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; + (*saved_regs_addr).regs[regnum] = (next_addr -= 4); } + /* fmovemx to index of sp may follow. */ + regmask = read_memory_integer (pc + 2, 2); + nextinsn = 0xffff & read_memory_integer (pc, 2); + if (0xf236 == nextinsn + && (regmask & 0xff00) == 0xf000) + { + pc += 10; /* Regmask's low bit is for register fp0, the first written */ + for (regnum = FP0_REGNUM + 7; + regnum >= FP0_REGNUM; + regnum--, regmask >>= 1) + if (regmask & 1) + (*saved_regs_addr).regs[regnum] = (next_addr += 12) - 12; + regmask = read_memory_integer (pc + 2, 2); + } + /* clrw -(sp); movw ccr,-(sp) may follow. */ + if (0x426742e7 == read_memory_integer (pc, 4)) + (*saved_regs_addr).regs[PS_REGNUM] = (next_addr -= 4); + lose: ; + (*saved_regs_addr).regs[SP_REGNUM] = (frame_info_addr)->frame + 8; + (*saved_regs_addr).regs[FP_REGNUM] = (frame_info_addr)->frame; + (*saved_regs_addr).regs[PC_REGNUM] = (frame_info_addr)->frame + 4; + } +#endif +} + +/* Return the innermost lexical block in execution + in a specified stack frame. The frame address is assumed valid. */ + +struct block * +get_frame_block (frame) + FRAME frame; +{ + struct frame_info *fi; + + fi = get_frame_info (frame); + return block_for_pc (fi->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) + { + 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); +} + +/* 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. */ + + /* 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; + + 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); +} +@ + + +1.2 +log +@Avoid fatal error for simple user error +@ +text +@d142 5 +d149 1 +@ + + +1.1 +log +@Initial revision +@ +text +@d152 1 +a152 1 + fatal ("get_prev_frame_info: Called before cache primed"); +@ diff --git a/gdb/RCS/coffread.c,v b/gdb/RCS/coffread.c,v new file mode 100644 index 0000000..9c45395 --- /dev/null +++ b/gdb/RCS/coffread.c,v @@ -0,0 +1,2047 @@ +head 1.5; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.5 +date 89.03.27.18.38.25; author gnu; state Exp; +branches ; +next 1.4; + +1.4 +date 89.03.27.18.37.20; author gnu; state Exp; +branches ; +next 1.3; + +1.3 +date 89.03.27.18.36.15; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.02.10.01.38.05; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.10.01.32.45; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.5 +log +@Remake A/UX changes. +@ +text +@/* Read coff symbol tables and convert to internal format, for GDB. + Design and support routines derived from dbxread.c, and UMAX COFF + specific routines written 9/1/87 by David D. Johnson, Brown University. + Revised 11/27/87 ddj@@cs.brown.edu + Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc. + +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! +*/ + +#include "defs.h" +#include "param.h" +#ifdef COFF_FORMAT +#include "symtab.h" + +#ifdef USG +#include +#include +#endif + +#include +#include +#include +#include +#include + +/* Avoid problems with A/UX predefine */ +#undef aux + +static void add_symbol_to_list (); +static void read_coff_symtab (); +static void patch_opaque_types (); +static struct type *decode_function_type (); +static struct type *decode_type (); +static struct type *decode_base_type (); +static struct type *read_enum_type (); +static struct type *read_struct_type (); +static void finish_block (); +static struct blockvector *make_blockvector (); +static struct symbol *process_coff_symbol (); +static int init_stringtab (); +static void free_stringtab (); +static char *getfilename (); +static char *getsymname (); +static int init_lineno (); +static void enter_linenos (); + +extern void free_all_symtabs (); +extern void free_all_psymtabs (); + + +/* Name of source file whose symbol data we are now processing. + This comes from a symbol named ".file". */ + +static char *last_source_file; + +/* Core address of start and end of text of current source file. + This comes from a ".text" symbol where x_nlinno > 0. */ + +static CORE_ADDR cur_src_start_addr; +static CORE_ADDR cur_src_end_addr; + +/* End of the text segment of the executable file, + as found in the symbol _etext. */ + +static CORE_ADDR end_of_text_addr; + +/* The addresses of the symbol table stream and number of symbols + of the object file we are reading (as copied into core). */ + +static FILE *nlist_stream_global; +static int nlist_nsyms_global; + +/* The file and text section headers of the symbol file */ + +static FILHDR file_hdr; +static SCNHDR text_hdr; + +/* The index in the symbol table of the last coff symbol that was processed. */ + +static int symnum; + +/* Vector of types defined so far, indexed by their coff symnum. */ + +static struct typevector *type_vector; + +/* Number of elements allocated for type_vector currently. */ + +static int type_vector_length; + +/* 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; + +/* Chain of typedefs of pointers to empty struct/union types. + They are chained thru the SYMBOL_VALUE. */ + +#define HASHSIZE 127 +static struct symbol *opaque_type_chain[HASHSIZE]; + +/* Record the symbols defined for each context in a list. + We don't create a struct block for the context until we + know how long to make it. */ + +struct pending +{ + struct pending *next; + struct symbol *symbol; +}; + +/* Here are the three lists that symbols are put on. */ + +struct pending *file_symbols; /* static at top level, and types */ + +struct pending *global_symbols; /* global functions and variables */ + +struct pending *local_symbols; /* everything local to lexical context */ + +/* List of unclosed lexical contexts + (that will become blocks, eventually). */ + +struct context_stack +{ + struct context_stack *next; + struct pending *locals; + struct pending_block *old_blocks; + struct symbol *name; + CORE_ADDR start_addr; + int depth; +}; + +struct context_stack *context_stack; + +/* Nonzero if within a function (so symbols should be local, + if nothing says specifically). */ + +int within_function; + +/* List of blocks already made (lexical contexts already closed). + This is used at the end to make the blockvector. */ + +struct pending_block +{ + struct pending_block *next; + struct block *block; +}; + +struct pending_block *pending_blocks; + +extern CORE_ADDR first_object_file_end; /* From blockframe.c */ + +/* File name symbols were loaded from. */ + +static char *symfile; + +/* Look up a coff type-number index. Return the address of the slot + where the type for that index is stored. + The type-number is in INDEX. + + This can be used for finding the type associated with that index + or for associating a new type with the index. */ + +static struct type ** +coff_lookup_type (index) + register int index; +{ + if (index >= type_vector_length) + { + int old_vector_length = type_vector_length; + + type_vector_length *= 2; + if (type_vector_length < index) { + type_vector_length = index * 2; + } + type_vector = (struct typevector *) + xrealloc (type_vector, sizeof (struct typevector) + + type_vector_length * sizeof (struct type *)); + bzero (&type_vector->type[ old_vector_length ], + (type_vector_length - old_vector_length) * sizeof(struct type *)); + } + return &type_vector->type[index]; +} + +/* Make sure there is a type allocated for type number index + and return the type object. + This can create an empty (zeroed) type object. */ + +static struct type * +coff_alloc_type (index) + int index; +{ + register struct type **type_addr = coff_lookup_type (index); + register struct type *type = *type_addr; + + /* If we are referring to a type not known at all yet, + allocate an empty type for it. + We will fill it in later if we find out how. */ + if (type == 0) + { + type = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + bzero (type, sizeof (struct type)); + *type_addr = type; + } + return type; +} + +/* maintain the lists of symbols and blocks */ + +/* Add a symbol to one of the lists of symbols. */ +static void +add_symbol_to_list (symbol, listhead) + struct symbol *symbol; + struct pending **listhead; +{ + register struct pending *link + = (struct pending *) xmalloc (sizeof (struct pending)); + + link->next = *listhead; + link->symbol = symbol; + *listhead = link; +} + +/* Take one of the lists of symbols and make a block from it. + Put the block on the list of pending blocks. */ + +static void +finish_block (symbol, listhead, old_blocks, start, end) + struct symbol *symbol; + struct pending **listhead; + struct pending_block *old_blocks; + CORE_ADDR start, end; +{ + register struct pending *next, *next1; + register struct block *block; + register struct pending_block *pblock; + struct pending_block *opblock; + register int i; + + /* Count the length of the list of symbols. */ + + for (next = *listhead, i = 0; next; next = next->next, i++); + + block = (struct block *) + obstack_alloc (symbol_obstack, sizeof (struct block) + (i - 1) * sizeof (struct symbol *)); + + /* Copy the symbols into the block. */ + + BLOCK_NSYMS (block) = i; + for (next = *listhead; next; next = next->next) + BLOCK_SYM (block, --i) = next->symbol; + + BLOCK_START (block) = start; + BLOCK_END (block) = end; + BLOCK_SUPERBLOCK (block) = 0; /* Filled in when containing block is made */ + + /* Put the block in as the value of the symbol that names it. */ + + if (symbol) + { + SYMBOL_BLOCK_VALUE (symbol) = block; + BLOCK_FUNCTION (block) = symbol; + } + else + BLOCK_FUNCTION (block) = 0; + + /* Now free the links of the list, and empty the list. */ + + for (next = *listhead; next; next = next1) + { + next1 = next->next; + free (next); + } + *listhead = 0; + + /* Install this block as the superblock + of all blocks made since the start of this scope + that don't have superblocks yet. */ + + opblock = 0; + for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next) + { + if (BLOCK_SUPERBLOCK (pblock->block) == 0) + BLOCK_SUPERBLOCK (pblock->block) = block; + opblock = pblock; + } + + /* Record this block on the list of all blocks in the file. + Put it after opblock, or at the beginning if opblock is 0. + This puts the block in the list after all its subblocks. */ + + pblock = (struct pending_block *) xmalloc (sizeof (struct pending_block)); + pblock->block = block; + if (opblock) + { + pblock->next = opblock->next; + opblock->next = pblock; + } + else + { + pblock->next = pending_blocks; + pending_blocks = pblock; + } +} + +static struct blockvector * +make_blockvector () +{ + register struct pending_block *next, *next1; + register struct blockvector *blockvector; + register int i; + + /* Count the length of the list of blocks. */ + + for (next = pending_blocks, i = 0; next; next = next->next, i++); + + blockvector = (struct blockvector *) + obstack_alloc (symbol_obstack, sizeof (struct blockvector) + (i - 1) * sizeof (struct block *)); + + /* Copy the blocks into the blockvector. + This is done in reverse order, which happens to put + the blocks into the proper order (ascending starting address). + finish_block has hair to insert each block into the list + after its subblocks in order to make sure this is true. */ + + BLOCKVECTOR_NBLOCKS (blockvector) = i; + for (next = pending_blocks; next; next = next->next) + BLOCKVECTOR_BLOCK (blockvector, --i) = next->block; + + /* Now free the links of the list, and empty the list. */ + + for (next = pending_blocks; next; next = next1) + { + next1 = next->next; + free (next); + } + pending_blocks = 0; + + return blockvector; +} + +/* Manage the vector of line numbers. */ + +static +record_line (line, pc) + int line; + CORE_ADDR pc; +{ + struct linetable_entry *e; + /* Make sure line vector is big enough. */ + + if (line_vector_index + 2 >= line_vector_length) + { + line_vector_length *= 2; + line_vector = (struct linetable *) + xrealloc (line_vector, sizeof (struct linetable) + + (line_vector_length + * sizeof (struct linetable_entry))); + } + + e = line_vector->item + line_vector_index++; + e->line = line; e->pc = pc; +} + +/* Start a new symtab for a new source file. + This is called when a COFF ".file" symbol is seen; + it indicates the start of data for one original source file. */ + +static void +start_symtab () +{ + file_symbols = 0; + global_symbols = 0; + context_stack = 0; + within_function = 0; + last_source_file = 0; + + /* Initialize the source file information for this file. */ + + line_vector_index = 0; + line_vector_length = 1000; + prev_line_number = -2; /* Force first line number to be explicit */ + line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + + line_vector_length * sizeof (struct linetable_entry)); +} + +/* Save the vital information for use when closing off the current file. + NAME is the file name the symbols came from, START_ADDR is the first + text address for the file, and SIZE is the number of bytes of text. */ + +static void +complete_symtab (name, start_addr, size) + char *name; + CORE_ADDR start_addr; + unsigned int size; +{ + last_source_file = savestring (name, strlen (name)); + cur_src_start_addr = start_addr; + cur_src_end_addr = start_addr + size; +} + +/* Finish the symbol definitions for one main source file, + close off all the lexical contexts for that file + (creating struct block's for them), then make the + struct symtab for that file and put it in the list of all such. */ + +static void +end_symtab () +{ + register struct symtab *symtab; + register struct context_stack *cstk; + register struct blockvector *blockvector; + register struct linetable *lv; + + /* Finish the lexical context of the last function in the file. */ + + if (context_stack) + { + cstk = context_stack; + context_stack = 0; + /* Make a block for the local symbols within. */ + finish_block (cstk->name, &local_symbols, cstk->old_blocks, + cstk->start_addr, cur_src_end_addr); + free (cstk); + } + + /* Ignore a file that has no functions with real debugging info. */ + if (pending_blocks == 0 && file_symbols == 0 && global_symbols == 0) + { + free (line_vector); + line_vector = 0; + line_vector_length = -1; + last_source_file = 0; + return; + } + + /* Create the two top-level blocks for this file. */ + finish_block (0, &file_symbols, 0, cur_src_start_addr, cur_src_end_addr); + finish_block (0, &global_symbols, 0, cur_src_start_addr, cur_src_end_addr); + + /* Create the blockvector that points to all the file's blocks. */ + blockvector = make_blockvector (); + + /* Now create the symtab object for this source file. */ + symtab = (struct symtab *) xmalloc (sizeof (struct symtab)); + symtab->free_ptr = 0; + + /* Fill in its components. */ + symtab->blockvector = blockvector; + symtab->free_code = free_linetable; + symtab->filename = last_source_file; + lv = line_vector; + lv->nitems = line_vector_index; + symtab->linetable = (struct linetable *) + xrealloc (lv, (sizeof (struct linetable) + + lv->nitems * sizeof (struct linetable_entry))); + symtab->nlines = 0; + symtab->line_charpos = 0; + + /* Link the new symtab into the list of such. */ + symtab->next = symtab_list; + symtab_list = symtab; + + /* Reinitialize for beginning of new file. */ + line_vector = 0; + line_vector_length = -1; + last_source_file = 0; +} + +/* Accumulate the misc functions in bunches of 127. + At the end, copy them all into one newly allocated structure. */ + +#define MISC_BUNCH_SIZE 127 + +struct misc_bunch +{ + struct misc_bunch *next; + struct misc_function contents[MISC_BUNCH_SIZE]; +}; + +/* Bunch currently being filled up. + The next field points to chain of filled bunches. */ + +static struct misc_bunch *misc_bunch; + +/* Number of slots filled in current bunch. */ + +static int misc_bunch_index; + +/* Total number of misc functions recorded so far. */ + +static int misc_count; + +static void +init_misc_functions () +{ + misc_count = 0; + misc_bunch = 0; + misc_bunch_index = MISC_BUNCH_SIZE; +} + +static void +record_misc_function (name, address) + char *name; + CORE_ADDR address; +{ + register struct misc_bunch *new; + + if (misc_bunch_index == MISC_BUNCH_SIZE) + { + new = (struct misc_bunch *) xmalloc (sizeof (struct misc_bunch)); + misc_bunch_index = 0; + new->next = misc_bunch; + misc_bunch = new; + } + misc_bunch->contents[misc_bunch_index].name = savestring (name, strlen (name)); + misc_bunch->contents[misc_bunch_index].address = address; + misc_bunch_index++; + misc_count++; +} + +/* if we see a function symbol, we do record_misc_function. + * however, if it turns out the next symbol is '.bf', then + * we call here to undo the misc definition + */ +static void +unrecord_misc_function () +{ + if (misc_bunch_index == 0) + error ("Internal error processing symbol table, at symbol %d.", + symnum); + misc_bunch_index--; + misc_count--; +} + + +static int +compare_misc_functions (fn1, fn2) + struct misc_function *fn1, *fn2; +{ + /* Return a signed result based on unsigned comparisons + so that we sort into unsigned numeric order. */ + if (fn1->address < fn2->address) + return -1; + if (fn1->address > fn2->address) + return 1; + return 0; +} + +static void +discard_misc_bunches () +{ + register struct misc_bunch *next; + + while (misc_bunch) + { + next = misc_bunch->next; + free (misc_bunch); + misc_bunch = next; + } +} + +static void +condense_misc_bunches () +{ + register int i, j; + register struct misc_bunch *bunch; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + + misc_function_vector + = (struct misc_function *) + xmalloc (misc_count * sizeof (struct misc_function)); + + j = 0; + bunch = misc_bunch; + while (bunch) + { + for (i = 0; i < misc_bunch_index; i++) + { + register char *tmp; + + misc_function_vector[j] = bunch->contents[i]; + tmp = misc_function_vector[j].name; + misc_function_vector[j].name = (tmp[0] == '_' ? tmp + offset : tmp); + j++; + } + bunch = bunch->next; + misc_bunch_index = MISC_BUNCH_SIZE; + } + + misc_function_count = j; + + /* Sort the misc functions by address. */ + + qsort (misc_function_vector, j, sizeof (struct misc_function), + compare_misc_functions); +} + +/* Call sort_syms to sort alphabetically + the symbols of each block of each symtab. */ + +static int +compare_symbols (s1, s2) + struct symbol **s1, **s2; +{ + /* Names that are less should come first. */ + register int namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2)); + if (namediff != 0) return namediff; + /* For symbols of the same name, registers should come first. */ + return ((SYMBOL_CLASS (*s2) == LOC_REGISTER) + - (SYMBOL_CLASS (*s1) == LOC_REGISTER)); +} + +static void +sort_syms () +{ + register struct symtab *s; + register int i, nbl; + register struct blockvector *bv; + register struct block *b; + + for (s = symtab_list; s; s = s->next) + { + bv = BLOCKVECTOR (s); + nbl = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < nbl; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + if (BLOCK_SHOULD_SORT (b)) + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); + } + } +} + +/* 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) + char *name; +{ + int desc; + int num_symbols; + int num_sections; + int symtab_offset; + extern void close (); + register int val; + struct cleanup *old_chain; + + dont_repeat (); + + if (name == 0) + { + if (symtab_list && !query ("Discard symbol table? ", 0)) + error ("Not confirmed."); + if (symfile) + free (symfile); + symfile = 0; + free_all_symtabs (); + return; + } + + if (symtab_list && !query ("Load new symbol table from \"%s\"? ", name)) + error ("Not confirmed."); + + if (symfile) + free (symfile); + symfile = 0; + + { + char *absolute_name; + + desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name); + if (desc < 0) + perror_with_name (name); + else + name = absolute_name; + } + + old_chain = make_cleanup (close, desc); + make_cleanup (free_current_contents, &name); + + if ((num_symbols = read_file_hdr (desc, &file_hdr)) < 0) + error ("File \"%s\" not in executable format.", name); + + if (num_symbols == 0) + { + free_all_symtabs (); + printf ("%s does not have a symbol-table.\n", name); + fflush (stdout); + return; + } + + printf ("Reading symbol data from %s...", name); + fflush (stdout); + + /* Throw away the old symbol table. */ + + free_all_symtabs (); + free_all_psymtabs (); /* Make sure that partial_symtab_list */ + /* is 0 also. */ + + num_sections = file_hdr.f_nscns; + symtab_offset = file_hdr.f_symptr; + + if (read_section_hdr (desc, _TEXT, &text_hdr, num_sections) < 0) + error ("\"%s\": can't read text section header", name); + + /* Read the line number table, all at once. */ + + val = init_lineno (desc, text_hdr.s_lnnoptr, text_hdr.s_nlnno); + if (val < 0) + error ("\"%s\": error reading line numbers\n", name); + + /* Now read the string table, all at once. */ + + val = init_stringtab (desc, symtab_offset + num_symbols * SYMESZ); + if (val < 0) + { + free_all_symtabs (); + printf ("\"%s\": can't get string table", name); + fflush (stdout); + return; + } + make_cleanup (free_stringtab, 0); + + /* Position to read the symbol table. Do not read it all at once. */ + val = lseek (desc, (long)symtab_offset, 0); + if (val < 0) + perror_with_name (name); + + init_misc_functions (); + make_cleanup (discard_misc_bunches, 0); + + /* Now that the executable file is positioned at symbol table, + process it and define symbols accordingly. */ + + read_coff_symtab (desc, num_symbols); + + patch_opaque_types (); + + /* Sort symbols alphabetically within each block. */ + + sort_syms (); + + /* Go over the misc functions and install them in vector. */ + + condense_misc_bunches (); + + /* 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. */ + + select_source_symtab (symtab_list); + + symfile = savestring (name, strlen (name)); + + do_cleanups (old_chain); + + printf ("done.\n"); + fflush (stdout); +} + +/* Return name of file symbols were loaded from, or 0 if none.. */ + +char * +get_sym_file () +{ + return symfile; +} + +/* Simplified internal version of coff symbol table information */ + +struct coff_symbol { + char *c_name; + int c_symnum; /* symbol number of this entry */ + int c_nsyms; /* 1 if syment only, 2 if syment + auxent */ + long c_value; + int c_sclass; + int c_secnum; + unsigned int c_type; +}; + +/* Given pointers to a symbol table in coff style exec file, + analyze them and create struct symtab's describing the symbols. + NSYMS is the number of symbols in the symbol table. + We read them one at a time using read_one_sym (). */ + +static void +read_coff_symtab (desc, nsyms) + int desc; + int nsyms; +{ + int newfd; /* Avoid multiple closes on same desc */ + FILE *stream; + register struct context_stack *new; + struct coff_symbol coff_symbol; + register struct coff_symbol *cs = &coff_symbol; + static SYMENT main_sym; + static AUXENT main_aux; + struct coff_symbol fcn_cs_saved; + static SYMENT fcn_sym_saved; + static AUXENT fcn_aux_saved; + + int num_object_files = 0; + int next_file_symnum = -1; + char *filestring; + int depth; + int fcn_first_line; + int fcn_last_line; + int fcn_start_addr; + long fcn_line_ptr; + struct cleanup *old_chain; + int fclose(); + + newfd = dup (desc); + if (newfd == -1) + fatal ("Too many open files"); + stream = fdopen (newfd, "r"); + + old_chain = make_cleanup (free_all_symtabs, 0); + make_cleanup (fclose, stream); + nlist_stream_global = stream; + nlist_nsyms_global = nsyms; + last_source_file = 0; + bzero (opaque_type_chain, sizeof opaque_type_chain); + + type_vector_length = 160; + type_vector = (struct typevector *) + xmalloc (sizeof (struct typevector) + + type_vector_length * sizeof (struct type *)); + bzero (type_vector->type, type_vector_length * sizeof (struct type *)); + + start_symtab (); + + symnum = 0; + while (symnum < nsyms) + { + QUIT; /* Make this command interruptable. */ + read_one_sym (cs, &main_sym, &main_aux); + + if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE) + { + CORE_ADDR last_file_end = cur_src_end_addr; + + if (last_source_file) + end_symtab (); + + start_symtab (); + complete_symtab ("_globals_", 0, first_object_file_end); + /* done with all files, everything from here on out is globals */ + } + + /* Special case for file with type declarations only, no text. */ + if (!last_source_file && cs->c_type != T_NULL && cs->c_secnum == N_DEBUG) + complete_symtab (filestring, 0, 0); + + /* Typedefs should not be treated as symbol definitions. */ + if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF) + { + /* record as misc function. if we get '.bf' next, + * then we undo this step + */ + record_misc_function (cs->c_name, cs->c_value); + + fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr; + fcn_start_addr = cs->c_value; + fcn_cs_saved = *cs; + fcn_sym_saved = main_sym; + fcn_aux_saved = main_aux; + continue; + } + + switch (cs->c_sclass) + { + case C_EFCN: + case C_EXTDEF: + case C_ULABEL: + case C_USTATIC: + case C_LINE: + case C_ALIAS: + case C_HIDDEN: + printf ("Bad n_sclass = %d\n", cs->c_sclass); + break; + + case C_FILE: + /* + * c_value field contains symnum of next .file entry in table + * or symnum of first global after last .file. + */ + next_file_symnum = cs->c_value; + filestring = getfilename (&main_aux); + /* + * Complete symbol table for last object file + * containing debugging information. + */ + if (last_source_file) + { + end_symtab (); + start_symtab (); + } + num_object_files++; + break; + + case C_STAT: + if (cs->c_name[0] == '.') { + if (strcmp (cs->c_name, _TEXT) == 0) { + if (num_object_files == 1) { + /* last address of startup file */ + first_object_file_end = cs->c_value + + main_aux.x_scn.x_scnlen; + } + /* for some reason the old code didn't do + * this if this section entry had + * main_aux.x_scn.x_nlinno equal to 0 + */ + complete_symtab (filestring, cs->c_value, + main_aux.x_scn.x_scnlen); + } + /* flush rest of '.' symbols */ + break; + } + /* fall in for static symbols that don't start with '.' */ + case C_EXT: + if (cs->c_sclass == C_EXT && + cs->c_secnum == N_ABS && + strcmp (cs->c_name, _ETEXT) == 0) + end_of_text_addr = cs->c_value; + if (cs->c_type == T_NULL) { + if (cs->c_secnum <= 1) { /* text or abs */ + record_misc_function (cs->c_name, cs->c_value); + break; + } else { + cs->c_type = T_INT; + } + } + (void) process_coff_symbol (cs, &main_aux); + break; + + case C_FCN: + if (strcmp (cs->c_name, ".bf") == 0) + { + unrecord_misc_function (); + + within_function = 1; + + /* value contains address of first non-init type code */ + /* main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains line number of '{' } */ + fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + + new = (struct context_stack *) + xmalloc (sizeof (struct context_stack)); + new->depth = depth = 0; + new->next = 0; + context_stack = new; + new->locals = 0; + new->old_blocks = pending_blocks; + new->start_addr = fcn_start_addr; + fcn_cs_saved.c_name = getsymname (&fcn_sym_saved); + new->name = process_coff_symbol (&fcn_cs_saved, + &fcn_aux_saved); + } + else if (strcmp (cs->c_name, ".ef") == 0) + { + /* the value of .ef is the address of epilogue code; + * not useful for gdb + */ + /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains number of lines to '}' */ + fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line); + new = context_stack; + + if (new == 0) + error ("Invalid symbol data; .bf/.ef/.bb/.eb symbol mismatch, at symbol %d.", + symnum); + + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, + fcn_cs_saved.c_value + + fcn_aux_saved.x_sym.x_misc.x_fsize); + context_stack = 0; + within_function = 0; + free (new); + } + break; + + case C_BLOCK: + if (strcmp (cs->c_name, ".bb") == 0) + { + new = (struct context_stack *) + xmalloc (sizeof (struct context_stack)); + depth++; + new->depth = depth; + new->next = context_stack; + context_stack = new; + new->locals = local_symbols; + new->old_blocks = pending_blocks; + new->start_addr = cs->c_value; + new->name = 0; + local_symbols = 0; + } + else if (strcmp (cs->c_name, ".eb") == 0) + { + new = context_stack; + if (new == 0 || depth != new->depth) + error ("Invalid symbol data: .bb/.eb symbol mismatch at symbol %d.", + symnum); + if (local_symbols && context_stack->next) + { + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr, cs->c_value); + } + depth--; + local_symbols = new->locals; + context_stack = new->next; + free (new); + } + break; + + default: + (void) process_coff_symbol (cs, &main_aux); + break; + } + } + + if (last_source_file) + end_symtab (); + fclose (stream); + discard_cleanups (old_chain); +} + +/* Routines for reading headers and symbols from executable. */ + +/* Read COFF file header, check magic number, + and return number of symbols. */ +read_file_hdr (chan, file_hdr) + int chan; + FILHDR *file_hdr; +{ + lseek (chan, 0L, 0); + if (myread (chan, (char *)file_hdr, FILHSZ) < 0) + return -1; + + switch (file_hdr->f_magic) + { +#ifdef NS32GMAGIC + case NS32GMAGIC: + case NS32SMAGIC: +#endif +#ifdef I386MAGIC + case I386MAGIC: +#endif + return file_hdr->f_nsyms; + + + default: +#ifdef BADMAG + if (BADMAG(file_hdr)) + return -1; + else + return file_hdr->f_nsyms; +#else + return -1; +#endif + } +} + +read_aout_hdr (chan, aout_hdr, size) + int chan; + AOUTHDR *aout_hdr; + int size; +{ + lseek (chan, (long)FILHSZ, 0); + if (size != sizeof (AOUTHDR)) + return -1; + if (myread (chan, (char *)aout_hdr, size) != size) + return -1; + return 0; +} + +read_section_hdr (chan, section_name, section_hdr, nsects) + register int chan; + register char *section_name; + SCNHDR *section_hdr; + register int nsects; +{ + register int i; + + if (lseek (chan, FILHSZ + sizeof (AOUTHDR), 0) < 0) + return -1; + + for (i = 0; i < nsects; i++) + { + if (myread (chan, (char *)section_hdr, SCNHSZ) < 0) + return -1; + if (strncmp (section_hdr->s_name, section_name, 8) == 0) + return 0; + } + return -1; +} + +read_one_sym (cs, sym, aux) + register struct coff_symbol *cs; + register SYMENT *sym; + register AUXENT *aux; +{ + cs->c_symnum = symnum; + fread ((char *)sym, SYMESZ, 1, nlist_stream_global); + cs->c_nsyms = (sym->n_numaux & 0xff) + 1; + if (cs->c_nsyms == 2) + { + /* doc for coff says there is either no aux entry or just one */ + fread ((char *)aux, AUXESZ, 1, nlist_stream_global); + } + else if (cs->c_nsyms > 2) + error ("more than one aux symbol table entry at symnum=%d\n", symnum); + + cs->c_name = getsymname (sym); + cs->c_value = sym->n_value; + cs->c_sclass = (sym->n_sclass & 0xff); + cs->c_secnum = sym->n_scnum; + cs->c_type = (unsigned) sym->n_type; + + symnum += cs->c_nsyms; +} + +/* Support for string table handling */ + +static char *stringtab = NULL; + +static int +init_stringtab (chan, offset) + int chan; + long offset; +{ + long buffer; + int val; + + if (stringtab) + { + free (stringtab); + stringtab = NULL; + } + + if (lseek (chan, offset, 0) < 0) + return -1; + + val = myread (chan, (char *)&buffer, sizeof buffer); + + /* If no string table is needed, then the file may end immediately + after the symbols. Just return with `stringtab' set to null. */ + if (val != sizeof buffer || buffer == 0) + return 0; + + stringtab = (char *) xmalloc (buffer); + if (stringtab == NULL) + return -1; + + bcopy (&buffer, stringtab, sizeof buffer); + + val = myread (chan, stringtab + sizeof buffer, buffer - sizeof buffer); + if (val != buffer - sizeof buffer || stringtab[buffer - 1] != '\0') + return -1; + + return 0; +} + +static void +free_stringtab () +{ + if (stringtab) + free (stringtab); + stringtab = NULL; +} + +static char * +getsymname (symbol_entry) + SYMENT *symbol_entry; +{ + static char buffer[SYMNMLEN+1]; + char *result; + + if (symbol_entry->n_zeroes == 0) + { + result = stringtab + symbol_entry->n_offset; + } + else + { + strncpy (buffer, symbol_entry->n_name, SYMNMLEN); + buffer[SYMNMLEN] = '\0'; + result = buffer; + } + return result; +} + +static char * +getfilename (aux_entry) + AUXENT *aux_entry; +{ + static char buffer[BUFSIZ]; + register char *temp; + char *result; + extern char *rindex (); + +#ifndef COFF_NO_LONG_FILE_NAMES + if (aux_entry->x_file.x_foff != 0) + strcpy (buffer, stringtab + aux_entry->x_file.x_foff); + else +#endif + { + strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN); + buffer[FILNMLEN] = '\0'; + } + result = buffer; + if ((temp = rindex (result, '/')) != NULL) + result = temp + 1; + return (result); +} + +/* Support for line number handling */ +static char *linetab = NULL; +static long linetab_offset; +static int linetab_count; + +static int +init_lineno (chan, offset, count) + int chan; + long offset; + int count; +{ + int val; + + if (lseek (chan, offset, 0) < 0) + return -1; + + if (linetab) + free (linetab); + linetab = (char *) xmalloc (count * LINESZ); + + val = myread (chan, linetab, count * LINESZ); + if (val != count * LINESZ) + return -1; + + linetab_offset = offset; + linetab_count = count; + return 0; +} + +static void +enter_linenos (file_offset, first_line, last_line) + long file_offset; + register int first_line; + register int last_line; +{ + register char *rawptr = &linetab[file_offset - linetab_offset]; + register struct lineno *lptr; + + /* skip first line entry for each function */ + rawptr += LINESZ; + /* line numbers start at one for the first line of the function */ + first_line--; + + for (lptr = (struct lineno *)rawptr; + lptr->l_lnno && lptr->l_lnno <= last_line; + rawptr += LINESZ, lptr = (struct lineno *)rawptr) + { + record_line (first_line + lptr->l_lnno, lptr->l_addr.l_paddr); + } +} + +static int +hashname (name) + char *name; +{ + register char *p = name; + register int total = p[0]; + register int c; + + c = p[1]; + total += c << 2; + if (c) + { + c = p[2]; + total += c << 4; + if (c) + total += p[3] << 6; + } + + return total % HASHSIZE; +} + +static void +patch_type (type, real_type) + struct type *type; + struct type *real_type; +{ + register struct type *target = TYPE_TARGET_TYPE (type); + register struct type *real_target = TYPE_TARGET_TYPE (real_type); + int field_size = TYPE_NFIELDS (real_target) * sizeof (struct field); + + TYPE_LENGTH (target) = TYPE_LENGTH (real_target); + TYPE_NFIELDS (target) = TYPE_NFIELDS (real_target); + TYPE_FIELDS (target) = (struct field *) + obstack_alloc (symbol_obstack, field_size); + + bcopy (TYPE_FIELDS (real_target), TYPE_FIELDS (target), field_size); + + if (TYPE_NAME (real_target)) + { + if (TYPE_NAME (target)) + free (TYPE_NAME (target)); + TYPE_NAME (target) = concat (TYPE_NAME (real_target), "", ""); + } +} + +/* Patch up all appropriate typdef symbols in the opaque_type_chains + so that they can be used to print out opaque data structures properly */ + +static void +patch_opaque_types () +{ + struct symtab *s; + + /* Look at each symbol in the per-file block of each symtab. */ + for (s = symtab_list; s; s = s->next) + { + register struct block *b; + register int i; + + /* Go through the per-file symbols only */ + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1); + for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--) + { + register struct symbol *real_sym; + + /* Find completed typedefs to use to fix opaque ones. + Remove syms from the chain when their types are stored, + but search the whole chain, as there may be several syms + from different files with the same name. */ + real_sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF && + SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE && + TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0) + { + register char *name = SYMBOL_NAME (real_sym); + register int hash = hashname (name); + register struct symbol *sym, *prev; + + prev = 0; + for (sym = opaque_type_chain[hash]; sym;) + { + if (name[0] == SYMBOL_NAME (sym)[0] && + !strcmp (name + 1, SYMBOL_NAME (sym) + 1)) + { + if (prev) + SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym); + else + opaque_type_chain[hash] + = (struct symbol *) SYMBOL_VALUE (sym); + + patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym)); + + if (prev) + sym = (struct symbol *) SYMBOL_VALUE (prev); + else + sym = opaque_type_chain[hash]; + } + else + { + prev = sym; + sym = (struct symbol *) SYMBOL_VALUE (sym); + } + } + } + } + } +} + +static struct symbol * +process_coff_symbol (cs, aux) + register struct coff_symbol *cs; + register AUXENT *aux; +{ + register struct symbol *sym + = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol)); + char *name; + char *dot; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + + bzero (sym, sizeof (struct symbol)); + name = cs->c_name; + name = (name[0] == '_' ? name + offset : name); + SYMBOL_NAME (sym) = obstack_copy0 (symbol_obstack, name, strlen (name)); + + /* default assumptions */ + SYMBOL_VALUE (sym) = cs->c_value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + + if (ISFCN (cs->c_type)) + { + SYMBOL_TYPE (sym) = + lookup_function_type (decode_function_type (cs, cs->c_type, aux)); + SYMBOL_CLASS (sym) = LOC_BLOCK; + if (cs->c_sclass == C_STAT) + add_symbol_to_list (sym, &file_symbols); + else if (cs->c_sclass == C_EXT) + add_symbol_to_list (sym, &global_symbols); + } + else + { + SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux); + switch (cs->c_sclass) + { + case C_NULL: + break; + + case C_AUTO: + SYMBOL_CLASS (sym) = LOC_LOCAL; + add_symbol_to_list (sym, &local_symbols); + break; + + case C_EXT: + SYMBOL_CLASS (sym) = LOC_STATIC; + add_symbol_to_list (sym, &global_symbols); + break; + + case C_STAT: + SYMBOL_CLASS (sym) = LOC_STATIC; + if (within_function) { + /* Static symbol of local scope */ + add_symbol_to_list (sym, &local_symbols); + } + else { + /* Static symbol at top level of file */ + add_symbol_to_list (sym, &file_symbols); + } + break; + + case C_REG: + case C_REGPARM: + SYMBOL_CLASS (sym) = LOC_REGISTER; + add_symbol_to_list (sym, &local_symbols); + break; + + case C_LABEL: + break; + + case C_ARG: + SYMBOL_CLASS (sym) = LOC_ARG; + add_symbol_to_list (sym, &local_symbols); + /* If 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; + + case C_TPDEF: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + + /* If type has no name, give it one */ + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0 + && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) + = concat (SYMBOL_NAME (sym), "", ""); + + /* Keep track of any type which points to empty structured type, + so it can be filled from a definition from another file */ + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0) + { + register int i = hashname (SYMBOL_NAME (sym)); + + SYMBOL_VALUE (sym) = (int) opaque_type_chain[i]; + opaque_type_chain[i] = sym; + } + add_symbol_to_list (sym, &file_symbols); + break; + + case C_STRTAG: + case C_UNTAG: + case C_ENTAG: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0 + && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) + = concat ("", + (cs->c_sclass == C_ENTAG + ? "enum " + : (cs->c_sclass == C_STRTAG + ? "struct " : "union ")), + SYMBOL_NAME (sym)); + add_symbol_to_list (sym, &file_symbols); + break; + + default: + break; + } + } + return sym; +} + +/* Decode a coff type specifier; + return the type that is meant. */ + +static +struct type * +decode_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register AUXENT *aux; +{ + register struct type *type = 0; + register int n; + unsigned int new_c_type; + + if (c_type & ~N_BTMASK) + { + new_c_type = DECREF (c_type); + if (ISPTR (c_type)) + { + type = decode_type (cs, new_c_type, aux); + type = lookup_pointer_type (type); + } + else if (ISFCN (c_type)) + { + type = decode_type (cs, new_c_type, aux); + type = lookup_function_type (type); + } + else if (ISARY (c_type)) + { + int i, n; + register unsigned short *dim; + struct type *base_type; + + /* Define an array type. */ + /* auxent refers to array, not base type */ + if (aux->x_sym.x_tagndx == 0) + cs->c_nsyms = 1; + + /* shift the indices down */ + dim = &aux->x_sym.x_fcnary.x_ary.x_dimen[0]; + i = 1; + n = dim[0]; + for (i = 0; *dim && i < DIMNUM - 1; i++, dim++) + *dim = *(dim + 1); + *dim = 0; + + type = (struct type *) + obstack_alloc (symbol_obstack, sizeof (struct type)); + bzero (type, sizeof (struct type)); + + base_type = decode_type (cs, new_c_type, aux); + + TYPE_CODE (type) = TYPE_CODE_ARRAY; + TYPE_TARGET_TYPE (type) = base_type; + TYPE_LENGTH (type) = n * TYPE_LENGTH (base_type); + } + return type; + } + + /* Reference to existing type */ + if (cs->c_nsyms > 1 && aux->x_sym.x_tagndx != 0) + { + type = coff_alloc_type (aux->x_sym.x_tagndx); + return type; + } + + return decode_base_type (cs, BTYPE (c_type), aux); +} + +/* Decode a coff type specifier for function definition; + return the type that the function returns. */ + +static +struct type * +decode_function_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register AUXENT *aux; +{ + if (aux->x_sym.x_tagndx == 0) + cs->c_nsyms = 1; /* auxent refers to function, not base type */ + + return decode_type (cs, DECREF (cs->c_type), aux); +} + +/* basic C types */ + +static +struct type * +decode_base_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register AUXENT *aux; +{ + struct type *type; + + switch (c_type) + { + case T_NULL: + /* shows up with "void (*foo)();" structure members */ + return builtin_type_void; + + case T_ARG: + /* shouldn't show up here */ + break; + + case T_CHAR: + return builtin_type_char; + + case T_SHORT: + return builtin_type_short; + + case T_INT: + return builtin_type_int; + + case T_LONG: + return builtin_type_long; + + case T_FLOAT: + return builtin_type_float; + + case T_DOUBLE: + return builtin_type_double; + + case T_STRUCT: + if (cs->c_nsyms != 2) + { + /* anonymous structure type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_NAME (type) = concat ("struct ", "", ""); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx); + } + return type; + + case T_UNION: + if (cs->c_nsyms != 2) + { + /* anonymous union type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_NAME (type) = concat ("union ", "", ""); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx); + } + TYPE_CODE (type) = TYPE_CODE_UNION; + return type; + + case T_ENUM: + return read_enum_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx); + + case T_MOE: + /* shouldn't show up here */ + break; + + case T_UCHAR: + return builtin_type_unsigned_char; + + case T_USHORT: + return builtin_type_unsigned_short; + + case T_UINT: + return builtin_type_unsigned_int; + + case T_ULONG: + return builtin_type_unsigned_long; + } + printf ("unexpected type %d at symnum %d\n", c_type, cs->c_symnum); + return builtin_type_void; +} + +/* This page contains subroutines of read_type. */ + +/* Read the description of a structure (or union type) + and return an object describing the type. */ + +static struct type * +read_struct_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + struct nextfield + { + struct nextfield *next; + struct field field; + }; + + register struct type *type; + register struct nextfield *list = 0; + struct nextfield *new; + int nfields = 0; + register int n; + char *name; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + SYMENT sub_sym; + AUXENT sub_aux; + int done = 0; + + type = coff_alloc_type (index); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_LENGTH (type) = length; + + while (!done && symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = (name[0] == '_' ? name + offset : name); + + switch (ms->c_sclass) + { + case C_MOS: + case C_MOU: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = savestring (name, strlen (name)); + list->field.type = decode_type (ms, ms->c_type, &sub_aux); + list->field.bitpos = 8 * ms->c_value; + list->field.bitsize = 0; + nfields++; + break; + + case C_FIELD: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = savestring (name, strlen (name)); + list->field.type = decode_type (ms, ms->c_type, &sub_aux); + list->field.bitpos = ms->c_value; + list->field.bitsize = sub_aux.x_sym.x_misc.x_lnsz.x_size; + nfields++; + break; + + case C_EOS: + done = 1; + break; + } + } + /* Now create the vector of fields, and record how big it is. */ + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + obstack_alloc (symbol_obstack, sizeof (struct field) * nfields); + + /* Copy the saved-up fields into the field vector. */ + + for (n = nfields; list; list = list->next) + TYPE_FIELD (type, --n) = list->field; + + return type; +} + +/* Read a definition of an enumeration type, + and create and return a suitable type object. + Also defines the symbols that represent the values of the type. */ + +static struct type * +read_enum_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + register struct symbol *sym; + register struct type *type; + int nsyms = 0; + struct pending **symlist; + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + SYMENT sub_sym; + AUXENT sub_aux; + struct pending *osyms, *syms; + register int n; + char *name; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + + type = coff_alloc_type (index); + if (within_function) + symlist = &local_symbols; + else + symlist = &file_symbols; + osyms = *symlist; + + while (symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = (name[0] == '_' ? name + offset : name); + + switch (ms->c_sclass) + { + case C_MOE: + sym = (struct symbol *) xmalloc (sizeof (struct symbol)); + bzero (sym, sizeof (struct symbol)); + + SYMBOL_NAME (sym) = savestring (name, strlen (name)); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = ms->c_value; + add_symbol_to_list (sym, symlist); + nsyms++; + break; + + case C_EOS: + break; + } + } + + /* Now fill in the fields of the type-structure. */ + + TYPE_LENGTH (type) = sizeof (int); + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NFIELDS (type) = nsyms; + TYPE_FIELDS (type) = (struct field *) + obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms); + + /* Find the symbols for the values and put them into the type. + The symbols can be found in the symlist that we put them on + to cause them to be defined. osyms contains the old value + of that symlist; everything up to there was defined by us. */ + + for (syms = *symlist, n = nsyms; syms != osyms; syms = syms->next) + { + SYMBOL_TYPE (syms->symbol) = type; + TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (syms->symbol); + TYPE_FIELD_VALUE (type, n) = 0; + TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (syms->symbol); + TYPE_FIELD_BITSIZE (type, n) = 0; + } + return type; +} + +/* This function is really horrible, but to avoid it, there would need + to be more filling in of forward references. THIS SHOULD BE MOVED + OUT OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED. */ +int +fill_in_vptr_fieldno (type) + struct type *type; +{ + if (TYPE_VPTR_FIELDNO (type) < 0) + TYPE_VPTR_FIELDNO (type) = + fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1)); + return TYPE_VPTR_FIELDNO (type); +} + +/* partial symbol tables are not implemented in coff, therefore + block_for_pc() (and others) will never decide to call this. */ + +extern struct symtab * +psymtab_to_symtab () +{ + fatal ("error: Someone called psymtab_to_symtab\n"); +} + +/* These will stay zero all the time */ +struct partial_symbol *global_psymbols, *static_psymbols; + +_initialize_coff () +{ + symfile = 0; + + static_psymbols = global_psymbols = (struct partial_symbol *) 0; + + add_com ("symbol-file", class_files, symbol_file_command, + "Load symbol table (in coff format) from executable file FILE."); +} + + +#endif /* COFF_FORMAT */ + +@ + + +1.4 +log +@Avoid A/UX change (#undef aux) for sending in to FSF. +@ +text +@d40 3 +@ + + +1.3 +log +@A/UX and USG changes. If BADMAG defined, use it. Avoid . +Declare fclose(). #undef aux which we use as a var. +@ +text +@a39 3 +/* Avoid problems with A/UX predefine */ +#undef aux + +@ + + +1.2 +log +@If discarding the symbol table, discard its name too, so "info files" +will give the right answer. +@ +text +@d31 1 +a31 1 +#include +d40 3 +d847 1 +a847 1 + +d1093 6 +d1100 1 +@ + + +1.1 +log +@Initial revision +@ +text +@d5 1 +a5 1 + Copyright (C) 1987, 1988 Free Software Foundation, Inc. +d684 3 +@ diff --git a/gdb/RCS/config.gdb,v b/gdb/RCS/config.gdb,v new file mode 100755 index 0000000..b569f62 --- /dev/null +++ b/gdb/RCS/config.gdb,v @@ -0,0 +1,229 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @@; + + +1.2 +date 89.03.27.18.38.55; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.13.19.14.24; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Add A/UX option (config.gdb aux). +@ +text +@#!/bin/sh + +# +# Shell script to create proper links to machine-dependent files in +# preparation for compiling gdb. +# +# Usage: config.gdb machine [operating-system] +# +# If config.gdb succeeds, it leaves its status in config.status. +# If config.gdb fails after disturbing the status quo, +# config.status is removed. +# + +progname=$0 + +case $# in +1) + machine=$1 + os="none" + ;; +2) + machine=$1 + os=$2 + ;; +*) + echo "Usage: $progname machine [operating-system]" + echo "Available machine types:" + echo m-*.h | sed 's/m-//g' | sed 's/\.h//g' + if [ -r config.status ] + then + cat config.status + fi + exit 1 + ;; +esac + +paramfile=m-${machine}.h +pinsnfile=${machine}-pinsn.c +opcodefile=${machine}-opcode.h +if [ -r ${machine}-dep.c ] +then + depfile=${machine}-dep.c +else + depfile=default-dep.c +fi + +# +# Special cases. +# If a file is not needed, set the filename to 'skip' and it will be +# ignored. +# +case $machine in +aux) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +vax) + pinsnfile=vax-pinsn.c + opcodefile=vax-opcode.h + ;; +hp9k320) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +isi) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +i386) + echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile" + opcodefile=skip + ;; +i386gas) + echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile" + echo "Use of the coff encapsulation features also requires the GNU binutils utilities" + echo "to be ahead of their System V counterparts in your path." + pinsnfile=i386-pinsn.c + depfile=i386-dep.c + opcodefile=skip + ;; +merlin) + pinsnfile=ns32k-pinsn.c + opcodefile=ns32k-opcode.h + ;; +news) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +npl) + pinsnfile=gld-pinsn.c + ;; +pn) + pinsnfile=gld-pinsn.c + ;; +sun2) + case $os in + os4|sunos4) + paramfile=m-sun2os4.h + ;; + os2|sunos2) + paramfile=m-sun2os2.h + esac + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +sun2os2) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +sun2os4) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +sun3) + case $os in + os4|sunos4) + paramfile=m-sun3os4.h + esac + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +sun3os4) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + depfile=sun3-dep.c + ;; +sun4os4) + pinsnfile=sparc-pinsn.c + opcodefile=sparc-opcode.h + depfile=sparc-dep.c + ;; +umax) + pinsnfile=ns32k-pinsn.c + opcodefile=ns32k-opcode.h + ;; +sparc|sun4) + case $os in + os4|sunos4) + paramfile=m-sun4os4.h + esac + pinsnfile=sparc-pinsn.c + opcodefile=sparc-opcode.h + depfile=sparc-dep.c + paramfile=m-sparc.h + ;; +test) + paramfile=one + pinsnfile=three + opcodefile=four + ;; +*) + echo "Unknown machine type: \`$machine'" + echo "Available types:" + echo m-*.h | sed 's/m-//g' | sed 's/\.h//g' + exit 1 +esac + +files="$paramfile $pinsnfile $opcodefile $depfile" +links="param.h pinsn.c opcode.h dep.c" + +while [ -n "$files" ] +do + # set file to car of files, files to cdr of files + set $files; file=$1; shift; files=$* + set $links; link=$1; shift; links=$* + + if [ "$file" != skip ] + then + if [ ! -r $file ] + then + echo "$progname: cannot create a link \`$link'," + echo "since the file \`$file' does not exist." + exit 1 + fi + + rm -f $link config.status + # Make a symlink if possible, otherwise try a hard link + ln -s $file $link 2>/dev/null || ln $file $link + + if [ ! -r $link ] + then + echo "$progname: unable to link \`$link' to \`$file'." + exit 1 + fi + echo "Linked \`$link' to \`$file'." + fi +done + +echo "Links are now set up for use with a $machine." \ + | tee config.status +exit 0 + +@ + + +1.1 +log +@Initial revision +@ +text +@d53 4 +@ diff --git a/gdb/RCS/core.c,v b/gdb/RCS/core.c,v new file mode 100644 index 0000000..f63081d --- /dev/null +++ b/gdb/RCS/core.c,v @@ -0,0 +1,651 @@ +head 1.4; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.4 +date 89.03.27.18.39.18; author gnu; state Exp; +branches ; +next 1.3; + +1.3 +date 89.02.10.01.39.45; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.02.09.23.22.33; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.09.22.49.56; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.4 +log +@Unisoft Assholes changes for user.ps. Avoid sys/fcntl.h. +@ +text +@/* Work with core dump and executable files, for GDB. + Copyright (C) 1986, 1987, 1989 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! +*/ + +#include "defs.h" +#include "param.h" +#include "gdbcore.h" + +#ifdef USG +#include +#include +#endif + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include +#endif + +#ifndef N_MAGIC +#ifdef COFF_FORMAT +#define N_MAGIC(exec) ((exec).magic) +#else +#define N_MAGIC(exec) ((exec).a_magic) +#endif +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef UNISOFT_ASSHOLES +#define PMMU +#define NEW_PMMU +#include /* Required for user.ps */ +#include /* '' */ +#include /* '' */ +#include +#define mc68881 /* Required to get float in user.ps */ +#endif + +#ifdef UMAX_CORE +#include +#else +#include +#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 +#define AOUTHDR struct exec +#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; + +/* 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; + +/* Address in executable file of start of text area data. */ + +int text_offset; + +/* Address in executable file of start of data area data. */ + +int exec_data_offset; + +/* Address in core file of start of data area data. */ + +int data_offset; + +/* Address in 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; + + fstat (corechan, &st_core); + + 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) + 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) + printf ("Core dump file \"%s\".\n", corefile); + else + printf ("No core dump file\n"); + + 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); + + 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 (have_inferior_p ()) + 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 ()) + return write_inferior_memory (memaddr, myaddr, len); + else + error ("Can write memory only when program being debugged is running."); +} + +/* 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; + + 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; + } + 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 (memaddr >= (corechan >= 0 ? data_end : exec_data_end) + && memaddr < stack_start) + { + i = min (len, stack_start - memaddr); + } + else if (memaddr >= stack_end && stack_end != 0) + { + i = min (len, - memaddr); + } + else + { + /* Address did not classify into one of the known ranges. + This could be because data_start != exec_data_start + or data_end similarly. */ + abort(); + } + + /* Now we know which file to use. + Set up its pointer and transfer the data. */ + if (xferfile) + { + if (*xferfile == 0) + if (xferfile == &execfile) + error ("No program file to examine."); + else + error ("No core dump file or running program to examine."); + val = lseek (xferchan, fileptr, 0); + if (val < 0) + perror_with_name (*xferfile); + val = myread (xferchan, myaddr, i); + if (val < 0) + perror_with_name (*xferfile); + } + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. + (FIXME we never write.) */ + else + { + bzero (myaddr, i); + returnval = 1; + } + + memaddr += i; + myaddr += i; + len -= i; + } + return returnval; +} + +/* 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."); +} + +@ + + +1.3 +log +@Fix up "info files" some more, to give more information. +Rearrange the tests in xfer_core_file to avoid dependencies +between data_start and exec_data_start, and for efficiency +and add an abort() to test correctness. (If you take out +never mind...) +@ +text +@d27 1 +a27 1 +#include +d50 10 +@ + + +1.2 +log +@Create gdbcore.h for externally visible variables; +spiff up the "info files" output to make it easier to read and more +informative. +@ +text +@d250 4 +d257 4 +a260 7 + printf ("Data segment in core file from 0x%x to 0x%x.\nStack segment in core file from 0x%x to 0x%x.\n", + data_start, data_end, stack_start, stack_end); + } + else if (execfile) + { + printf ("Data segment in executable from 0x%x to 0x%x.\n", + exec_data_start, exec_data_end); +d297 3 +a299 1 +/* Return 0 if address could be read, 1 if not. */ +d301 4 +d327 1 +d329 1 +d331 3 +a333 1 + along with the next address. */ +a334 17 + if (memaddr < text_start) + { + i = min (len, text_start - memaddr); + } + else if (memaddr >= text_end && memaddr < data_start) + { + i = min (len, data_start - memaddr); + } + else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end) + && memaddr < stack_start) + { + i = min (len, stack_start - memaddr); + } + else if (memaddr >= stack_end && stack_end != 0) + { + i = min (len, - memaddr); + } +d337 1 +a337 1 + else if (memaddr >= data_start && memaddr < data_end) +d368 25 +d411 2 +a412 1 + read zeros if reading, or do nothing if writing. */ +@ + + +1.1 +log +@Initial revision +@ +text +@d2 1 +a2 1 + Copyright (C) 1986, 1987 Free Software Foundation, Inc. +d23 1 +d35 1 +d43 1 +d231 4 +a234 1 + if (corefile == 0) +a235 2 + else + printf ("Core dump file \"%s\".\n", corefile); +d242 1 +a242 1 + printf ("Symbols loaded from \"%s\".\n", symfile); +d248 1 +a248 1 + printf ("Text segment from 0x%x to 0x%x.\n", +d253 1 +a253 1 + printf ("Data segment from 0x%x to 0x%x.\nStack segment from 0x%x to 0x%x.\n", +d256 1 +a256 1 + else +@ diff --git a/gdb/RCS/dbxread.c,v b/gdb/RCS/dbxread.c,v new file mode 100644 index 0000000..eb9d1cd --- /dev/null +++ b/gdb/RCS/dbxread.c,v @@ -0,0 +1,4610 @@ +head 1.3; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.3 +date 89.03.27.18.41.32; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.02.10.01.38.34; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.10.01.30.11; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.3 +log +@Avoid sys/fcntl.h. +@ +text +@/* Read dbx symbol tables and convert to internal format, for GDB. + Copyright (C) 1986, 1987, 1988, 1989 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! +*/ + +#include "param.h" + +#ifdef READ_DBX_FORMAT + +#ifdef USG +#include +#include +#define L_SET 0 +#define L_INCR 1 +#endif + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#include "stab.gnu.h" +#else +#include +#include +#endif + +/* + * 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__ */ + +#include +#include +#include +#include +#include +#include "defs.h" +#include "symtab.h" + +#ifndef COFF_FORMAT +#define AOUTHDR struct exec +#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 (); + +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 + +/* Macro for size of text segment */ +#ifndef SIZE_OF_TEXT_SEGMENT +#define SIZE_OF_TEXT_SEGMENT hdr.a_text +#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 + +/* 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. */ + +#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 */ + +/* 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 first_object_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; + +/* Partial symbol list for all of the global and static symbols found + in a file */ + +struct partial_symbol *global_psymbols, *static_psymbols; +int global_psymbols_allocated, static_psymbols_allocated; + +/* Position for next psymbol to be added */ + +struct partial_symbol *next_ps_global, *next_ps_static; + +/* Global variable which, when set, indicates that we are processing a + .o file compiled with gcc */ + +static unsigned char processing_gcc_compilation; + +static int +xxmalloc (n) +{ + int v = malloc (n); + if (v == 0) + abort (); + return v; +} + +/* 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]; + } +} + +/* Make sure there is a type allocated for type numbers TYPENUMS + and return the type object. + This can create an empty (zeroed) type object. */ + +static struct type * +dbx_alloc_type (typenums) + int typenums[2]; +{ + register struct type **type_addr = dbx_lookup_type (typenums); + register struct type *type = *type_addr; + + /* If we are referring to a type not known at all yet, + allocate an empty type for it. + We will fill it in later if we find out how. */ + if (type == 0) + { + type = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + bzero (type, sizeof (struct type)); + TYPE_VPTR_FIELDNO (type) = -1; + *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); + + /* Set default for compiler to pcc; assume that we aren't processing + a gcc compiled file until proved otherwise. */ + + processing_gcc_compilation = 0; +} + +/* 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); + } + + /* 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) + char *name; + CORE_ADDR address; +{ + register struct misc_bunch *new; + + 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; + 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); +} + +/* 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 (); + +/* 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) + char *name; +{ + 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; + + dont_repeat (); + + if (name == 0) + { + if ((symtab_list || partial_symtab_list) + && !query ("Discard symbol table? ", 0)) + error ("Not confirmed."); + if (symfile) + free (symfile); + symfile = 0; + free_all_symtabs (); + free_all_psymtabs (); + return; + } + + 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); + + 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); + stat (name, &statbuf); + READ_STRING_TABLE_SIZE (buffer); + if (buffer >= 0 && buffer < statbuf.st_size) + stringtab = (char *) alloca (buffer); + else + stringtab = NULL; + if (stringtab == NULL) + error ("ridiculous string table size: %d bytes", name, buffer); + + bcopy (&buffer, stringtab, sizeof buffer); + val = myread (desc, stringtab + sizeof buffer, buffer - sizeof 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); + +#ifdef READ_GDB_SYMSEGS + /* That puts us at the symsegs. Read them. */ + symseg_chain = read_symsegs (desc, name); + hash_symsegs (); + + /* Free the symtabs made by read_symsegs, but not their contents, + which have been copied into symtabs on symtab_list. */ + for (symseg = symseg_chain; symseg; symseg = symseg->next) + { + int i; + struct sourcevector *sv = (struct sourcevector *) symseg->linetable; + + for (i = 0; i < sv->length; i++) + { + int j; + struct source *source = sv->source[i]; + struct symtab *sp1 + = (struct symtab *) xxmalloc (sizeof (struct symtab)); + + bcopy (symseg, sp1, sizeof (struct symtab)); + sp1->filename = savestring (source->name, strlen (source->name)); + sp1->linetable = &source->contents; + sp1->free_code = free_nothing; + sp1->free_ptr = (i == 0) ? (char *) symseg : 0; + + sp1->next = symtab_list; + symtab_list = sp1; + } + } +#else + /* Where people are using the 4.2 ld program, must not check for + symsegs, because that ld puts randonm garbage at the end of + the output file and that would trigger an error message. */ + symseg_chain = 0; +#endif + + /* 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, NUMBER_OF_SYMBOLS, 0, 0, 0); + + /* 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_allocated = total_symbols / 10; + static_psymbols_allocated = total_symbols / 10; + next_ps_global = global_psymbols = (struct partial_symbol *) + xmalloc (global_psymbols_allocated * sizeof (struct partial_symbol)); + next_ps_static = static_psymbols = (struct partial_symbol *) + xmalloc (static_psymbols_allocated * 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(); + +/* 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. + + 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 process_symbol_for_psymtab (); + +static void +read_dbx_symtab (desc, stringtab, nlistlen, inclink, text_addr, text_size) + int desc; + register char *stringtab; + register int nlistlen; + int inclink; + unsigned text_addr; + int text_size; +{ + register char *namestring; + register struct symbol *sym, *prev; + int hash; + int num_object_files = 0; + int past_first_source_file = 0; + struct cleanup *old_chain; + int current_text_start, current_file_symbol_start; + struct pending *global_symbols, *static_symbols; + int nsl; /* Length of namestring, when needed */ + + /* 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; + + /* Setup a define to deal cleanly with the underscore problem */ + +#ifdef NAMES_HAVE_UNDERSCORE +#define HASH_OFFSET 1 +#else +#define HASH_OFFSET 0 +#endif + + global_symbols = static_symbols = + (struct pending *) 0; + 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; +#endif + + symtab_input_desc = desc; /* This is needed for fill_symbuf below */ + symbuf_end = symbuf_idx = 0; + + for (symnum = 0; symnum < nlistlen; symnum++) + { + struct nlist *bufp; + unsigned char type; + + /* 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++]; + type = bufp->n_type; + + /* + * Special cases to speed up readin. + */ + if (type == N_SLINE) continue; + + namestring = bufp->n_un.n_strx ? bufp->n_un.n_strx + stringtab : ""; + + switch (type) + { + /* + * Standard, non-debugger, symbols + */ + + case N_TEXT | N_EXT: + /* Catch etext */ + + if (!strcmp (namestring, "_etext")) + end_of_text_addr = bufp->n_value; + /* Fall through */ + +#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 + 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 */ + + last_global_sym = symnum; + if (!first_global_sym) first_global_sym = symnum; + + record_misc_function (namestring, bufp->n_value); /* Always */ + + continue; + +#ifdef N_NBTEXT + case N_NBTEXT: +#endif + case N_TEXT: + if (!strcmp (namestring + strlen (namestring) - 2, ".o") + || !strncmp (namestring, "-l", 2)) + { + if (num_object_files++ == 1) + first_object_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, + next_ps_global, next_ps_static); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } + else + past_first_source_file = 1; + } + continue; + + case N_UNDF: + case N_UNDF | N_EXT: + case N_ABS: + case N_DATA: + case N_BSS: +#ifdef N_NBDATA + case N_NBDATA: +#endif +#ifdef N_NBBSS + case N_NBBSS: +#endif + case N_FN: + /* 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: + case N_SETV | N_EXT: +#endif + continue; + + /* + * Debugger symbols + */ + + case N_SO: + /* End the current partial symtab and start a new one */ + + 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, + next_ps_global, next_ps_static); + 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), + next_ps_global, next_ps_static); + + 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 */ + add_bincl_to_list (pst, namestring, bufp->n_value); + + /* Fall through */ +#endif + + case N_SOL: + /* 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 *)); +#ifdef DEBUG_INFO + fprintf (stderr, "Had to realloc includes. New size: %d\n", + includes_allocated); +#endif + } + continue; + + case N_FUN: + case N_SSYM: + case N_GSYM: + case N_LSYM: + case N_STSYM: + case N_LCSYM: + case N_ENTRY: +#ifdef N_MAIN + case N_MAIN: +#endif +#ifdef N_BSLINE + case N_BSLINE: +#endif + case N_PC: +#ifdef N_M2C + case N_M2C: + case N_SCOPE: +#endif + /* Process a symbol as appropriate for the type (this + information is contained in the name of the symbol) */ + + if (namestring[0] != '\0') +#if 1 + process_symbol_for_psymtab (namestring); +#else + process_symbol_for_psymtab (namestring, tmp_symchain); +#endif + continue; + +#ifdef N_BINCL + case N_EXCL: + /* 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 + 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 (type)) + continue; + + fatal ("Bad symbol type 0x%x encountered in gdb scan", type); + } + } + + if (last_source_file) + { + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * sizeof (struct nlist), end_of_text_addr, + dependency_list, dependencies_used, + next_ps_global, next_ps_static); + includes_used = 0; + dependencies_used = 0; + pst = (struct partial_symtab *) 0; + } + + free_bincl_list (); + discard_cleanups (old_chain); +} + +/* + * Take a single symbol (name: NAME) and process it (add it to the + * app psymbol list or not). + */ +static void +process_symbol_for_psymtab (name) + char *name; +{ + char *p = (char *) index(name, ':') + 1; + int deftype; + struct partial_symbol *sym; + enum { T_IGNORE, T_STATIC, T_GLOBAL } symbol_type; + enum namespace ns = UNDEF_NAMESPACE; + enum address_class class; + int hash; + + if (p == (char *) 0x1) + /* No ":" ; I guess it's not a debuggging symbol */ + return; + + if ((*p >= '0' && *p <= '9') || *p == '(') + deftype = 'l'; + else + deftype = *p; + + /* Figure out how to handle this symbol */ + switch (deftype) + { + /* T is a struct/union/enum, t is a typedef */ + case 'T': + symbol_type = T_STATIC; + ns = STRUCT_NAMESPACE; + class = LOC_TYPEDEF; + break; + case 't': + symbol_type = T_STATIC; + ns = VAR_NAMESPACE; + class = LOC_TYPEDEF; + break; + case 'c': + symbol_type = T_STATIC; + ns = VAR_NAMESPACE; + class = LOC_CONST; + break; + case 'S': + symbol_type = T_STATIC; + ns = VAR_NAMESPACE; + class = LOC_STATIC; + break; + case 'f': + symbol_type = T_STATIC; + ns = VAR_NAMESPACE; + class = LOC_BLOCK; + break; + case 'F': + symbol_type = T_GLOBAL; + ns = VAR_NAMESPACE; + class = LOC_BLOCK; + break; + case 'G': + symbol_type = T_GLOBAL; + ns = VAR_NAMESPACE; + class = LOC_STATIC; + break; + default: + return; + } + + /* Create the symbol and store it on the list */ + /* There's a better algorithm possible for the allocation; figure + out how far through the symbol table we are and do a reestimate */ + if (symbol_type == T_STATIC) + { + if (next_ps_static >= static_psymbols + static_psymbols_allocated) + { + static_psymbols = (struct partial_symbol *) + xrealloc (static_psymbols, + (static_psymbols_allocated * 2 + * sizeof (struct partial_symbol))); + /* Next assumes we only went one over. Should be good if + program works correctly */ + next_ps_static = static_psymbols + static_psymbols_allocated; + static_psymbols_allocated *= 2; +#ifdef DEBUGINFO + fprintf(stderr, "debuginfo: Had to realloc statics\n"); +#endif + } + sym = next_ps_static++; + } + else + { + if (next_ps_global >= global_psymbols + global_psymbols_allocated) + { + global_psymbols = (struct partial_symbol *) + xrealloc (global_psymbols, + (global_psymbols_allocated * 2 + * sizeof (struct partial_symbol))); + next_ps_global = global_psymbols + global_psymbols_allocated; + global_psymbols_allocated *= 2; +#ifdef DEBUGINFO + fprintf(stderr, "debuginfo: Had to realloc globals\n"); +#endif + } + sym = next_ps_global++; + } + + SYMBOL_NAME(sym) = (char *) obstack_alloc (psymbol_obstack, + p - name); + strncpy(SYMBOL_NAME(sym), name, p - name - 1); + SYMBOL_NAME(sym)[p - name - 1] = '\0'; + SYMBOL_NAMESPACE(sym) = ns; + SYMBOL_CLASS(sym) = class; +} +#undef HASH_OFFSET + +/* + * 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; + result->statics_offset = static_syms - static_psymbols; + + result->n_global_syms = 0; + result->n_static_syms = 0; + + return result; +} + +static int +compare_psymbols (s1, s2) + register struct partial_symbol *s1, *s2; +{ + register char + *st1 = SYMBOL_NAME (s1), + *st2 = SYMBOL_NAME (s2); + + return (st1[0] - st2[0] ? st1[0] - st2[0] : + strcmp (st1 + 1, st2 + 1)); +} + + +/* Close off the current usage of a partial_symbol table entry. This + involves setting the correct number of includes (with a realloc), + setting the high text mark, setting the symbol length in the + executable, and setting the length of the global and static lists + of psymbols. + + The global symbols and static symbols are then seperately sorted. + + Then the partial symtab is put on the global list. + *** List variables and peculiarities of same. *** + */ +static void +end_psymtab (pst, include_list, num_includes, capping_symbol_offset, + capping_text, dependency_list, number_dependencies, + capping_global, capping_static) + struct partial_symtab *pst; + char **include_list; + int num_includes; + int capping_symbol_offset; + int capping_text; + struct partial_symtab **dependency_list; + int number_dependencies; + struct partial_symbol *capping_global, *capping_static; +{ + int i; + + pst->ldsymlen = capping_symbol_offset - pst->ldsymoff; + pst->texthigh = capping_text; + + pst->n_global_syms = + capping_global - (global_psymbols + pst->globals_offset); + pst->n_static_syms = + capping_static - (static_psymbols + 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; + } + + /* Sort the global list; don't sort the static list */ + qsort (global_psymbols + pst->globals_offset, pst->n_global_syms, + sizeof (struct partial_symbol), compare_psymbols); + + /* Put the psymtab on the psymtab list */ + pst->next = partial_symtab_list; + partial_symtab_list = pst; +} + +/* + * 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. + */ +static void scan_file_globals (); +static void read_ofile_symtab (); + +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"); + + /* 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) + psymtab_to_symtab (pst->dependencies[i]); + + if (pst->ldsymlen) /* Otherwise it's a dummy */ + { + /* Open symbol file and read in string table */ + stat (name, &statbuf); + 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); + + /* Read in the string table */ + lseek (desc, STRING_TABLE_OFFSET, L_SET); + READ_STRING_TABLE_SIZE (stsize); + if (stsize >= 0 && stsize < statbuf.st_size) + stringtab = (char *) alloca (stsize); + else + stringtab = NULL; + if (stringtab == NULL) + error ("ridiculous string table size: %d bytes", name, stsize); + + bcopy (&stsize, stringtab, sizeof stsize); + val = myread (desc, stringtab + sizeof stsize, stsize - sizeof stsize); + if (val < 0) + perror_with_name (name); + + /* Init stuff necessary for reading in symbols */ + free_pendings = 0; + pending_blocks = 0; + file_symbols = 0; + global_symbols = 0; + make_cleanup (really_free_pendings, 0); + + /* Read in this files symbols */ + lseek (desc, SYMBOL_TABLE_OFFSET, L_SET); + read_ofile_symtab (desc, stringtab, pst->ldsymoff, + pst->ldsymlen, pst->textlow, + pst->texthigh - pst->textlow, 0); + sort_symtab_syms (symtab_list); /* At beginning since just added */ + + /* Match with global symbols */ + lseek (desc, SYMBOL_TABLE_OFFSET, L_SET); + scan_file_globals (desc, stringtab, + first_global_sym * sizeof(struct nlist), + last_global_sym - first_global_sym + 1); + + do_cleanups (old_chain); + } + + /* Find pst in list, prune it, and free it's storage */ + for (list_patch = &partial_symtab_list; + *list_patch && *list_patch != pst; + list_patch = &((*list_patch)->next)) + ; + + if (!(*list_patch)) /* pst not in list. Don't worry about it? */ + fatal ("internal: psymtab_to_symtab called with non-listed pst"); + + *list_patch = (*list_patch)->next; /* Prune */ + + pst->readin = 1; /* Mark as read in */ + + /* It's the last one if we actually read something in */ + if (pst->ldsymlen) + return symtab_list; + else + /* 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. + * + * DESC is the file descriptor of the symbol file, with the seek + * pointer pointing at the beginning of the symbol table. + * STRINGTAB is the file's string table, already read in. + * OFFSET is the offset (in bytes) of the beginning of the global + * symbols from the beginning of the symbol table. + * NUMSYMS is the number of symbols that have to be checked. + */ +static void +scan_file_globals (desc, stringtab, offset, numsyms) + int desc; + char *stringtab; + int offset; + int numsyms; +{ + int hash; + + lseek(desc, offset, L_INCR); + symtab_input_desc = desc; + symbuf_end = symbuf_idx = 0; + + for (symnum = 0; symnum < numsyms; symnum++) + { + struct nlist *bufp; + unsigned char type; + char *namestring; + + QUIT; + if (symbuf_idx == symbuf_end) + fill_symbuf (); + + bufp = &symbuf[symbuf_idx++]; + type = bufp->n_type; + + if (type & N_EXT && type != N_EXT) + { + struct symbol *sym, *prev; + + namestring = bufp->n_un.n_strx ? + bufp->n_un.n_strx + stringtab : ""; + prev = (struct symbol *) 0; + + /* Get the hash index and check all the symbols + under that hash index. */ + +#ifdef NAMES_HAVE_UNDERSCORE + hash = hashname (namestring + 1); +#else /* ! NAMES_HAVE_UNDERSCORE */ + hash = hashname (namestring); +#endif /* ! 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 */ + ) + { + /* 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); + SYMBOL_VALUE (sym) = bufp->n_value; + if (prev) + sym = (struct symbol *) SYMBOL_VALUE (prev); + else + sym = global_sym_chain[hash]; + break; /* Only one reference per file */ + } + else + { + prev = sym; + sym = (struct symbol *) SYMBOL_VALUE (sym); + } + } + } + } + /* There shouldn't be anything left on the hash list at this point. + If there is, we have done something wrong. For right now it's + worth checking, until I get the bugs out. */ + /* Sigh. Unfortunately, the above is not true. If an extern + variable is mentioned in an include file (or a program) and the + variable is never either referenced or defined, there will be a + debugger symbol with no "real" symbol. Oh well. */ +} + +/* + * 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, 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; + lseek(desc, sym_offset, L_INCR); + + 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; + + namestring = bufp->n_un.n_strx ? 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)) + 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; + + /* 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, and all symbols on the Convex. */ + 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. */ + + 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_RBRAC. */ + new = &context_stack[--context_stack_depth]; + if (desc != new->depth) + error ("Invalid symbol data: N_LBRAC/N_RBRAC symbol mismatch, symtab pos %d.", symnum); + 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. */ + if (local_symbols && context_stack_depth > 1) + { + /* 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); + } + break; + + case N_FN: + /* 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. */ + 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: + case N_ECOMM: + 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; + int num_object_files = 0; + +#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 ? 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")) + || ! strcmp (namestring, "-l", 2)) + { + if (num_object_files++ == 1) + first_object_file_end = bufp->n_value; + 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; + + /* 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); + 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); + } + } + + 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"); + + 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); + make_cleanup (free_current_contents, &name); + + 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); + stat (name, &statbuf); + READ_STRING_TABLE_SIZE (buffer); + if (buffer >= 0 && buffer < statbuf.st_size) + stringtab = (char *) alloca (buffer); + else + stringtab = NULL; + if (stringtab == NULL) + error ("ridiculous string table size: %d bytes", name, buffer); + + bcopy (&buffer, stringtab, sizeof buffer); + val = myread (desc, stringtab + sizeof buffer, buffer - sizeof buffer); + if (val < 0) + perror_with_name (name); + +#ifdef READ_GDB_SYMSEGS + /* That puts us at the symsegs. Read them. */ + symseg_chain = read_symsegs (desc, name); + hash_symsegs (); + + /* Free the symtabs made by read_symsegs, but not their contents, + which have been copied into symtabs on symtab_list. */ + for (symseg = symseg_chain; symseg; symseg = symseg->next) + { + int i; + struct sourcevector *sv = (struct sourcevector *) symseg->linetable; + + for (i = 0; i < sv->length; i++) + { + int j; + struct source *source = sv->source[i]; + struct symtab *sp1 + = (struct symtab *) xxmalloc (sizeof (struct symtab)); + + bcopy (symseg, sp1, sizeof (struct symtab)); + sp1->filename = savestring (source->name, strlen (source->name)); + sp1->linetable = &source->contents; + sp1->free_code = free_nothing; + sp1->free_ptr = (i == 0) ? (char *) symseg : 0; + + sp1->next = symtab_list; + symtab_list = sp1; + } + } +#else + /* Where people are using the 4.2 ld program, must not check for + symsegs, because that ld puts randonm garbage at the end of + the output file and that would trigger an error message. */ + symseg_chain = 0; +#endif + + /* 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; + + /* Make a default for file to list. */ + /* Hmmm. I'd say we don't want this in add_file_command, but . . . */ + + select_source_symtab (symtab_list); + + 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); +} + +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; + + 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. */ + 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; + } + break; + case 'i': + { + SYMBOL_TYPE (sym) = builtin_type_int; + SYMBOL_VALUE (sym) = atoi (p); + SYMBOL_CLASS (sym) = LOC_CONST_BYTES; + } + 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); + /* DESC == 0 implies compiled with GCC. + In this case, if it says `short', believe it. */ + if (desc == 0) + break; + /* 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; + + case 'P': + SYMBOL_CLASS (sym) = LOC_REGPARM; + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'r': + SYMBOL_CLASS (sym) = LOC_REGISTER; + SYMBOL_VALUE (sym) = 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': + 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; + + default: + error ("Invalid symbol data: unknown symbol-type code `%c' at symtab pos %d.", deftype, symnum); + } + return sym; +} + +/* 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); + } +} + +/* 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]; + + 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; + switch ((*pp)[-1]) + { + case 'x': + type = dbx_alloc_type (typenums); + /* Set the type code according to the following letter. */ + switch ((*pp)[0]) + { + case 's': + TYPE_CODE (type) = TYPE_CODE_STRUCT; + break; + case 'u': + TYPE_CODE (type) = TYPE_CODE_UNION; + break; + case 'e': + TYPE_CODE (type) = TYPE_CODE_ENUM; + break; + } + /* Skip the name the cross-ref points to. */ + /* 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.) */ + *pp = (char *) index (*pp, ','); + /* Just allocate the type and leave it zero if nothing known */ + return dbx_alloc_type (typenums); + + 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; + *dbx_lookup_type (typenums) = type; + break; + + case '*': + type1 = read_type (pp); + if (TYPE_POINTER_TYPE (type1)) + { + type = TYPE_POINTER_TYPE (type1); + *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 '&': + type1 = read_type (pp); + if (TYPE_REFERENCE_TYPE (type1)) + { + type = TYPE_REFERENCE_TYPE (type1); + *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); + *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); + *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; + +#if 0 + /* Format of an array type: + "ar;lower;upper;". Put code + in to handle this. */ + + /* dbx expresses array types in terms of a range type for the index, + and that range type is specified right inside the array type spec + making ar1;MIN;MAX;VALTYPE */ + if (!strncmp (*pp, "r1;0;", 5)) + (*pp) += 5; + else if (!strncmp (*pp, "r(0,1);0;", 9)) + (*pp) += 9; + else break; + + TYPE_CODE (type) = TYPE_CODE_ARRAY; + /* In Fortran, an upper bound may be T... meaning a parameter specifies + the length of the data. In this case, just pretend the bound is 1. + This happens only for array parameters, which are really passed + as pointers anyway, and we will translate them into such. */ + if (**pp == 'T') + { + n = 1; + while (**pp != ';') + (*pp)++; + } + else + n = read_number (pp, ';') + 1; + TYPE_TARGET_TYPE (type) = read_type (pp); + TYPE_LENGTH (type) = TYPE_LENGTH (TYPE_TARGET_TYPE (type)) * n; + break; +#endif + + 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; + struct type *baseclass = NULL; + int read_possible_virtual_info = 0; + + 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, 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 = read_number (pp, ','); + baseclass = read_type (pp); + *pp += 1; /* skip trailing ';' */ + baseclass_vec[i] = lookup_basetype_type (baseclass, offset, via_virtual, via_public); + + /* 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). */ + + 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; + + /* Read the data. */ + 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, ';'); + /* 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[32] = "operator "; + char *o = opname + 9; + + /* 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); + new_sublist->fn_field.args = read_args (pp, ':'); + 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 (); + + if (*(*pp)++ == '*') + new_sublist->fn_field.voffset = read_number (pp, ';') + 1; + else + new_sublist->fn_field.voffset = 0; + + 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; + if (baseclass) + TYPE_NFN_FIELDS_TOTAL (type) += TYPE_NFN_FIELDS_TOTAL (baseclass); + + 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 enumberation 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; + + /* Format of an array type: + "ar;lower;upper;". Put code in + to handle this. */ + + index_type = read_type (pp); + if (*(*pp)++ != ';') + error ("Invalid symbol data; improper format of array type decl."); + lower = read_number (pp, ';'); + upper = read_number (pp, ';'); + element_type = read_type (pp); + + { + /* 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 instead of a NAME means the end. */ + while (**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++; + } + + (*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. */ + + for (syms = *symlist, n = nsyms; 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 */ + 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; + } + 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); +} + +void +_initialize_dbxread () +{ + symfile = 0; + header_files = (struct header_file *) 0; + this_object_header_files = (int *) 0; + + 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 */ +@ + + +1.2 +log +@If discarding the symbol table, discard its name too, so "info files" +will give the right answer. +@ +text +@d27 1 +a27 1 +#include +@ + + +1.1 +log +@Initial revision +@ +text +@d2 1 +a2 1 + Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc. +d1457 3 +@ diff --git a/gdb/RCS/default-dep.c,v b/gdb/RCS/default-dep.c,v new file mode 100644 index 0000000..81c18f3 --- /dev/null +++ b/gdb/RCS/default-dep.c,v @@ -0,0 +1,731 @@ +head 1.4; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.4 +date 89.03.27.20.08.50; author gnu; state Exp; +branches ; +next 1.3; + +1.3 +date 89.03.27.20.07.47; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.03.27.18.49.06; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.20.19.47.11; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.4 +log +@Restore A/UX-specific changes. +@ +text +@/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include +#endif + +#ifdef UNISOFT_ASSHOLES +#define PMMU +#define NEW_PMMU +#define mc68881 /* Needed to get float in user.h!!! */ +#include /* For user.h */ +#include +#include +/* Things Unisoft defined differently from every other Unix system */ +#define NBPG PAGESIZE +#define UPAGES USIZE +#define KERNEL_U_ADDR UDOT +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include +#endif +#ifndef N_SET_MAGIC +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif + +#include /* After a.out.h */ +#include +#include + +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. + + If you are having trouble debugging ptrace calls, turn on DEBUG + and every call to ptrace, in this module or elsewhere, will be + logged to stderr. */ +int +call_ptrace (request, pid, arg3, arg4) + int request, pid, arg3, arg4; +{ +#ifdef DEBUG + int result; + + fprintf(stderr, "ptrace(%x,,%x, %x) = ", request, arg3, arg4); + result=ptrace (request, pid, arg3, arg4); + fprintf(stderr, "%x\n", result); + return result; + +#define ptrace call_ptrace + +#else + return ptrace (request, pid, arg3, arg4); +#endif +} + +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; +#ifdef UNISOFT_ASSHOLES + /* You can't write the PC with ptrace 6, only with ptrace 11! */ + if (regno == PC_REGNUM) + ptrace(11, inferior_pid, 16, read_register(regno)); + else +#endif + 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; +#ifdef UNISOFT_ASSHOLES + if (regno == PC_REGNUM) + ptrace(11, inferior_pid, 16, read_register(regno)); + else +#endif + 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 (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. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#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; + +#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) + { + 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 ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* Some machines put an absolute address in here; Unisoft + seems to put the offset in the upage of the regs. Sigh. */ + 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) + perror_with_name (reg_names[regno]); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (reg_names[regno]); + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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); +} +@ + + +1.3 +log +@Remove A/UX-specific changes for shipping to FSF. +@ +text +@d30 13 +d176 7 +a182 1 + ptrace (6, inferior_pid, regaddr, read_register (regno)); +d193 6 +a198 1 + ptrace (6, inferior_pid, regaddr, read_register (regno)); +@ + + +1.2 +log +@A/UX and USG changes, and a little better error reporting. +@ +text +@a29 13 +#ifdef UNISOFT_ASSHOLES +#define PMMU +#define NEW_PMMU +#define mc68881 /* Needed to get float in user.h!!! */ +#include /* For user.h */ +#include +#include +/* Things Unisoft defined differently from every other Unix system */ +#define NBPG PAGESIZE +#define UPAGES USIZE +#define KERNEL_U_ADDR UDOT +#endif + +d163 1 +a163 7 +#ifdef UNISOFT_ASSHOLES + /* You can't write the PC with ptrace 6, only with ptrace 11! */ + if (regno == PC_REGNUM) + ptrace(11, inferior_pid, 16, read_register(regno)); + else +#endif + ptrace (6, inferior_pid, regaddr, read_register (regno)); +d174 1 +a174 6 +#ifdef UNISOFT_ASSHOLES + if (regno == PC_REGNUM) + ptrace(11, inferior_pid, 16, read_register(regno)); + else +#endif + ptrace (6, inferior_pid, regaddr, read_register (regno)); +@ + + +1.1 +log +@Initial revision +@ +text +@d30 13 +a46 1 +#include +d58 2 +d67 5 +a71 1 + machine-dependent file. */ +d76 11 +d88 1 +d176 7 +a182 1 + ptrace (6, inferior_pid, regaddr, read_register (regno)); +d193 6 +a198 1 + ptrace (6, inferior_pid, regaddr, read_register (regno)); +d201 1 +a201 1 + sprintf (buf, "writing register number %d", regno); +d446 3 +a448 1 + perror_with_name (filename); +d455 6 +a460 1 + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; +d478 1 +a478 1 + perror_with_name (filename); +d482 1 +a482 1 + perror_with_name (filename); +@ diff --git a/gdb/RCS/findvar.c,v b/gdb/RCS/findvar.c,v new file mode 100644 index 0000000..9095f2b --- /dev/null +++ b/gdb/RCS/findvar.c,v @@ -0,0 +1,584 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.04.26.01.06.46; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.04.25.15.38.48; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@use XXX_BIG_ENDIAN macros rather than runtime tests. +@ +text +@/* Find a variable's value in memory, for GDB, the GNU debugger. + Copyright (C) 1986, 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! +*/ + +#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 dissapears 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. */ + + if (REGISTER_IN_WINDOW_P(regnum)) + { + fi = get_frame_info (frame); + 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 address, 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; + + case LOC_ARG: + fi = get_frame_info (frame); + addr = val + FRAME_ARGS_ADDRESS (fi); + 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: + v = value_from_register (type, val, frame); + 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 address, + 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); + + 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_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; + } + + return value_cast (lookup_pointer_type (type), + value_from_long (builtin_type_long, (LONGEST) addr)); +} + +@ + + +1.1 +log +@Initial revision +@ +text +@d448 2 +a449 5 + union { int i; char c; } test; + /* If we want less than the full size, we need to + test for a big-endian or little-endian machine. */ + test.i = 1; + if (test.c != 1 && len < REGISTER_RAW_SIZE (regnum)) +d454 2 +a455 1 + +a490 1 + union { int i; char c; } test; +d492 2 +a493 4 + /* If var is less than the full size of register, we need to + test for a big-endian or little-endian machine. */ + test.i = 1; + if (test.c != 1 && len < REGISTER_RAW_SIZE (val)) +d496 1 +@ diff --git a/gdb/RCS/gdb.texinfo,v b/gdb/RCS/gdb.texinfo,v new file mode 100644 index 0000000..ff38f18 --- /dev/null +++ b/gdb/RCS/gdb.texinfo,v @@ -0,0 +1,3009 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @@; + + +1.2 +date 89.02.10.01.41.38; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.10.00.33.03; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Improve doc in various ways, mostly xref{Expressions} so you can +find out what an expression is (I had trouble finding it, since +it's in a nested menu somewhere.) +@ +text +@\input texinfo +@@setfilename ../info/gdb +@@settitle GDB, The GNU Debugger +@@ifinfo +This file documents the GNU debugger GDB. + +Copyright (C) 1988 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Distribution'' and ``GDB General Public License'' are +included exactly as in the original, and provided that the entire resulting +derived work is distributed under the terms of a permission notice +identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that the sections entitled ``Distribution'' and ``GDB General Public +License'' may be included in a translation approved by the author instead +of in the original English. +@@end ifinfo + +@@setchapternewpage odd +@@settitle GDB Manual +@@titlepage +@@sp 6 +@@center @@titlefont{GDB Manual} +@@sp 1 +@@center The GNU Source-Level Debugger +@@sp 4 +@@center Third Edition, GDB version 3.1 +@@sp 1 +@@center January 1989 +@@sp 5 +@@center Richard M. Stallman +@@page +@@vskip 0pt plus 1filll +Copyright @@copyright{} 1988, 1989 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Distribution'' and ``GDB General Public License'' are +included exactly as in the original, and provided that the entire resulting +derived work is distributed under the terms of a permission notice +identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that the sections entitled ``Distribution'' and ``GDB General Public +License'' may be included in a translation approved by the author instead +of in the original English. +@@end titlepage +@@page + +@@node Top, Commands,, (DIR) +@@unnumbered Summary of GDB + +The purpose of a debugger such as GDB is to allow you to execute another +program while examining what is going on inside it. We call the other +program ``your program'' or ``the program being debugged''. + +GDB can do four kinds of things (plus other things in support of these): + +@@enumerate +@@item +Start the program, specifying anything that might affect its behavior. + +@@item +Make the program stop on specified conditions. + +@@item +Examine what has happened, when the program has stopped, so that you +can see bugs happen. + +@@item +Change things in the program, so you can correct the effects of one bug +and go on to learn about another without having to recompile first. +@@end enumerate + +GDB can be used to debug programs written in C and C++. Pascal support +is being implemented, and Fortran support will be added when a GNU +Fortran compiler is written. + +@@menu +* License:: The GDB General Public License gives you permission + to redistribute GDB on certain terms; and also + explains that there is no warranty. +* Input:: GDB command syntax and input conventions. +* Files:: Specifying files for GDB to operate on. +* Options:: GDB arguments and options. +* Compilation::Compiling your program so you can debug it. +* Running:: Running your program under GDB. +* Stopping:: Making your program stop. Why it may stop. What to do then. +* Stack:: Examining your program's stack. +* Source:: Examining your program's source files. +* Data:: Examining data in your program. +* Symbols:: Examining the debugger's symbol table. +* Altering:: Altering things in your program. +* Sequences:: Canned command sequences for repeated use. +* Emacs:: Using GDB through GNU Emacs. +* Remote:: Remote kernel debugging across a serial line. +* Commands:: Index of GDB commands. +* Concepts:: Index of GDB concepts. +@@end menu + +@@node License, Input, Top, Top +@@unnumbered GDB General Public License +@@center (Clarified 11 Feb 1988) + + The license agreements of most software companies keep you at the mercy +of those companies. By contrast, our general public license is intended to +give everyone the right to share GDB. To make sure that you get the rights +we want you to have, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. Hence this +license agreement. + + Specifically, we want to make sure that you have the right to give away +copies of GDB, that you receive source code or else can get it if you want +it, that you can change GDB or use pieces of it in new free programs, and +that you know you can do these things. + + To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute copies +of GDB, 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. + + Also, for our own protection, we must make certain that everyone finds +out that there is no warranty for GDB. If GDB is modified by someone else +and passed on, we want its recipients to know that what they have is not +what we distributed, so that any problems introduced by others will not +reflect on our reputation. + + Therefore we (Richard Stallman and the Free Software Foundation, +Inc.) make the following terms which say what you must do to be +allowed to distribute or change GDB. + +@@unnumberedsec Copying Policies + +@@enumerate +@@item +You may copy and distribute verbatim copies of GDB source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each file a valid copyright notice ``Copyright +@@copyright{} 1988 Free Software Foundation, Inc.'' (or with whatever year +is appropriate); keep intact the notices on all files that +refer to this License Agreement and to the absence of any warranty; and +give any other recipients of the GDB program a copy of this License +Agreement along with the program. You may charge a distribution fee +for the physical act of transferring a copy. + +@@item +You may modify your copy or copies of GDB source code 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: + +@@itemize @@bullet +@@item +cause the modified files to carry prominent notices stating +that you changed the files and the date of any change; and + +@@item +cause the whole of any work that you distribute or publish, that +in whole or in part contains or is a derivative of GDB or any +part thereof, to be licensed at no charge to all third parties on +terms identical to those contained in this License Agreement +(except that you may choose to grant more extensive warranty +protection to some or all third parties, at your option). + +@@item +if the modified program serves as a debugger, cause it, when +started running in the simplest and usual way, to print an +announcement including a valid copyright notice ``Copyright +@@copyright{} 1988 Free Software Foundation, Inc.'' (or with the +year that is appropriate), saying 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 License Agreement. + +@@item +You may charge a distribution fee for the physical act of +transferring a copy, and you may at your option offer warranty +protection in exchange for a fee. +@@end itemize + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + +@@item +You may copy and distribute GDB (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: + +@@itemize @@bullet +@@item +accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of +Paragraphs 1 and 2 above; or, + +@@item +accompany it with a written offer, valid for at least three +years, to give any third party free (except for a nominal +shipping charge) a complete machine-readable copy of the +corresponding source code, to be distributed under the terms of +Paragraphs 1 and 2 above; or, + +@@item +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.) +@@end itemize + +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. + +@@item +You may not copy, sublicense, distribute or transfer GDB except as +expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer GDB is void and +your rights to use GDB under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full +compliance. + +@@item +If you wish to incorporate parts of GDB into other free programs whose +distribution conditions are different, write to the Free Software +Foundation. We have not yet worked out a simple rule that can be +stated here, but we will often permit this. We will be guided by the +two goals of preserving the free status of all derivatives our free +software and of promoting the sharing and reuse of software. +@@end enumerate + +@@iftex +@@vfil +@@eject +@@end iftex +@@unnumberedsec NO WARRANTY + + BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, THE FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB ``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 GDB +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY +SERVICING, REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL FREE SOFTWARE +FOUNDATION, INC., RICHARD M. STALLMAN, AND/OR ANY OTHER PARTY WHO MAY +MODIFY AND REDISTRIBUTE GDB AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY +FREE SOFTWARE FOUNDATION, INC.) THE PROGRAM, EVEN IF YOU HAVE BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY +OTHER PARTY. + +@@node Input, Files, License, Top +@@chapter GDB Input Conventions + +GDB is invoked with the shell command @@samp{gdb}. Once started, it reads +commands from the terminal until you tell it to exit. + +A GDB command is a single line of input. There is no limit on how long +it can be. It starts with a command name, which is followed by arguments +whose meaning depends on the command name. Some command names do not +allow arguments. + +GDB command names may always be abbreviated if the abbreviation is +unambiguous. Sometimes even ambiguous abbreviations are allowed; for +example, @@samp{s} is specially defined as equivalent to @@samp{step} +even though there are other commands whose names start with @@samp{s}. +Possible command abbreviations are often stated in the documentation +of the individual commands. + +A blank line as input to GDB means to repeat the previous command verbatim. +Certain commands do not allow themselves to be repeated this way; these are +commands for which unintentional repetition might cause trouble and which +you are unlikely to want to repeat. Certain others (@@samp{list} and +@@samp{x}) act differently when repeated because that is more useful. + +A line of input starting with @@samp{#} is a comment; it does nothing. +This is useful mainly in command files (@@xref{Command Files}). + +Occasionally it is useful to execute a shell command from within gdb. +This can be done with the @@samp{shell} command, or the shell escape +character @@samp{!}. + +@@table @@code +@@item shell @@var{shell command string} +@@kindex shell +@@item !@@var{shell command string} +@@kindex ! +@@cindex shell escape +Directs GDB to invoke an inferior shell to execute @@samp{shell command string}. +The environmental variable @@samp{SHELL} is used if it exists, otherwise gdb +uses @@samp{/bin/sh}. +@@end table + +GDB @@dfn{prompts} for commands with a string that is normally @@samp{(gdb)}. +When debugging GDB with GDB, it is useful to change the prompt in one of +the GDBs so that you can distinguish them. This can be done with the +@@samp{set prompt} command. + +@@table @@code +@@item set prompt @@var{newprompt} +@@kindex set prompt +Directs GDB to use @@var{newprompt} as its prompt string henceforth. +@@end table + +@@cindex exiting GDB +@@kindex quit +To exit GDB, use the @@samp{quit} command (abbreviated @@samp{q}). +@@kbd{Ctrl-c} will not exit from GDB, but rather will terminate the action +of any GDB command that is in progress and return to GDB command level. +It is safe to type @@kbd{Ctrl-c} at any time because GDB does not allow +it to take effect until a time when it is safe. + +@@node Files, Options, Input, Top +@@chapter Specifying GDB's Files + +@@cindex core dump file +@@cindex executable file +@@cindex symbol table +GDB needs to know the filename of the program to be debugged. To debug a +core dump of a previous run, GDB must be told the filename of the core +dump. + +@@menu +* Arguments: File Arguments. Specifying files with arguments + (when you start GDB). +* Commands: File Commands. Specifying files with GDB commands. +@@end menu + +@@node File Arguments, File Commands, Files, Files +@@section Specifying Files with Arguments + +The usual way to specify the executable and core dump file names is with +two command arguments given when you start GDB. The first argument is used +as the file for execution and symbols, and the second argument (if any) is +used as the core dump file name. Thus, + +@@example +gdb progm core +@@end example + +@@noindent +specifies @@file{progm} as the executable program and @@file{core} as a core +dump file to examine. (You do not need to have a core dump file if what +you plan to do is debug the program interactively.) + +@@xref{Options}, for full information on command options and arguments for +GDB. + +@@node File Commands,, File Arguments, Files +@@section Specifying Files with Commands + +Usually you specify the files for GDB to work with by giving arguments when +you invoke GDB. But occasionally it is necessary to change to a different +file during a GDB session. Or you may run GDB and forget to specify the +files you want to use. In these situations the GDB commands to specify new +files are useful. + +@@table @@code +@@item exec-file @@var{filename} +@@kindex exec-file +Specify that the program to be run is found in @@var{filename}. If you +do not specify a directory and the file is not found in GDB's working +directory, GDB will use the environment variable @@samp{PATH} as a list +of directories to search, just as the shell does when looking for a +program to run. + +@@item symbol-file @@var{filename} +@@kindex symbol-file +Read symbol table information from file @@var{filename}. @@samp{PATH} +is searched when necessary. Most of the time you will use both the +@@samp{exec-file} and @@samp{symbol-file} commands on the same file. + +@@samp{symbol-file} with no argument clears out GDB's symbol table. + +@@item core-file @@var{filename} +@@kindex core-file +Specify the whereabouts of a core dump file to be used as the +``contents of memory''. Note that the core dump contains only the +writable parts of memory; the read-only parts must come from the +executable file. + +@@samp{core-file} with no argument specifies that no core file is +to be used. + +@@item add-file @@var{filename} @@var{address} +@@kindex add-file +The @@samp{add-file} command takes two arguments, a file name, and the +address at which that file has been (or should be) dynamically loaded. +GDB will then treat that file as though it had always been dynamically +linked, and provide the user with all the normal GDB features, including +symbolic debugging. + +With the @@samp{add-file} command, it is possible to debug code which was +not present in the initial load image of the program under test. +Suppose you have a program which can, while running, dynamically link a +program fragment into its address space. One program which does this is +KCL, a free common lisp implementation. The fragment will be loaded +into the main program's address space at some address, and the main +program can then call functions within the fragment by calculating (or +otherwise obtaining) their addresses. + +@@item kill +@@kindex kill +Cancel running the program under GDB. This could be used if you wish +to debug a core dump instead. GDB ignores any core dump file if it is +actually running the program, so the @@samp{kill} command is the only +sure way to go back to using the core dump file. + +@@item info files +@@kindex info files +Print the names of the executable and core dump files currently in +use by GDB, and the file from which symbols were loaded. +@@end table + +While all three file-specifying commands allow both absolute and relative +file names as arguments, GDB always converts the file name to an absolute +one and remembers it that way. + +The @@samp{symbol-file} command causes GDB to forget the contents of its +convenience variables, the value history, and all breakpoints and +auto-display expressions. This is because they may contain pointers to the +internal data recording symbols and data types, which are part of the old +symbol table data being discarded inside GDB. + +@@node Options, Compilation, Files, Top +@@chapter Options and Arguments for GDB + +When you invoke GDB, you can pass commands telling it what files to +operate on and what other things to do. + +@@menu +* Mode Options:: Options controlling modes of operation. +* File Options:: Options to specify files (executable, coredump, commands) +* Other Arguments:: Any other arguments without options + also specify files. +@@end menu + +@@node Mode Options, File Options, Options, Options +@@section Mode Options + +@@table @@samp +@@item -nx +Do not execute commands from the init files @@file{.gdbinit}. +Normally, the commands in these files are executed after all the +command options and arguments have been processed. @@xref{Command +Files}. + +@@item -q +``Quiet''. Do not print the usual introductory messages. + +@@item -batch +Run in batch mode. Exit with code 1 after processing all the command +files specified with @@samp{-x} (and @@file{.gdbinit}, if not +inhibited). Exit also if, due to an error, GDB would otherwise +attempt to read a command from the terminal. + +@@item -fullname +This option is used when Emacs runs GDB as a subprocess. It tells GDB +to output the full file name and line number in a standard, +recognizable fashion each time a stack frame is displayed (which +includes each time the program stops). This recognizable format looks +like two @@samp{\032} characters, followed by the filename, line number +and character position separated by colons, and a newline. The +Emacs-to-GDB interface program uses the two @@samp{\032} characters as +a signal to display the source code for the frame. +@@end table + +@@node File Options, Other Arguments, Mode Options, Options +@@section File-specifying Options + +All the options and command line arguments given are processed +in sequential order. The order makes a difference when the +@@samp{-x} command is used. + +@@table @@samp +@@item -s @@var{file} +Read symbol table from file @@var{file}. + +@@item -e @@var{file} +Use file @@var{file} as the executable file to execute when +appropriate, and for examining pure data in conjunction with a core +dump. + +@@item -se @@var{file} +Read symbol table from file @@var{file} and use it as the executable +file. + +@@item -c @@var{file} +Use file @@var{file} as a core dump to examine. + +@@item -x @@var{file} +Execute GDB commands from file @@var{file}. + +@@item -d @@var{directory} +Add @@var{directory} to the path to search for source files. +@@end table + +@@node Other Arguments,, File Options, Options +@@section Other Arguments + +If there are arguments to GDB that are not options or associated with +options, the first one specifies the symbol table and executable file name +(as if it were preceded by @@samp{-se}) and the second one specifies a core +dump file name (as if it were preceded by @@samp{-c}). + +@@node Compilation, Running, Options, Top +@@chapter Compiling Your Program for Debugging + +In order to debug a program effectively, you need to ask for debugging +information when you compile it. This information in the object file +describes the data type of each variable or function and the correspondence +between source line numbers and addresses in the executable code. + +To request debugging information, specify the @@samp{-g} option when you run +the compiler. + +The Unix C compiler is unable to handle the @@samp{-g} and @@samp{-O} options +together. This means that you cannot ask for optimization if you ask for +debugger information. + +The GNU C compiler supports @@samp{-g} with or without @@samp{-O}, making it +possible to debug optimized code. We recommend that you @@emph{always} use +@@samp{-g} whenever you compile a program. You may think the program is +correct, but there's no sense in pushing your luck. + +If you are using the GNU C compiler, the GNU assembler and the GNU linker, +you can choose between two formats of debugging information: the standard +Unix format, which is what you get with @@samp{-g}, and GDB's own format, +which you request by using @@samp{-gg} instead of @@samp{-g}. This stores +debugging information in the executable file in a format much like that +which is used inside GDB. This has these advantages and disadvantages: + +@@itemize @@bullet +@@item +GDB can read @@samp{-gg} format more than twice as fast as Unix +@@samp{-g} format. + +@@item +The @@samp{-gg} format uses much more disk space than Unix format. + +@@item +The Unix debuggers can understand only Unix format, so you cannot use +Unix source-level debuggers if you compile with @@samp{-gg}. (The +@@code{adb} debugger works with either format; it does not use this +information in any case.) +@@end itemize + +@@node Running, Stopping, Compilation, Top +@@chapter Running Your Program Under GDB + +@@cindex running +@@kindex run +To start your program under GDB, use the @@samp{run} command. The program +must already have been specified using the @@samp{exec-file} command or with +an argument to GDB (@@pxref{Files}); what @@samp{run} does is create an +inferior process, load the program into it, and set it in motion. + +The execution of a program is affected by certain information it receives +from its superior. GDB provides ways to specify them, which you must do +@@i{before} starting the program. (You can change them after starting the +program, but such changes do not affect the program unless you start it +over again.) + +@@table @@asis +@@item The @@i{arguments.} +You specify the arguments to give the program as the arguments of the +@@samp{run} command. + +@@item The @@i{environment.} +The program normally inherits its environment from GDB, but you can +use the GDB commands @@samp{set environment} and +@@samp{unset environment} to change parts of the environment that will +be given to the program.@@refill + +@@item The @@i{working directory.} +The program inherits its working directory from GDB. You can set GDB's +working directory with the @@samp{cd} command in GDB. +@@end table + +After the @@samp{run} command, the debugger does nothing but wait for your +program to stop. @@xref{Stopping}. + +Note that once your program has been started by the @@samp{run} command, +you may evaluate expressions that involve calls to functions in the +inferior. @@xref{Expressions}. If you wish to evaluate a function +simply for it's side affects, you may use the @@samp{set} command. +@@xref{Assignment}. + +@@menu +* Arguments:: Specifying the arguments for your program. +* Environment:: Specifying the environment for your program. +* Working Directory:: Specifying the working directory for giving + to your program when it is run. +* Input/Output:: Specifying the program's standard input and output. +* Attach:: Debugging a process started outside GDB. +@@end menu + +@@node Arguments, Environment, Running, Running +@@section Your Program's Arguments + +@@cindex arguments (to your program) +You specify the arguments to give the program as the arguments of the +@@samp{run} command. They are passed to a shell, which expands wildcard +characters and performs redirection of I/O, and thence to the program. + +@@samp{run} with no arguments uses the same arguments used by the previous +@@samp{run}. + +@@kindex set args +The command @@samp{set args} can be used to specify the arguments to be used +the next time the program is run. If @@samp{set args} has no arguments, it +means to use no arguments the next time the program is run. If you have +run your program with arguments and want to run it again with no arguments, +this is the only way to do so. + +@@node Environment, Working Directory, Arguments, Running +@@section Your Program's Environment + +@@cindex environment (of your program) +The @@dfn{environment} consists of a set of @@dfn{environment variables} and +their values. Environment variables conventionally record such things as +your user name, your home directory, your terminal type, and your search +path for programs to run. Usually you set up environment variables with +the shell and they are inherited by all the other programs you run. When +debugging, it can be useful to try running the program with different +environments without having to start the debugger over again. + +@@table @@code +@@item info environment @@var{varname} +@@kindex info environment +Print the value of environment variable @@var{varname} to be given to +your program when it is started. This command can be abbreviated +@@samp{i env @@var{varname}}. + +@@item info environment +Print the names and values of all environment variables to be given to +your program when it is started. This command can be abbreviated +@@samp{i env}. + +@@item set environment @@var{varname} @@var{value} +@@item set environment @@var{varname} = @@var{value} +@@kindex set environment +Sets environment variable @@var{varname} to @@var{value}, for your program +only, not for GDB itself. @@var{value} may be any string; the values of +environment variables are just strings, and any interpretation is +supplied by your program itself. The @@var{value} parameter is optional; +if it is eliminated, the variable is set to a null value. This command +can be abbreviated as short as @@samp{set e}. + +@@item delete environment @@var{varname} +@@kindex delete environment +@@item unset environment @@var{varname} +@@kindex unset environment +Remove variable @@var{varname} from the environment to be passed to +your program. This is different from @@samp{set env @@var{varname} =} +because @@samp{delete environment} makes a variable not be defined at +all, which is distinguishable from an empty value. This command can +be abbreviated @@samp{d e}. +@@end table + +@@node Working Directory, Input/Output, Environment, Running +@@section Your Program's Working Directory + +@@cindex working directory (of your program) +Each time you start your program with @@samp{run}, it inherits its working +directory from the current working directory of GDB. GDB's working +directory is initially whatever it inherited from its superior, but you can +specify the working directory for GDB with the @@samp{cd} command. + +The GDB working directory also serves as a default for the commands +that specify files for GDB to operate on. @@xref{Files}. + +@@table @@code +@@item cd @@var{directory} +@@kindex cd +Set GDB's working directory to @@var{directory}. + +@@item pwd +@@kindex pwd +Print GDB's working directory. +@@end table + +@@node Input/Output, Attach, Working Directory, Running +@@section Your Program's Input and Output + +@@cindex redirection +@@cindex controlling terminal +By default, the program you run under GDB does input and output to the same +terminal that GDB uses. + +You can redirect the program's input and/or output using @@samp{sh}-style +redirection commands in the @@samp{run} command. For example, + +@@example +run > outfile +@@end example + +@@noindent +starts the program, diverting its output to the file @@file{outfile}. + +@@kindex tty +Another way to specify where the program should do input and output is with +the @@samp{tty} command. This command accepts a file name as argument, and +causes this file to be the default for future @@samp{run} commands. It also +resets the controlling terminal for future @@samp{run} commands. For +example, + +@@example +tty /dev/ttyb +@@end example + +@@noindent +directs that processes started with subsequent @@samp{run} commands default +to do input and output on the terminal @@file{/dev/ttyb} and sets the +controlling terminal to @@file{/dev/ttyb}. An explicit redirection in +@@samp{run} overrides the @@samp{tty} command's effect on input/output +redirection. + +When you use the @@samp{tty} command or redirect input in the @@samp{run} +command, the @@emph{input for your program} comes from the specified file, +but the input for GDB still comes from your terminal. + +@@node Attach,, Input/Output, Running +@@section Debugging an Already-Running Process +@@kindex detach +@@kindex attach +@@cindex attach + +Some operating systems (in particular, Sun) allow GDB to begin debugging an +already-running process that was started outside of GDB. To do this you +must use the @@samp{attach} command instead of the @@samp{run} command. + +The @@samp{attach} command requires one argument, which is the process-id of +the process you want to debug. (The usual way to find out the process-id +of the process is with the @@samp{ps} utility.) + +The first thing GDB does after arranging to debug the process is to stop +it. You can examine and modify an attached process with all the GDB +commands that ordinarily available when you start processes with +@@samp{run}. You can insert breakpoints; you can step and continue; you +can modify storage. If you would rather the process continue running, +use the @@samp{continue} command after attaching. + +When you are finished debugging the attached process, you can use the +@@samp{detach} command to release it from GDB's control. Detaching +the process continues its execution. After the @@samp{detach} command, +that process and GDB become completely independent once more, and you +are ready to @@samp{attach} another process or start one with @@samp{run}. + +If you exit GDB or use the @@samp{run} command while you have an attached +process, you kill that process. You will be asked for confirmation if you +try to do either of these things. + +@@node Stopping, Stack, Running, Top +@@chapter Stopping and Continuing + +When you run a program normally, it runs until exiting. The purpose +of using a debugger is so that you can stop it before that point; +or so that if the program runs into trouble you can find out why. + +@@menu +* Signals:: Fatal signals in your program just stop it; + then you can use GDB to see what is going on. +* Breakpoints:: Breakpoints let you stop your program when it + reaches a specified point in the code. +* Continuing:: Resuming execution until the next signal or breakpoint. +* Stepping:: Stepping runs the program a short distance and + then stops it wherever it has come to. +@@end menu + +@@node Signals, Breakpoints, Stopping, Stopping +@@section Signals + +A signal is an asynchronous event that can happen in a program. The +operating system defines the possible kinds of signals, and gives each kind +a name and a number. For example, @@code{SIGINT} is the signal a program +gets when you type @@kbd{Ctrl-c}; @@code{SIGSEGV} is the signal a program +gets from referencing a place in memory far away from all the areas in use; +@@code{SIGALRM} occurs when the alarm clock timer goes off (which happens +only if the program has requested an alarm). + +Some signals, including @@code{SIGALRM}, are a normal part of the +functioning of the program. Others, such as @@code{SIGSEGV}, indicate +errors; these signals are @@dfn{fatal} (kill the program immediately) if the +program has not specified in advance some other way to handle the signal. +@@code{SIGINT} does not indicate an error in the program, but it is normally +fatal so it can carry out the purpose of @@kbd{Ctrl-c}: to kill the program. + +GDB has the ability to detect any occurrence of a signal in the program +running under GDB's control. You can tell GDB in advance what to do for +each kind of signal. + +Normally, GDB is set up to ignore non-erroneous signals like @@code{SIGALRM} +(so as not to interfere with their role in the functioning of the program) +but to stop the program immediately whenever an error signal happens. +You can change these settings with the @@samp{handle} command. You must +specify which signal you are talking about with its number. + +@@table @@code +@@item info signal +@@kindex info signal +Print a table of all the kinds of signals and how GDB has been told to +handle each one. You can use this to see the signal numbers of all +the defined types of signals. + +@@item handle @@var{signalnum} @@var{keywords}@@dots{} +@@kindex handle +Change the way GDB handles signal @@var{signalnum}. The @@var{keywords} +say what change to make. +@@end table + +To use the @@samp{handle} command you must know the code number of the +signal you are concerned with. To find the code number, type @@samp{info +signal} which prints a table of signal names and numbers. + +The keywords allowed by the handle command can be abbreviated. Their full +names are + +@@table @@code +@@item stop +GDB should stop the program when this signal happens. This implies +the @@samp{print} keyword as well. + +@@item print +GDB should print a message when this signal happens. + +@@item nostop +GDB should not stop the program when this signal happens. It may +still print a message telling you that the signal has come in. + +@@item noprint +GDB should not mention the occurrence of the signal at all. This +implies the @@samp{nostop} keyword as well. + +@@item pass +GDB should allow the program to see this signal; the program will be +able to handle the signal, or may be terminated if the signal is fatal +and not handled. + +@@item nopass +GDB should not allow the program to see this signal. +@@end table + +When a signal has been set to stop the program, the program cannot see the +signal until you continue. It will see the signal then, if @@samp{pass} is +in effect for the signal in question @@i{at that time}. In other words, +after GDB reports a signal, you can use the @@samp{handle} command with +@@samp{pass} or @@samp{nopass} to control whether that signal will be seen by +the program when you later continue it. + +You can also use the @@samp{signal} command to prevent the program from +seeing a signal, or cause it to see a signal it normally would not see, +or to give it any signal at any time. @@xref{Signaling}. + +@@node Breakpoints, Continuing, Signals, Stopping +@@section Breakpoints + +@@cindex breakpoints +A @@dfn{breakpoint} makes your program stop whenever a certain point in the +program is reached. You set breakpoints explicitly with GDB commands, +specifying the place where the program should stop by line number, function +name or exact address in the program. You can add various other conditions +to control whether the program will stop. + +Each breakpoint is assigned a number when it is created; these numbers are +successive integers starting with 1. In many of the commands for controlling +various features of breakpoints you use the breakpoint number to say which +breakpoint you want to change. Each breakpoint may be @@dfn{enabled} or +@@dfn{disabled}; if disabled, it has no effect on the program until you +enable it again. + +@@kindex info break +@@kindex $_ +The command @@samp{info break} prints a list of all breakpoints set and not +cleared, showing their numbers, where in the program they are, and any +special features in use for them. Disabled breakpoints are included in the +list, but marked as disabled. @@samp{info break} with a breakpoint number +as argument lists only that breakpoint. The convenience variable @@samp{$_} +and the default examining-address for the @@samp{x} command are set to the +address of the last breakpoint listed (@@pxref{Memory}). + +@@menu +* Set Breaks:: How to establish breakpoints. +* Clear Breaks:: How to remove breakpoints no longer needed. +* Disabling:: How to disable breakpoints (turn them off temporarily). +* Conditions:: Making extra conditions on whether to stop. +* Break Commands:: Commands to be executed at a breakpoint. +* Error in Breakpoints:: "Cannot insert breakpoints" error--why, what to do. +@@end menu + +@@node Set Breaks, Clear Breaks, Breakpoints, Breakpoints +@@subsection Setting Breakpoints + +@@kindex break +Breakpoints are set with the @@samp{break} command (abbreviated @@samp{b}). +You have several ways to say where the breakpoint should go. + +@@table @@code +@@item break @@var{function} +Set a breakpoint at entry to function @@var{function}. + +@@item break @@var{linenum} +Set a breakpoint at line @@var{linenum} in the current source file. +That file is the last file whose source text was printed. This +breakpoint will stop the program just before it executes any of the +code on that line. + +@@item break @@var{filename}:@@var{linenum} +Set a breakpoint at line @@var{linenum} in source file @@var{filename}. + +@@item break @@var{filename}:@@var{function} +Set a breakpoint at entry to function @@var{function} found in file +@@var{filename}. Specifying a filename as well as a function name is +superfluous except when multiple files contain similarly named +functions. + +@@item break *@@var{address} +Set a breakpoint at address @@var{address}. You can use this to set +breakpoints in parts of the program which do not have debugging +information or source files. + +@@item break +Set a breakpoint at the next instruction to be executed in the selected +stack frame (@@pxref{Stack}). In any selected frame but the innermost, +this will cause the program to stop as soon as control returns to that +frame. This is equivalent to a @@samp{finish} command in the frame +inside the selected frame. If this is done in the innermost frame gdb +will stop the next time it reaches the current location; this may be +useful inside of loops. It does not stop at this breakpoint immediately +upon continuation of the program since no code would be executed if it +did. + +@@item break @@dots{} if @@var{cond} +Set a breakpoint with condition @@var{cond}; evaluate the expression +@@var{cond} each time the breakpoint is reached, and stop only if the +value is nonzero. @@samp{@@dots{}} stands for one of the possible +arguments described above (or no argument) specifying where to break. +@@xref{Conditions}, for more information on breakpoint conditions. + +@@item tbreak @@var{args} +@@kindex tbreak +Set a breakpoint enabled only for one stop. @@var{args} are the +same as in the @@samp{break} command, and the breakpoint is set in the same +way, but the breakpoint is automatically @@dfn{disabled} the first time it +is hit. +@@end table + +GDB allows you to set any number of breakpoints at the same place in the +program. There is nothing silly or meaningless about this. When the +breakpoints are conditional, this is even useful (@@pxref{Conditions}). + +@@node Clear Breaks, Disabling, Set Breaks, Breakpoints +@@subsection Clearing Breakpoints + +@@cindex clear breakpoint +@@cindex delete breakpoints +It is often necessary to eliminate a breakpoint once it has done its job +and you no longer want the program to stop there. This is called +@@dfn{clearing} or @@samp{deleting} the breakpoint. A breakpoint that +has been cleared no longer exists in any sense. + +With the @@samp{clear} command you can clear breakpoints according to where +they are in the program. With the @@samp{delete} command you can clear +individual breakpoints by specifying their breakpoint numbers. + +@@b{It is not necessary to clear a breakpoint to proceed past it.} GDB +automatically ignores breakpoints in the first instruction to be executed +when you continue execution at the same address where the program stopped. + +@@table @@code +@@item clear +@@kindex clear +Clear any breakpoints at the next instruction to be executed in the +selected stack frame (@@pxref{Selection}). When the innermost frame +is selected, this is a good way to clear a breakpoint that the program +just stopped at. + +@@item clear @@var{function} +@@itemx clear @@var{filename}:@@var{function} +Clear any breakpoints set at entry to the function @@var{function}. + +@@item clear @@var{linenum} +@@item clear @@var{filename}:@@var{linenum} +Clear any breakpoints set at or within the code of the specified line. + +@@item delete @@var{bnums}@@dots{} +@@kindex delete +Delete the breakpoints of the numbers specified as arguments. +A breakpoint deleted is forgotten completely. +@@end table + +@@node Disabling, Conditions, Clear Breaks, Breakpoints +@@subsection Disabling Breakpoints + +@@cindex disabled breakpoints +@@cindex enabled breakpoints +Rather than clearing a breakpoint, you might prefer to @@dfn{disable} it. +This makes the breakpoint inoperative as if it had been cleared, but +remembers the information on the breakpoint so that you can @@dfn{enable} +it again later. + +You disable and enable breakpoints with the @@samp{enable} and +@@samp{disable} commands, specifying one or more breakpoint numbers as +arguments. Use @@samp{info break} to print a list of breakpoints if you +don't know which breakpoint numbers to use. + +A breakpoint can have any of four different states of enablement: + +@@itemize @@bullet +@@item +Enabled. The breakpoint will stop the program. A breakpoint made +with the @@samp{break} command starts out in this state. +@@item +Disabled. The breakpoint has no effect on the program. +@@item +Enabled once. The breakpoint will stop the program, but +when it does so it will become disabled. A breakpoint made +with the @@samp{tbreak} command starts out in this state. +@@item +Enabled for deletion. The breakpoint will stop the program, but +immediately after it does so it will be deleted permanently. +@@end itemize + +You change the state of enablement of a breakpoint with the following +commands: + +@@table @@code +@@item disable breakpoints @@var{bnums}@@dots{} +@@kindex disable breakpoints +@@item disable @@var{bnums}@@dots{} +@@kindex disable +Disable the specified breakpoints. A disabled breakpoint has no +effect but is not forgotten. All options such as ignore-counts, +conditions and commands are remembered in case the breakpoint is +enabled again later. + +@@item enable breakpoints @@var{bnums}@@dots{} +@@kindex enable breakpoints +@@item enable @@var{bnums}@@dots{} +@@kindex enable +Enable the specified breakpoints. They become effective once again in +stopping the program, until you specify otherwise. + +@@item enable breakpoints once @@var{bnums}@@dots{} +@@item enable once @@var{bnums}@@dots{} +Enable the specified breakpoints temporarily. Each will be disabled +again the next time it stops the program (unless you have used one of +these commands to specify a different state before that time comes). + +@@item enable breakpoints delete @@var{bnums}@@dots{} +@@item enable delete @@var{bnums}@@dots{} +Enable the specified breakpoints to work once and then die. Each of +the breakpoints will be deleted the next time it stops the program +(unless you have used one of these commands to specify a different +state before that time comes). +@@end table + +Aside from the automatic disablement or deletion of a breakpoint when it +stops the program, which happens only in certain states, the state of +enablement of a breakpoint changes only when one of the commands above +is used. + +@@node Conditions, Break Commands, Disabling, Breakpoints +@@subsection Break Conditions + +@@cindex conditions +The simplest sort of breakpoint breaks every time the program reaches a +specified place. You can also specify a @@dfn{condition} for a breakpoint. +A condition is just a boolean expression in your programming language +(@@xref{Expressions}). A breakpoint with a condition evaluates the +expression each time the program reaches it, and the program stops +only if the condition is true. + +Break conditions may have side effects, and may even call functions in your +program. These may sound like strange things to do, but their effects are +completely predictable unless there is another enabled breakpoint at the +same address. (In that case, GDB might see the other breakpoint first and +stop the program without checking the condition of this one.) Note that +breakpoint commands are usually more convenient and flexible for the +purpose of performing side effects when a breakpoint is reached +(@@pxref{Break Commands}). + +Break conditions can be specified when a breakpoint is set, by using +@@samp{if} in the arguments to the @@samp{break} command. @@xref{Set Breaks}. +They can also be changed at any time with the @@samp{condition} command: + +@@table @@code +@@item condition @@var{bnum} @@var{expression} +@@kindex condition +Specify @@var{expression} as the break condition for breakpoint number +@@var{bnum}. From now on, this breakpoint will stop the program only if +the value of @@var{expression} is true (nonzero, in C). @@var{expression} +is not evaluated at the time the @@samp{condition} command is given. +@@xref{Expressions}. + +@@item condition @@var{bnum} +Remove the condition from breakpoint number @@var{bnum}. It becomes +an ordinary unconditional breakpoint. +@@end table + +@@cindex ignore count (of breakpoint) +A special feature is provided for one kind of condition: to prevent the +breakpoint from doing anything until it has been reached a certain number +of times. This is done with the @@dfn{ignore count} of the breakpoint. +When the program reaches a breakpoint whose ignore count is positive, then +instead of stopping, it just decrements the ignore count by one and +continues. + +@@table @@code +@@item ignore @@var{bnum} @@var{count} +@@kindex ignore +Set the ignore count of breakpoint number @@var{bnum} to @@var{count}. +The next @@var{count} times the breakpoint is reached, it will not stop. + +To make the breakpoint stop the next time it is reached, specify +a count of zero. + +@@item cont @@var{count} +Continue execution of the program, setting the ignore count of the +breakpoint that the program stopped at to @@var{count} minus one. +Continuing through the breakpoint does not itself count as one of +@@var{count}. Thus, the program will not stop at this breakpoint until the +@@var{count}'th time it is hit. + +This command is allowed only when the program stopped due to a +breakpoint. At other times, the argument to @@samp{cont} is ignored. +@@end table + +If a breakpoint has a positive ignore count and a condition, the condition +is not checked. Once the ignore count reaches zero, the condition will +start to be checked. + +Note that you could achieve the effect of the ignore count with a condition +such as @@samp{$foo-- <= 0} using a debugger convenience variable that is +decremented each time. That is why the ignore count is considered a +special case of a condition. @@xref{Convenience Vars}. + +@@node Break Commands, Error in Breakpoints, Conditions, Breakpoints +@@subsection Commands Executed on Breaking + +@@cindex breakpoint commands +You can give any breakpoint a series of commands to execute when the +program stops due to that breakpoint. For example, you might want to +print the values of certain expressions, or enable other breakpoints. + +@@table @@code +@@item commands @@var{bnum} +Specify commands for breakpoint number @@var{bnum}. The commands +themselves appear on the following lines. Type a line containing just +@@samp{end} to terminate the commands. + +To remove all commands from a breakpoint, use the command +@@samp{commands} and follow it immediately by @@samp{end}; that is, give +no commands. + +With no arguments, @@samp{commands} refers to the last breakpoint set. +@@end table + +It is possible for breakpoint commands to start the program up again. +Simply use the @@samp{cont} command, or @@samp{step}, or any other command +to resume execution. However, any remaining breakpoint commands are +ignored. When the program stops again, GDB will act according to why +that stop took place. + +@@kindex silent +If the first command specified is @@samp{silent}, the usual message about +stopping at a breakpoint is not printed. This may be desirable for +breakpoints that are to print a specific message and then continue. +If the remaining commands too print nothing, you will see no sign that +the breakpoint was reached at all. @@samp{silent} is not really a command; +it is meaningful only at the beginning of the commands for a breakpoint. + +The commands @@samp{echo} and @@samp{output} that allow you to print precisely +controlled output are often useful in silent breakpoints. @@xref{Output}. + +For example, here is how you could use breakpoint commands to print the +value of @@code{x} at entry to @@code{foo} whenever it is positive. We +assume that the newly created breakpoint is number 4; @@samp{break} will +print the number that is assigned. + +@@example +break foo if x>0 +commands 4 +silent +echo x is\040 +output x +echo \n +cont +end +@@end example + +One application for breakpoint commands is to correct one bug so you can +test another. Put a breakpoint just after the erroneous line of code, give +it a condition to detect the case in which something erroneous has been +done, and give it commands to assign correct values to any variables that +need them. End with the @@samp{cont} command so that the program does not +stop, and start with the @@samp{silent} command so that no output is +produced. Here is an example: + +@@example +break 403 +commands 5 +silent +set x = y + 4 +cont +end +@@end example + +One deficiency in the operation of automatically continuing breakpoints +under Unix appears when your program uses raw mode for the terminal. +GDB switches back to its own terminal modes (not raw) before executing +commands, and then must switch back to raw mode when your program is +continued. This causes any pending terminal input to be lost. + +In the GNU system, this will be fixed by changing the behavior of +terminal modes. + +Under Unix, when you have this problem, you might be able to get around +it by putting your actions into the breakpoint condition instead of +commands. For example + +@@example +condition 5 (x = y + 4), 0 +@@end example + +@@noindent +is a condition expression (@@xref{Expressions}) that will change @@code{x} +as needed, then always have the value 0 so the program will not stop. +Loss of input is avoided here because break conditions are evaluated +without changing the terminal modes. When you want to have nontrivial +conditions for performing the side effects, the operators @@samp{&&}, +@@samp{||} and @@samp{?@@: @@dots{} :@@:} may be useful. + +@@node Error in Breakpoints,, Break Commands, Breakpoints +@@subsection ``Cannot Insert Breakpoints'' Error + +Under some Unix systems, breakpoints cannot be used in a program if any +other process is running that program. Attempting to run or continue +the program with a breakpoint in this case will cause GDB to stop it. + +When this happens, you have three ways to proceed: + +@@enumerate +@@item +Remove or disable the breakpoints, then continue. + +@@item +Suspend GDB, and copy the file containing the program to a new name. +Resume GDB and use the @@samp{exec-file} command to specify that GDB +should run the program under that name. Then start the program again. + +@@item +Recompile the program so that the text is non-sharable (a.out format +OMAGIC). +@@end enumerate + +@@node Continuing, Stepping, Breakpoints, Stopping +@@section Continuing + +After your program stops, most likely you will want it to run some more if +the bug you are looking for has not happened yet. + +@@table @@code +@@item cont +@@kindex cont +Continue running the program at the place where it stopped. +@@end table + +If the program stopped at a breakpoint, the place to continue running +is the address of the breakpoint. You might expect that continuing would +just stop at the same breakpoint immediately. In fact, @@samp{cont} +takes special care to prevent that from happening. You do not need +to clear the breakpoint to proceed through it after stopping at it. + +You can, however, specify an ignore-count for the breakpoint that the +program stopped at, by means of an argument to the @@samp{cont} command. +@@xref{Conditions}. + +If the program stopped because of a signal other than @@code{SIGINT} or +@@code{SIGTRAP}, continuing will cause the program to see that signal. +You may not want this to happen. For example, if the program stopped +due to some sort of memory reference error, you might store correct +values into the erroneous variables and continue, hoping to see more +execution; but the program would probably terminate immediately as +a result of the fatal signal once it sees the signal. To prevent this, +you can continue with @@samp{signal 0}. @@xref{Signaling}. You can +also act in advance to prevent the program from seeing certain kinds +of signals, using the @@samp{handle} command (@@pxref{Signals}). + +@@node Stepping,, Continuing, Stopping +@@section Stepping + +@@cindex stepping +@@dfn{Stepping} means setting your program in motion for a limited time, so +that control will return automatically to the debugger after one line of +code or one machine instruction. Breakpoints are active during stepping +and the program will stop for them even if it has not gone as far as the +stepping command specifies. + +@@table @@code +@@item step +@@kindex step +Proceed the program until control reaches a different line, then stop +it and return to the debugger. This command is abbreviated @@samp{s}. + +@@item step @@var{count} +Proceed as in @@samp{step}, but do so @@var{count} times. If a breakpoint +or a signal not related to stepping is reached before @@var{count} steps, +stepping stops right away. + +This command may be given when control is within a routine for which +there is no debugging information. In that case, execution will proceed +until control reaches a different routine, or is about to return from +this routine. An argument repeats this action. + +@@item next +@@kindex next +Similar to @@samp{step}, but any function calls appearing within the line of +code are executed without stopping. Execution stops when control reaches a +different line of code at the stack level which was executing when the +@@samp{next} command was given. This command is abbreviated @@samp{n}. + +An argument is a repeat count, as in @@samp{step}. + +@@samp{next} within a routine without debugging information acts as does +@@samp{step}, but any function calls appearing within the code of the +routine are executed without stopping. + +@@item finish +@@kindex finish +Continue running until just after the selected stack frame returns +(or until there is some other reason to stop, such as a fatal signal +or a breakpoint). Print value returned by the selected stack frame (if +any). + +Contrast this with the @@samp{return} command (@@pxref{Returning}). + +@@item until +@@kindex until +Proceed the program until control reaches a line greater than the current +line, then stop is and return to the debugger. Control is also returned to +the debugger if the program exits the current stack frame. Note that this +form of the command uses single stepping, and hence is slower than +@@samp{until} with an argument. This command is abbreviated @@samp{u}. + +@@item until @@var{location} +Proceed the program until either the specified location is reached, or the +current (innermost) stack frame returns. This form of the command uses +breakpoints, and hence is quicker than @@samp{until} without an argument. + +@@item stepi +@@itemx si +@@kindex stepi +@@kindex si +Proceed one machine instruction, then stop and return to the debugger. + +It is often useful to do @@samp{display/i $pc} when stepping by machine +instructions. This will cause the next instruction to be executed to +be displayed automatically at each stop. @@xref{Auto Display}. + +An argument is a repeat count, as in @@samp{step}. + +@@item nexti +@@itemx ni +@@kindex nexti +@@kindex ni +Proceed one machine instruction, but if it is a subroutine call, +proceed until the subroutine returns. + +An argument is a repeat count, as in @@samp{next}. +@@end table + +A typical technique for using stepping is to put a breakpoint +(@@pxref{Breakpoints}) at the beginning of the function or the section of +the program in which a problem is believed to lie, and then step through +the suspect area, examining the variables that are interesting, until the +problem happens. + +The @@samp{cont} command can be used after stepping to resume execution +until the next breakpoint or signal. + +@@node Stack, Source, Stopping, Top +@@chapter Examining the Stack + +When your program has stopped, the first thing you need to know is where it +stopped and how it got there. + +@@cindex call stack +Each time your program performs a function call, the information about +where in the program the call was made from is saved in a block of data +called a @@dfn{stack frame}. The frame also contains the arguments of the +call and the local variables of the function that was called. All the +stack frames are allocated in a region of memory called the @@dfn{call +stack}. + +When your program stops, the GDB commands for examining the stack allow you +to see all of this information. + +One of the stack frames is @@dfn{selected} by GDB and many GDB commands +refer implicitly to the selected frame. In particular, whenever you ask +GDB for the value of a variable in the program, the value is found in the +selected frame. There are special GDB commands to select whichever frame +you are interested in. + +When the program stops, GDB automatically selects the currently executing +frame and describes it briefly as the @@samp{frame} command does +(@@pxref{Frame Info, Info}). + +@@menu +* Frames:: Explanation of stack frames and terminology. +* Backtrace:: Summarizing many frames at once. +* Selection:: How to select a stack frame. +* Info: Frame Info, Commands to print information on stack frames. +@@end menu + +@@node Frames, Backtrace, Stack, Stack +@@section Stack Frames + +@@cindex frame +The call stack is divided up into contiguous pieces called @@dfn{frames}; +each frame is the data associated with one call to one function. The frame +contains the arguments given to the function, the function's local +variables, and the address at which the function is executing. + +@@cindex initial frame +@@cindex outermost frame +@@cindex innermost frame +When your program is started, the stack has only one frame, that of the +function @@code{main}. This is called the @@dfn{initial} frame or the +@@dfn{outermost} frame. Each time a function is called, a new frame is +made. Each time a function returns, the frame for that function invocation +is eliminated. If a function is recursive, there can be many frames for +the same function. The frame for the function in which execution is +actually occurring is called the @@dfn{innermost} frame. This is the most +recently created of all the stack frames that still exist. + +@@cindex frame pointer +Inside your program, stack frames are identified by their addresses. A +stack frame consists of many bytes, each of which has its own address; each +kind of computer has a convention for choosing one of those bytes whose +address serves as the address of the frame. Usually this address is kept +in a register called the @@dfn{frame pointer register} while execution is +going on in that frame. + +@@cindex frame number +GDB assigns numbers to all existing stack frames, starting with zero for +the innermost frame, one for the frame that called it, and so on upward. +These numbers do not really exist in your program; they are to give you a +way of talking about stack frames in GDB commands. + +@@cindex selected frame +Many GDB commands refer implicitly to one stack frame. GDB records a stack +frame that is called the @@dfn{selected} stack frame; you can select any +frame using one set of GDB commands, and then other commands will operate +on that frame. When your program stops, GDB automatically selects the +innermost frame. + +@@node Backtrace, Selection, Frames, Stack +@@section Backtraces + +A backtrace is a summary of how the program got where it is. It shows one +line per frame, for many frames, starting with the currently executing +frame (frame zero), followed by its caller (frame one), and on up the +stack. + +@@table @@code +@@item backtrace +@@itemx bt +Print a backtrace of the entire stack: one line per frame for all +frames in the stack. + +You can stop the backtrace at any time by typing the system interrupt +character, normally @@kbd{Control-C}. + +@@item backtrace @@var{n} +@@itemx bt @@var{n} +Similar, but stop after @@var{n} frames. + +@@item backtrace @@var{-n} +@@itemx bt @@var{-n} +Similar, but print the outermost @@var{n} frames instead of the +innermost. +@@end table + +Each line in a backtrace shows the frame number, the program counter, the +function and its arguments, and the source file name and line number (if +known). The program counter is omitted if is the beginning of the code for +the source line. This is the same as the first of the two lines printed +when you select a frame. + +@@node Selection, Frame Info, Backtrace, Stack +@@section Selecting a Frame + +Most commands for examining the stack and other data in the program work on +whichever stack frame is selected at the moment. Here are the commands for +selecting a stack frame; all of them finish by printing a brief description +of the stack frame just selected. + +@@table @@code +@@item frame @@var{n} +@@kindex frame +Select frame number @@var{n}. Recall that frame zero is the innermost +(currently executing) frame, frame one is the frame that called the +innermost one, and so on. The highest-numbered frame is @@code{main}'s +frame. + +@@item frame @@var{addr} +Select the frame at address @@var{addr}. This is useful mainly if the +chaining of stack frames has been damaged by a bug, making it +impossible for GDB to assign numbers properly to all frames. In +addition, this can be useful when the program has multiple stacks and +switches between them. + +@@item up @@var{n} +@@kindex up +Select the frame @@var{n} frames up from the frame previously selected. +For positive numbers @@var{n}, this advances toward the outermost +frame, to higher frame numbers, to frames that have existed longer. +@@var{n} defaults to one. + +@@item down @@var{n} +@@kindex down +Select the frame @@var{n} frames down from the frame previously +selected. For positive numbers @@var{n}, this advances toward the +innermost frame, to lower frame numbers, to frames that were created +more recently. @@var{n} defaults to one. +@@end table + +All of these commands end by printing some information on the frame that +has been selected: the frame number, the function name, the arguments, the +source file and line number of execution in that frame, and the text of +that source line. For example: + +@@example +#3 main (argc=3, argv=??, env=??) at main.c, line 67 +67 read_input_file (argv[i]); +@@end example + +After such a printout, the @@samp{list} command with no arguments will print +ten lines centered on the point of execution in the frame. @@xref{List}. + +@@node Frame Info,, Selection, Stack +@@section Information on a Frame + +There are several other commands to print information about the selected +stack frame. + +@@table @@code +@@item frame +This command prints a brief description of the selected stack frame. +It can be abbreviated @@samp{f}. With an argument, this command is +used to select a stack frame; with no argument, it does not change +which frame is selected, but still prints the same information. + +@@item info frame +@@kindex info frame +This command prints a verbose description of the selected stack frame, +including the address of the frame, the addresses of the next frame in +(called by this frame) and the next frame out (caller of this frame), +the address of the frame's arguments, the program counter saved in it +(the address of execution in the caller frame), and which registers +were saved in the frame. The verbose description is useful when +something has gone wrong that has made the stack format fail to fit +the usual conventions. + +@@item info frame @@var{addr} +Print a verbose description of the frame at address @@var{addr}, +without selecting that frame. The selected frame remains unchanged by +this command. + +@@item info args +@@kindex info args +Print the arguments of the selected frame, each on a separate line. + +@@item info locals +@@kindex info locals +Print the local variables of the selected frame, each on a separate +line. These are all variables declared static or automatic within all +program blocks that execution in this frame is currently inside of. +@@end table + +@@node Source, Data, Stack, Top +@@chapter Examining Source Files + +GDB knows which source files your program was compiled from, and +can print parts of their text. When your program stops, GDB +spontaneously prints the line it stopped in. Likewise, when you +select a stack frame (@@pxref{Selection}), GDB prints the line +which execution in that frame has stopped in. You can also +print parts of source files by explicit command. + +@@menu +* List:: Using the @@samp{list} command to print source files. +* Search:: Commands for searching source files. +* Source Path:: Specifying the directories to search for source files. +@@end menu + +@@node List, Search, Source, Source +@@section Printing Source Lines + +@@kindex list +To print lines from a source file, use the @@samp{list} command +(abbreviated @@samp{l}). There are several ways to specify what part +of the file you want to print. + +Here are the forms of the @@samp{list} command most commonly used: + +@@table @@code +@@item list @@var{linenum} +Print ten lines centered around line number @@var{linenum} in the +current source file. + +@@item list @@var{function} +Print ten lines centered around the beginning of function +@@var{function}. + +@@item list +Print ten more lines. If the last lines printed were printed with a +@@samp{list} command, this prints ten lines following the last lines +printed; however, if the last line printed was a solitary line printed +as part of displaying a stack frame (@@pxref{Stack}), this prints ten +lines centered around that line. + +@@item list @@minus{} +Print ten lines just before the lines last printed. +@@end table + +Repeating a @@samp{list} command with @@key{RET} discards the argument, +so it is equivalent to typing just @@samp{list}. This is more useful +than listing the same lines again. An exception is made for an +argument of @@samp{-}; that argument is preserved in repetition so that +each repetition moves up in the file. + +In general, the @@samp{list} command expects you to supply zero, one or two +@@dfn{linespecs}. Linespecs specify source lines; there are several ways +of writing them but the effect is always to specify some source line. +Here is a complete description of the possible arguments for @@samp{list}: + +@@table @@code +@@item list @@var{linespec} +Print ten lines centered around the line specified by @@var{linespec}. + +@@item list @@var{first},@@var{last} +Print lines from @@var{first} to @@var{last}. Both arguments are +linespecs. + +@@item list ,@@var{last} +Print ten lines ending with @@var{last}. + +@@item list @@var{first}, +Print ten lines starting with @@var{first}. + +@@item list + +Print ten lines just after the lines last printed. + +@@item list @@minus{} +Print ten lines just before the lines last printed. + +@@item list +As described in the preceding table. +@@end table + +Here are the ways of specifying a single source line---all the +kinds of linespec. + +@@table @@asis +@@item @@var{linenum} +Specifies line @@var{linenum} of the current source file. +When a @@samp{list} command has two linespecs, this refers to +the same source file as the first linespec. + +@@item +@@var{offset} +Specifies the line @@var{offset} lines after the last line printed. +When used as the second linespec in a @@samp{list} command that has +two, this specifies the line @@var{offset} lines down from the +first linespec. + +@@item @@minus{}@@var{offset} +Specifies the line @@var{offset} lines before the last line printed. + +@@item @@var{filename}:@@var{linenum} +Specifies line @@var{linenum} in the source file @@var{filename}. + +@@item @@var{function} +Specifies the line of the open-brace that begins the body of the +function @@var{function}. + +@@item @@var{filename}:@@var{function} +Specifies the line of the open-brace that begins the body of the +function @@var{function} in the file @@var{filename}. The file name is +needed with a function name only for disambiguation of identically +named functions in different source files. + +@@item *@@var{address} +Specifies the line containing the program address @@var{address}. +@@var{address} may be any expression. +@@end table + +One other command is used to map source lines to program addresses. + +@@table @@code +@@item info line @@var{linenum} +@@kindex info line +Print the starting and ending addresses of the compiled code for +source line @@var{linenum}. + +@@kindex $_ +The default examine address for the @@samp{x} command is changed to the +starting address of the line, so that @@samp{x/i} is sufficient to +begin examining the machine code (@@pxref{Memory}). Also, this address +is saved as the value of the convenience variable @@samp{$_} +(@@pxref{Convenience Vars}). +@@end table + +@@node Search, Source Path, List, Source +@@section Searching Source Files +@@cindex searching +@@kindex forward-search +@@kindex reverse-search + +There are two commands for searching through the current source file for a +regular expression. + +The command @@samp{forward-search @@var{regexp}} checks each line, starting +with the one following the last line listed, for a match for @@var{regexp}. +It lists the line that is found. You can abbreviate the command name +as @@samp{fo}. + +The command @@samp{reverse-search @@var{regexp}} checks each line, starting +with the one before the last line listed and going backward, for a match +for @@var{regexp}. It lists the line that is found. You can abbreviate +this command with as little as @@samp{rev}. + +@@node Source Path,, Search, Source +@@section Specifying Source Directories + +@@cindex source path +@@cindex directories for source files +Executable programs do not record the directories of the source files they +were compiled from, just the names. GDB remembers a list of directories to +search for source files; this is called the @@dfn{source path}. Each time +GDB wants a source file, it tries all the directories in the list, in the +order they are present in the list, until it finds a file with the desired +name. + +@@kindex directory +When you start GDB, its source path contains just the current working +directory. To add other directories, use the @@samp{directory} command. +@@b{Note that the search path for executable files and the working directory +are @@i{not} used for finding source files.} + +@@table @@code +@@item directory @@var{dirname} +Add directory @@var{dirname} to the end of the source path. + +@@item directory +Reset the source path to just the current working directory of GDB. +This requires confirmation. + +@@samp{directory} with no argument can cause source files previously +found by GDB to be found in a different directory. To make this work +correctly, this command also clears out the tables GDB maintains +about the source files it has already found. + +@@item info directories +@@kindex info directories +Print the source path: show which directories it contains. +@@end table + +Because the @@samp{directory} command adds to the end of the source path, +it does not affect any file that GDB has already found. If the source +path contains directories that you do not want, and these directories +contain misleading files with names matching your source files, the +way to correct the situation is as follows: + +@@enumerate +@@item +Choose the directory you want at the beginning of the source path. +Use the @@samp{cd} command to make that the current working directory. + +@@item +Use @@samp{directory} with no argument to reset the source path to just +that directory. + +@@item +Use @@samp{directory} with suitable arguments to add any other +directories you want in the source path. +@@end enumerate + +@@node Data, Symbols, Source, Top +@@chapter Examining Data + +@@cindex printing data +@@cindex examining data +@@kindex print +The usual way of examining data in your program is with the @@samp{print} +command (abbreviated @@samp{p}). It evaluates and prints the value of any +valid expression of the language the program is written in (for now, C). +You type + +@@example +print @@var{exp} +@@end example + +@@noindent +where @@var{exp} is any valid expression, and the value of @@var{exp} +is printed in a format appropriate to its data type. + +A more low-level way of examining data is with the @@samp{x} command. +It examines data in memory at a specified address and prints it in a +specified format. + +GDB supports one command to modify the default format of displayed data: + +@@table @@samp +@@item set array-max +@@kindex set array-max +@@samp{set array-max} sets the maximum number of elements of an array which +will be printed. This limit also applies to the display of strings. +@@end table + +@@menu +* Expressions:: Expressions that can be computed and printed. +* Variables:: Using your program's variables in expressions. +* Assignment:: Setting your program's variables. +* Arrays:: Examining part of memory as an array. +* Formats:: Specifying formats for printing values. +* Memory:: Examining memory explicitly. +* Auto Display:: Printing certain expressions whenever program stops. +* Value History:: Referring to values previously printed. +* Convenience Vars:: Giving names to values for future reference. +* Registers:: Referring to and storing in machine registers. +@@end menu + +@@node Expressions, Variables, Data, Data +@@section Expressions + +@@cindex expressions +Many different GDB commands accept an expression and compute its value. +Any kind of constant, variable or operator defined by the programming +language you are using is legal in an expression in GDB. This includes +conditional expressions, function calls, casts and string constants. +It unfortunately does not include symbols defined by preprocessor +#define commands. + +Casts are supported in all languages, not just in C, because it is so +useful to cast a number into a pointer so as to examine a structure +at that address in memory. + +GDB supports three kinds of operator in addition to those of programming +languages: + +@@table @@code +@@item @@@@ +@@samp{@@@@} is a binary operator for treating parts of memory as arrays. +@@xref{Arrays}, for more information. + +@@item :: +@@samp{::} allows you to specify a variable in terms of the file or +function it is defined in. @@xref{Variables}. + +@@item @@{@@var{type}@@} @@var{addr} +Refers to an object of type @@var{type} stored at address @@var{addr} in +memory. @@var{addr} may be any expression whose value is an integer or +pointer (but parentheses are required around nonunary operators, just as in +a cast). This construct is allowed regardless of what kind of data is +officially supposed to reside at @@var{addr}.@@refill +@@end table + +@@node Variables, Arrays, Expressions, Data +@@section Program Variables + +The most common kind of expression to use is the name of a variable +in your program. + +Variables in expressions are understood in the selected stack frame +(@@pxref{Selection}); they must either be global (or static) or be visible +according to the scope rules of the programming language from the point of +execution in that frame. This means that in the function + +@@example +foo (a) + int a; +@@{ + bar (a); + @@{ + int b = test (); + bar (b); + @@} +@@} +@@end example + +@@noindent +the variable @@code{a} is usable whenever the program is executing +within the function @@code{foo}, but the variable @@code{b} is visible +only while the program is executing inside the block in which @@code{b} +is declared. + +As a special exception, you can refer to a variable or function whose +scope is a single source file even if the current execution point is not +in this file. But it is possible to have more than one such variable +or function with the same name (if they are in different source files). +In such a case, it is not defined which one you will get. If you wish, +you can specify any one of them using the colon-colon construct: + +@@example +@@var{block}::@@var{variable} +@@end example + +@@noindent +Here @@var{block} is the name of the source file whose variable you want. + +@@node Arrays, Formats, Variables, Data +@@section Artificial Arrays + +@@cindex artificial array +It is often useful to print out several successive objects of the +same type in memory; a section of an array, or an array of +dynamically determined size for which only a pointer exists in the +program. + +This can be done by constructing an @@dfn{artificial array} with the +binary operator @@samp{@@@@}. The left operand of @@samp{@@@@} should be +the first element of the desired array, as an individual object. +The right operand should be the length of the array. The result is +an array value whose elements are all of the type of the left argument. +The first element is actually the left argument; the second element +comes from bytes of memory immediately following those that hold the +first element, and so on. Here is an example. If a program says + +@@example +int *array = (int *) malloc (len * sizeof (int)); +@@end example + +@@noindent +you can print the contents of @@code{array} with + +@@example +p *array@@@@len +@@end example + +The left operand of @@samp{@@@@} must reside in memory. Array values made +with @@samp{@@@@} in this way behave just like other arrays in terms of +subscripting, and are coerced to pointers when used in expressions. +(It would probably appear in an expression via the value history, +after you had printed it out.) + +@@node Formats, Memory, Arrays, Data +@@section Formats + +@@cindex formatted output +@@cindex output formats +GDB normally prints all values according to their data types. Sometimes +this is not what you want. For example, you might want to print a number +in hex, or a pointer in decimal. Or you might want to view data in memory +at a certain address as a character string or an instruction. These things +can be done with @@dfn{output formats}. + +The simplest use of output formats is to say how to print a value +already computed. This is done by starting the arguments of the +@@samp{print} command with a slash and a format letter. The format +letters supported are: + +@@table @@samp +@@item x +Regard the bits of the value as an integer, and print the integer in +hexadecimal. + +@@item d +Print as integer in signed decimal. + +@@item u +Print as integer in unsigned decimal. + +@@item o +Print as integer in octal. + +@@item a +Print as an address, both absolute in hex and then relative +to a symbol defined as an address below it. + +@@item c +Regard as an integer and print it as a character constant. + +@@item f +Regard the bits of the value as a floating point number and print +using typical floating point syntax. +@@end table + +For example, to print the program counter in hex (@@pxref{Registers}), type + +@@example +p/x $pc +@@end example + +@@noindent +Note that no space is required before the slash; this is because command +names in GDB cannot contain a slash. + +To reprint the last value in the value history with a different format, +you can use the @@samp{print} command with just a format and no +expression. For example, @@samp{p/x} reprints the last value in hex. + +@@node Memory, Auto Display, Formats, Data +@@subsection Examining Memory + +@@cindex examining memory +@@kindex x +The command @@samp{x} (for `examine') can be used to examine memory under +explicit control of formats, without reference to the program's data types. + +@@samp{x} is followed by a slash and an output format specification, +followed by an expression for an address. The expression need not have +a pointer value (though it may); it is used as an integer, as the +address of a byte of memory. @@xref{Expressions} for more information +on expressions. + +The output format in this case specifies both how big a unit of memory +to examine and how to print the contents of that unit. It is done +with one or two of the following letters: + +These letters specify just the size of unit to examine: + +@@table @@samp +@@item b +Examine individual bytes. + +@@item h +Examine halfwords (two bytes each). + +@@item w +Examine words (four bytes each). + +@@cindex word +Many assemblers and cpu designers still use `word' for a 16-bit quantity, +as a holdover from specific predecessor machines of the 1970's that really +did use two-byte words. But more generally the term `word' has always +referred to the size of quantity that a machine normally operates on and +stores in its registers. This is 32 bits for all the machines that GNU +runs on. + +@@item g +Examine giant words (8 bytes). +@@end table + +These letters specify just the way to print the contents: + +@@table @@samp +@@item x +Print as integers in unsigned hexadecimal. + +@@item d +Print as integers in signed decimal. + +@@item u +Print as integers in unsigned decimal. + +@@item o +Print as integers in unsigned octal. + +@@item a +Print as an address, both absolute in hex and then relative +to a symbol defined as an address below it. + +@@item c +Print as character constants. + +@@item f +Print as floating point. This works only with sizes @@samp{w} and +@@samp{g}. + +@@item s +Print a null-terminated string of characters. The specified unit size +is ignored; instead, the unit is however many bytes it takes to reach +a null character (including the null character). + +@@item i +Print a machine instruction in assembler syntax (or nearly). The +specified unit size is ignored; the number of bytes in an instruction +varies depending on the type of machine, the opcode and the addressing +modes used. +@@end table + +If either the manner of printing or the size of unit fails to be specified, +the default is to use the same one that was used last. If you don't want +to use any letters after the slash, you can omit the slash as well. + +You can also omit the address to examine. Then the address used is +just after the last unit examined. This is why string and instruction +formats actually compute a unit-size based on the data: so that the +next string or instruction examined will start in the right place. +The @@samp{print} command sometimes sets the default address for +the @@samp{x} command; when the value printed resides in memory, the +default is set to examine the same location. @@samp{info line} also +sets the default for @@samp{x}, to the address of the start of the +machine code for the specified line and @@samp{info breakpoints} sets +it to the address of the last breakpoint listed. + +When you use @@key{RET} to repeat an @@samp{x} command, it does not repeat +exactly the same: the address specified previously (if any) is ignored, so +that the repeated command examines the successive locations in memory +rather than the same ones. + +You can examine several consecutive units of memory with one command by +writing a repeat-count after the slash (before the format letters, if any). +The repeat count must be a decimal integer. It has the same effect as +repeating the @@samp{x} command that many times except that the output may +be more compact with several units per line. + +@@example +x/10i $pc +@@end example + +@@noindent +Prints ten instructions starting with the one to be executed next in the +selected frame. After doing this, you could print another ten following +instructions with + +@@example +x/10 +@@end example + +@@noindent +in which the format and address are allowed to default. + +@@kindex $_ +@@kindex $__ +The addresses and contents printed by the @@samp{x} command are not put in +the value history because there is often too much of them and they would +get in the way. Instead, GDB makes these values available for subsequent +use in expressions as values of the convenience variables @@samp{$_} and +@@samp{$__}. + +After an @@samp{x} command, the last address examined is available for use +in expressions in the convenience variable @@samp{$_}. The contents of that +address, as examined, are available in the convenience variable @@samp{$__}. + +If the @@samp{x} command has a repeat count, the address and contents saved +are from the last memory unit printed; this is not the same as the last +address printed if several units were printed on the last line of output. + +@@node Auto Display, Value History, Memory, Data +@@section Automatic Display + +If you find that you want to print the value of an expression frequently +(to see how it changes), you might want to add it to the @@dfn{automatic +display list} so that GDB will print its value each time the program stops. +Each expression added to the list is given a number to identify it; +to remove an expression from the list, you specify that number. +The automatic display looks like this: + +@@example +2: foo = 38 +3: bar[5] = (struct hack *) 0x3804 +@@end example + +@@noindent +showing item numbers, expressions and their current values. + +@@table @@code +@@item display @@var{exp} +@@kindex display +Add the expression @@var{exp} to the list of expressions to display +each time the program stops. @@xref{Expressions}. + +@@item display/@@var{fmt} @@var{exp} +For @@var{fmt} specifying only a display format and not a size or +count, add the expression @@var{exp} to the auto-display list but +arranges to display it each time in the specified format @@var{fmt}. + +@@item display/@@var{fmt} @@var{addr} +For @@var{fmt} @@samp{i} or @@samp{s}, or including a unit-size or a +number of units, add the expression @@var{addr} as a memory address to +be examined each time the program stops. Examining means in effect +doing @@samp{x/@@var{fmt} @@var{addr}}. @@xref{Memory}. + +@@item undisplay @@var{dnums}@@dots{} +@@kindex undisplay +@@item delete display @@var{dnums}@@dots{} +@@kindex delete display +Remove item numbers @@var{dnums} from the list of expressions to display. + +@@item disable display @@var{dnums}@@dots{} +@@kindex disable display +Disable the display of item numbers @@var{dnums}. A disabled display item +has no effect but is not forgotten. It may be later enabled. + +@@item enable display @@var{dnums}@@dots{} +@@kindex enable display +Enable display of item numbers @@var{dnums}. It becomes effective once +again in auto display of its expression, until you specify otherwise. + +@@item display +Display the current values of the expressions on the list, just as is +done when the program stops. + +@@item info display +@@kindex info display +Print the list of expressions to display automatically, each one +with its item number, but without showing the values. +@@end table + +@@node Value History, Convenience Vars, Auto Display, Data +@@section Value History + +@@cindex value history +Every value printed by the @@samp{print} command is saved for the entire +session in GDB's @@dfn{value history} so that you can refer to it in +other expressions. + +@@cindex $ +@@cindex $$ +The values printed are given @@dfn{history numbers} for you to refer to them +by. These are successive integers starting with 1. @@samp{print} shows you +the history number assigned to a value by printing @@samp{$@@var{n} = } +before the value; here @@var{n} is the history number. + +To refer to any previous value, use @@samp{$} followed by the value's +history number. The output printed by @@samp{print} is designed to remind +you of this. Just @@samp{$} refers to the most recent value in the history, +and @@samp{$$} refers to the value before that. + +For example, suppose you have just printed a pointer to a structure and +want to see the contents of the structure. It suffices to type + +@@example +p *$ +@@end example + +If you have a chain of structures where the component @@samp{next} points +to the next one, you can print the contents of the next one with + +@@example +p *$.next +@@end example + +It might be useful to repeat this command many times by typing @@key{RET}. + +Note that the history records values, not expressions. If the value of +@@code{x} is 4 and you type + +@@example +print x +set x=5 +@@end example + +@@noindent +then the value recorded in the value history by the @@samp{print} command +remains 4 even though @@code{x}'s value has changed. + +@@table @@code +@@item info history +@@kindex info history +Print the last ten values in the value history, with their item +numbers. This is like @@samp{p $$9} repeated ten times, except that +@@samp{info history} does not change the history. + +@@item info history @@var{n} +Print ten history values centered on history item number @@var{n}. +@@end table + +@@node Convenience Vars, Registers, Value History, Data +@@section Convenience Variables + +@@cindex convenience variables +GDB provides @@dfn{convenience variables} that you can use within GDB to +hold on to a value and refer to it later. These variables exist entirely +within GDB; they are not part of your program, and setting a convenience +variable has no effect on further execution of your program. That's why +you can use them freely. + +Convenience variables have names starting with @@samp{$}. Any name starting +with @@samp{$} can be used for a convenience variable, unless it is one of +the predefined set of register names (@@pxref{Registers}). + +You can save a value in a convenience variable with an assignment +expression, just as you would set a variable in your program. Example: + +@@example +set $foo = *object_ptr +@@end example + +@@noindent +would save in @@samp{$foo} the value contained in the object pointed to by +@@code{object_ptr}. + +Using a convenience variable for the first time creates it; but its value +is @@code{void} until you assign a new value. You can alter the value with +another assignment at any time. + +Convenience variables have no fixed types. You can assign a convenience +variable any type of value, even if it already has a value of a different +type. The convenience variable as an expression has whatever type its +current value has. + +@@table @@code +@@item info convenience +@@kindex info convenience +Print a list of convenience variables used so far, and their values. +Abbreviated @@samp{i con}. +@@end table + +One of the ways to use a convenience variable is as a counter to be +incremented or a pointer to be advanced. For example: + +@@example +set $i = 0 +print bar[$i++]->contents +@@i{@@dots{}repeat that command by typing @@key{RET}.} +@@end example + +Some convenience variables are created automatically by GDB and given +values likely to be useful. + +@@table @@samp +@@item $_ +The variable @@samp{$_} is automatically set by the @@samp{x} command to +the last address examined (@@pxref{Memory}). Other commands which +provide a default address for @@samp{x} to examine also set @@samp{$_} +to that address; these commands include @@samp{info line} and @@samp{info +breakpoint}. + +@@item $__ +The variable @@samp{$__} is automatically set by the @@samp{x} command +to the value found in the last address examined. +@@end table + +@@node Registers,, Convenience Vars, Data +@@section Registers + +@@cindex registers +Machine register contents can be referred to in expressions as variables +with names starting with @@samp{$}. The names of registers are different +for each machine; use @@samp{info registers} to see the names used on your +machine. The names @@samp{$pc} and @@samp{$sp} are used on all machines for +the program counter register and the stack pointer. Often @@samp{$fp} is +used for a register that contains a pointer to the current stack frame. + +GDB always considers the contents of an ordinary register as an integer +when the register is examined in this way. Some machines have special +registers which can hold nothing but floating point; these registers are +considered floating point. There is no way to refer to the contents of an +ordinary register as floating point value (although you can @@emph{print} +it as a floating point value with @@samp{print/f $@@var{regname}}). + +Some registers have distinct ``raw'' and ``virtual'' data formats. This +means that the data format in which the register contents are saved by the +operating system is not the same one that your program normally sees. For +example, the registers of the 68881 floating point coprocessor are always +saved in ``extended'' format, but virtually all C programs expect to work with +``double'' format. In such cases, GDB normally works with the virtual +format only (the format that makes sense for your program), but the +@@samp{info registers} command prints the data in both formats. + +Register values are relative to the selected stack frame +(@@pxref{Selection}). This means that you get the value that the register +would contain if all stack frames farther in were exited and their saved +registers restored. In order to see the real contents of all registers, +you must select the innermost frame (with @@samp{frame 0}). + +Some registers are never saved (typically those numbered zero or one) +because they are used for returning function values; for these registers, +relativization makes no difference. + +@@table @@code +@@item info registers +@@kindex info registers +Print the names and relativized values of all registers. + +@@item info registers @@var{regname} +Print the relativized value of register @@var{regname}. @@var{regname} +may be any register name valid on the machine you are using, with +or without the initial @@samp{$}. +@@end table + +@@subsection Examples + +You could print the program counter in hex with + +@@example +p/x $pc +@@end example + +@@noindent +or print the instruction to be executed next with + +@@example +x/i $pc +@@end example + +@@noindent +or add four to the stack pointer with + +@@example +set $sp += 4 +@@end example + +@@noindent +The last is a way of removing one word from the stack, on machines where +stacks grow downward in memory (most machines, nowadays). This assumes +that the innermost stack frame is selected. Setting @@samp{$sp} is +not allowed when other stack frames are selected. + +@@node Symbols, Altering, Data, Top +@@chapter Examining the Symbol Table + +The commands described in this section allow you to make inquiries for +information about the symbols (names of variables, functions and types) +defined in your program. This information is found by GDB in the symbol +table loaded by the @@samp{symbol-file} command; it is inherent in the text +of your program and does not change as the program executes. + +@@table @@code +@@item whatis @@var{exp} +@@kindex whatis +Print the data type of expression @@var{exp}. @@var{exp} is not +actually evaluated, and any side-effecting operations (such as +assignments or function calls) inside it do not take place. +@@xref{Expressions}. + +@@item whatis +Print the data type of @@samp{$}, the last value in the value history. + +@@item info address @@var{symbol} +@@kindex info address +Describe where the data for @@var{symbol} is stored. For register +variables, this says which register. For other automatic variables, +this prints the stack-frame offset at which the variable is always +stored. Note the contrast with @@samp{print &@@var{symbol}}, which does +not work at all for register variables and for automatic variables +prints the exact address of the current instantiation of the variable. + +@@item ptype @@var{typename} +@@kindex ptype +Print a description of data type @@var{typename}. @@var{typename} may be +the name of a type, or for C code it may have the form +@@samp{struct @@var{struct-tag}}, @@samp{union @@var{union-tag}} or +@@samp{enum @@var{enum-tag}}.@@refill + +@@item info sources +@@kindex info sources +Print the names of all source files in the program for which there +is debugging information. + +@@item info functions +@@kindex info functions +Print the names and data types of all defined functions. + +@@item info functions @@var{regexp} +Print the names and data types of all defined functions +whose names contain a match for regular expression @@var{regexp}. +Thus, @@samp{info fun step} finds all functions whose names +include @@samp{step}; @@samp{info fun ^step} finds those whose names +start with @@samp{step}. + +@@item info variables +@@kindex info variables +Print the names and data types of all variables that are declared +outside of functions. + +@@item info variables @@var{regexp} +Print the names and data types of all variables, declared outside of +functions, whose names contain a match for regular expression +@@var{regexp}. + +@@item info types +@@kindex info types +Print all data types that are defined in the program. + +@@item info types @@var{regexp} +Print all data types that are defined in the program whose names +contain a match for regular expression @@var{regexp}. + +@@item info methods +@@item info methods @@var{regexp} +@@kindex info methods +The @@samp{info-methods} command permits the user to examine all defined +methods within C@@code{++} program, or (with the @@var{regexp} argument) a +specific set of methods found in the various C@@code{++} classes. Many +C@@code{++} classes which implement a large number of differently typed +methods implement a large number of methods as well. Thus, the +@@samp{ptype} command can give the user a tremendous overdose of +information about what methods are associated with a given class. The +@@samp{info-methods} command filters these methods do to only those +methods which match the regular-expression search key. + +@@item printsyms @@var{filename} +@@kindex printsyms +Write a complete dump of the debugger's symbol data into the +file @@var{filename}. +@@end table + +@@node Altering, Sequences, Symbols, Top +@@chapter Altering Execution + +There are several ways to alter the execution of your program with GDB +commands. + +@@menu +* Assignment:: Altering variable values or memory contents. +* Jumping:: Altering control flow. +* Signaling:: Making signals happen in the program. +* Returning:: Making a function return prematurely. +@@end menu + +@@node Assignment, Jumping, Altering, Altering +@@section Assignment to Variables + +@@cindex assignment +@@cindex setting variables +To alter the value of a variable, evaluate an assignment expression. +@@xref{Expressions}. For example, + +@@example +print x=4 +@@end example + +@@noindent +would store the value 4 into the variable @@code{x}, and then print +the value of the assignment expression (which is 4). + +@@kindex set +@@kindex set variable +If you are not interested in seeing the value of the assignment, use the +@@samp{set} command instead of the @@samp{print} command. @@samp{set} is +really the same as @@samp{print} except that the expression's value is not +printed and is not put in the value history (@@pxref{Value History}). The +expression is evaluated only for side effects. + +Note that if the beginning of the argument string of the @@samp{set} command +appears identical to a @@samp{set} subcommand, it may be necessary to use +the @@samp{set variable} command. This command is identical to @@samp{set} +except for its lack of subcommands. + +GDB allows more implicit conversions in assignments than C does; you can +freely store an integer value into a pointer variable or vice versa, and +any structure can be converted to any other structure that is the same +length or shorter. + +In C, all the other assignment operators such as @@samp{+=} and @@samp{++} +are supported as well. + +To store into arbitrary places in memory, use the @@samp{@@{@@dots{}@@}} +construct to generate a value of specified type at a specified address +(@@pxref{Expressions}). For example, + +@@example +set @@{int@@}0x83040 = 4 +@@end example + +@@node Jumping, Signaling, Assignment, Altering +@@section Continuing at a Different Address + +@@table @@code +@@item jump @@var{linenum} +@@kindex jump +Resume execution at line number @@var{linenum}. Execution may stop +immediately if there is a breakpoint there. + +The @@samp{jump} command does not change the current stack frame, or +the stack pointer, or the contents of any memory location or any +register other than the program counter. If line @@var{linenum} is in +a different function from the one currently executing, the results may +be wild if the two functions expect different patterns of arguments or +of local variables. For this reason, the @@samp{jump} command requests +confirmation if the specified line is not in the function currently +executing. However, even wild results are predictable based on +changing the program counter. + +@@item jump *@@var{address} +Resume execution at the instruction at address @@var{address}. +@@end table + +A similar effect can be obtained by storing a new value into the register +@@samp{$pc}, but not exactly the same. + +@@example +set $pc = 0x485 +@@end example + +@@noindent +specifies the address at which execution will resume, but does not resume +execution. That does not happen until you use the @@samp{cont} command or a +stepping command (@@pxref{Stepping}). + +@@node Signaling, Returning, Jumping, Altering +@@section Giving the Program a Signal + +@@table @@code +@@item signal @@var{signalnum} +@@kindex signal +Resume execution where the program stopped, but give it immediately +the signal number @@var{signalnum}. + +Alternatively, if @@var{signalnum} is zero, continue execution and give +no signal. This is useful when the program has received a signal +but you don't want the program to see that signal; the @@samp{cont} command +would signal the program. +@@end table + +@@node Returning,, Signaling, Altering +@@section Returning from a Function + +@@cindex returning from a function +@@kindex return +You can make any function call return immediately, using the @@samp{return} +command. + +First select the stack frame that you wish to return from +(@@pxref{Selection}). Then type the @@samp{return} command. If you wish to +specify the value to be returned, give that as an argument. + +This pops the selected stack frame (and any other frames inside of it), +leaving its caller as the innermost remaining frame. That frame becomes +selected. The specified value is stored in the registers used for +returning values of functions. + +The @@samp{return} command does not resume execution; it leaves the program +stopped in the state that would exist if the function had just returned. +Contrast this with the @@samp{finish} command (@@pxref{Stepping}), which +resumes execution @@i{until} the selected stack frame returns naturally. + +@@node Sequences, Emacs, Altering, Top +@@chapter Canned Sequences of Commands + +GDB provides two ways to store sequences of commands for execution as a +unit: user-defined commands and command files. + +@@menu +* Define:: User-defined commands. +* Command Files:: Command files. +* Output:: Controlled output commands useful in + user-defined commands and command files. +@@end menu + +@@node Define, Command Files, Sequences, Sequences +@@section User-Defined Commands + +@@cindex user-defined commands +A @@dfn{user-defined command} is a sequence of GDB commands to which you +assign a new name as a command. This is done with the @@samp{define} +command. + +@@table @@code +@@item define @@var{commandname} +@@kindex define +Define a command named @@var{commandname}. If there is already a command +by that name, you are asked to confirm that you want to redefine it. + +The definition of the command is made up of other GDB command lines, +which are given following the @@samp{define} command. The end of these +commands is marked by a line containing @@samp{end}. + +@@item document @@var{commandname} +@@kindex document +Give documentation to the user-defined command @@var{commandname}. The +command @@var{commandname} must already be defined. This command reads +lines of documentation just as @@samp{define} reads the lines of the +command definition, ending with @@samp{end}. After the @@samp{document} command is finished, +@@samp{help} on command @@var{commandname} will print the documentation +you have specified. + +You may use the @@samp{document} command again to change the +documentation of a command. Redefining the command with @@samp{define} +does not change the documentation. +@@end table + +User-defined commands do not take arguments. When they are executed, the +commands of the definition are not printed. An error in any command +stops execution of the user-defined command. + +Commands that would ask for confirmation if used interactively proceed +without asking when used inside a user-defined command. Many GDB commands +that normally print messages to say what they are doing omit the messages +when used in user-defined command. + +@@node Command Files, Output, Define, Sequences +@@section Command Files + +@@cindex command files +A command file for GDB is a file of lines that are GDB commands. Comments +(lines starting with @@samp{#}) may also be included. An empty line in a +command file does nothing; it does not mean to repeat the last command, as +it would from the terminal. + +@@cindex init file +@@cindex .gdbinit +When GDB starts, it automatically executes its @@dfn{init files}, command +files named @@file{.gdbinit}. GDB reads the init file (if any) in your home +directory and then the init file (if any) in the current working +directory. (The init files are not executed if the @@samp{-nx} option +is given.) You can also request the execution of a command file with the +@@samp{source} command: + +@@table @@code +@@item source @@var{filename} +@@kindex source +Execute the command file @@var{filename}. +@@end table + +The lines in a command file are executed sequentially. They are not +printed as they are executed. An error in any command terminates execution +of the command file. + +Commands that would ask for confirmation if used interactively proceed +without asking when used in a command file. Many GDB commands that +normally print messages to say what they are doing omit the messages +when used in a command file. + +@@node Output,, Command Files, Sequences +@@section Commands for Controlled Output + +During the execution of a command file or a user-defined command, the only +output that appears is what is explicitly printed by the commands of the +definition. This section describes three commands useful for generating +exactly the output you want. + +@@table @@code +@@item echo @@var{text} +@@kindex echo +Print @@var{text}. Nonprinting characters can be included in +@@var{text} using C escape sequences, such as @@samp{\n} to print a +newline. @@b{No newline will be printed unless you specify one.} + +A backslash at the end of @@var{text} is ignored. It is useful for +outputting a string ending in spaces, since trailing spaces are +trimmed from all arguments. A backslash at the beginning preserves +leading spaces in the same way, because @@samp{\ } as an escape +sequence stands for a space. Thus, to print @@samp{ and foo = }, do + +@@example +echo \ and foo = \ +@@end example + +@@item output @@var{expression} +@@kindex output +Print the value of @@var{expression} and nothing but that value: no +newlines, no @@samp{$@@var{nn} = }. The value is not entered in the +value history either. @@xref{Expressions} for more information +on expressions. + +@@item output/@@var{fmt} @@var{expression} +Print the value of @@var{expression} in format @@var{fmt}. +@@xref{Formats}, for more information. + +@@item printf @@var{string}, @@var{expressions}@@dots{} +@@kindex printf +Print the values of the @@var{expressions} under the control of +@@var{string}. The @@var{expressions} are separated by commas and may +be either numbers or pointers. Their values are printed as specified +by @@var{string}, exactly as if the program were to execute + +@@example +printf (@@var{string}, @@var{expressions}@@dots{}); +@@end example + +For example, you can print two values in hex like this: + +@@example +printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo +@@end example + +The only backslash-escape sequences that you can use in the string are +the simple ones that consist of backslash followed by a letter. +@@end table + +@@node Emacs, Remote, Sequences, Top +@@chapter Using GDB under GNU Emacs + +A special interface allows you to use GNU Emacs to view (and +edit) the source files for the program you are debugging with +GDB. + +To use this interface, use the command @@kbd{M-x gdb} in Emacs. +Give the executable file you want to debug as an argument. This +command starts a GDB process as a subprocess of Emacs, with input +and output through a newly created Emacs buffer. + +Using this GDB process is just like using GDB normally except for two things: + +@@itemize @@bullet +@@item +All ``terminal'' input and output goes through the Emacs buffer. This +applies both to GDB commands and their output, and to the input and +output done by the program you are debugging. + +This is useful because it means that you can copy the text of previous +commands and input them again; you can even use parts of the output +in this way. + +All the facilities of Emacs's Shell mode are available for this purpose. + +@@item +GDB displays source code through Emacs. Each time GDB displays a +stack frame, Emacs automatically finds the source file for that frame +and puts an arrow (@@samp{=>}) at the left margin of the current line. + +Explicit GDB @@samp{list} or search commands still produce output as +usual, but you probably will have no reason to use them. +@@end itemize + +In the GDB I/O buffer, you can use these special Emacs commands: + +@@table @@kbd +@@item M-s +Execute to another source line, like the GDB @@samp{step} command. + +@@item M-n +Execute to next source line in this function, skipping all function +calls, like the GDB @@samp{next} command. + +@@item M-i +Execute one instruction, like the GDB @@samp{stepi} command. + +@@item M-u +Move up one stack frame (and display that frame's source file in +Emacs), like the GDB @@samp{up} command. + +@@item M-d +Move down one stack frame (and display that frame's source file in +Emacs), like the GDB @@samp{down} command. (This means that you cannot +delete words in the usual fashion in the GDB buffer; I am guessing you +won't often want to do that.) + +@@item C-c C-f +Execute until exit from the selected stack frame, like the GDB +@@samp{finish} command. +@@end table + +In any source file, the Emacs command @@kbd{C-x SPC} (@@code{gdb-break}) +tells GDB to set a breakpoint on the source line point is on. + +The source files displayed in Emacs are in ordinary Emacs buffers +which are visiting the source files in the usual way. You can edit +the files with these buffers if you wish; but keep in mind that GDB +communicates with Emacs in terms of line numbers. If you add or +delete lines from the text, the line numbers that GDB knows will cease +to correspond properly to the code. + +@@node Remote, Commands, Emacs, Top +@@chapter Remote Kernel Debugging + +GDB has a special facility for debugging a remote machine via a serial +connection. This can be used for kernel debugging. + +The program to be debugged on the remote machine needs to contain a +debugging device driver which talks to GDB over the serial line using the +protocol described below. The same version of GDB that is used ordinarily +can be used for this. + +@@menu +* Remote Commands:: Commands used to start and finish remote debugging. +@@end menu + +For details of the communication protocol, see the comments in the GDB +source file @@file{remote.c}. + +@@node Remote Commands,, Remote, Remote +@@section Commands for Remote Debugging + +To start remote debugging, first run GDB and specify as an executable file +the program that is running in the remote machine. This tells GDB how +to find the program's symbols and the contents of its pure text. Then +establish communication using the @@samp{attach} command with a device +name rather than a pid as an argument. For example: + +@@example +attach /dev/ttyd +@@end example + +@@noindent +if the serial line is connected to the device named @@file{/dev/ttyd}. This +will stop the remote machine if it is not already stopped. + +Now you can use all the usual commands to examine and change data and to +step and continue the remote program. + +To resume the remote program and stop debugging it, use the @@samp{detach} +command. + +@@node Commands, Concepts, Remote, Top +@@unnumbered Command Index + +@@printindex ky + +@@node Concepts,, Commands, Top +@@unnumbered Concept Index + +@@printindex cp + +@@contents +@@bye +@ + + +1.1 +log +@Initial revision +@ +text +@d617 3 +a619 2 +inferior. If you wish to evaluate a function simply for it's side +affects, you may use the @@samp{set} command. @@xref{Assignment}. +d1101 4 +a1104 3 +A condition is just a boolean expression in your programming language. +A breakpoint with a condition evaluates the expression each time the +program reaches it, and the program stops only if the condition is true. +d1126 1 +d1259 6 +a1264 5 +is a condition expression that will change @@code{x} as needed, then always +have the value 0 so the program will not stop. Loss of input is avoided +here because break conditions are evaluated without changing the terminal +modes. When you want to have nontrivial conditions for performing the side +effects, the operators @@samp{&&}, @@samp{||} and @@samp{?@@: @@dots{} :@@:} may be useful. +d1269 3 +a1271 3 +Under Unix, breakpoints cannot be used in a program if any other process +is running that program. Attempting to run or continue the program with +a breakpoint in this case will cause GDB to stop it. +d1875 2 +d2047 2 +a2048 1 +address of a byte of memory. +d2196 1 +a2196 1 +each time the program stops. +d2382 1 +a2382 1 +saved in ``extended'' format, but all C programs expect to work with +d2451 1 +d2544 1 +a2544 1 +For example, +d2628 3 +a2630 3 +no signal. This may be useful when the program has received a signal +and the @@samp{cont} command would allow the program to see that +signal. +d2691 1 +a2691 1 +command definition. After the @@samp{document} command is finished, +d2771 2 +a2772 1 +value history either. +@ diff --git a/gdb/RCS/gdbcore.h,v b/gdb/RCS/gdbcore.h,v new file mode 100644 index 0000000..872e5af --- /dev/null +++ b/gdb/RCS/gdbcore.h,v @@ -0,0 +1,105 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.02.09.23.23.12; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.09.22.43.14; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Create gdbcore.h with external variables that relate to core files. +@ +text +@/* Machine independent variables that describe the core file under GDB. + Copyright (C) 1986, 1987, 1989 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! +*/ + +/* 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; +@ + + +1.1 +log +@Initial revision +@ +text +@d1 68 +@ diff --git a/gdb/RCS/inflow.c,v b/gdb/RCS/inflow.c,v new file mode 100644 index 0000000..972b615 --- /dev/null +++ b/gdb/RCS/inflow.c,v @@ -0,0 +1,636 @@ +head 1.3; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.3 +date 89.03.27.20.12.35; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.02.09.23.23.40; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.09.22.28.04; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.3 +log +@General portability changes. Make various local terminal control +parameter processing #ifdef the particular IOCTL used to get them. +This handles various Sys V/Berkeley merges. Also avoid vfork +and . +@ +text +@/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 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! +*/ +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_TERMIO +#include +#undef TIOCGETP +#define TIOCGETP TCGETA +#undef TIOCSETN +#define TIOCSETN TCSETA +#undef TIOCSETP +#define TIOCSETP TCSETAF +#define TERMINAL struct termio +#else +#include +#include +#include +#define TERMINAL struct sgttyb +#endif + +#ifdef SET_STACK_LIMIT_HUGE +#include +#include +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; + +#ifdef TIOCGETC +static struct tchars tc_inferior; +static struct tchars tc_ours; +#endif + +#ifdef TIOCGLTC +static struct ltchars ltc_inferior; +static struct ltchars ltc_ours; +#endif /* TIOCGLTC */ + +#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; + +#ifdef TIOCGETC + 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); +#ifdef TIOCGETC + 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. */ + int (*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); + +#ifdef TIOCGETC + 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); + +#ifdef TIOCGETC + 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 ("No terminal status when remote debugging.\n"); + return; + } + + printf ("Inferior's terminal status (currently saved by GDB):\n"); + +#ifdef HAVE_TERMIO + + printf ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n", + tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag); + printf ("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 ("c_cc: "); + for (i = 0; (i < NCC); i += 1) + printf ("0x%x ", sg_inferior.c_cc[i]); + printf ("\n"); + +#else /* not HAVE_TERMIO */ + + printf ("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 */ + +#ifdef TIOCGETC + printf ("tchars: "); + for (i = 0; i < sizeof (struct tchars); i++) + printf ("0x%x ", ((char *)&tc_inferior)[i]); + printf ("\n"); +#endif + +#ifdef TIOCGLTC + printf ("ltchars: "); + for (i = 0; i < sizeof (struct ltchars); i++) + printf ("0x%x ", ((char *)<c_inferior)[i]); + printf ("\n"); + ioctl (0, TIOCSLTC, <c_ours); +#endif + +#ifdef TIOCLGET + printf ("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); + + dup2(tty, 0); + dup2(tty, 1); + dup2(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 (); + + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + 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); + +/* 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); + } + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +static void +kill_command () +{ + if (remote_debugging) + 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 ())); +} + +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."); + + for (i = 0; ; 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); + } +} + +void +_initialize_inflow () +{ + add_com ("term-status", class_obscure, term_status_command, + "Print info on inferior's saved terminal status."); + + 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."); + + add_com ("kill", class_run, kill_command, + "Kill execution of program being debugged."); + + inferior_pid = 0; + + ioctl (0, TIOCGETP, &sg_ours); + fcntl (0, F_GETFL, tflags_ours); + +#ifdef TIOCGETC + 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; +} + +@ + + +1.2 +log +@When the inferior process dies, deselect the current frame so that +the "where" ("backtrace") command will not think there's a stack. +@ +text +@d27 1 +a27 1 +#include +a34 6 +/* May be unnecessary since many parts of inflow.c + have migrated to *-infdep.c */ +#ifdef USG +#include +#endif + +d73 1 +a73 1 +#ifdef TIOCGLTC +d76 3 +d81 3 +d86 1 +a86 1 +#endif /* TIOCGLTC */ +d117 4 +a121 1 + tc_inferior = tc_ours; +d123 3 +d127 1 +a127 1 +#endif /* TIOCGLTC */ +d150 3 +a153 1 + ioctl (0, TIOCSETC, &tc_inferior); +d155 2 +d158 1 +a158 1 +#endif /* TIOCGLTC */ +d228 3 +a231 1 + ioctl (0, TIOCGETC, &tc_inferior); +d233 2 +d236 1 +a236 1 +#endif /* TIOCGLTC */ +d253 3 +a256 1 + ioctl (0, TIOCSETC, &tc_ours); +d258 2 +d261 1 +a261 1 +#endif /* TIOCGLTC */ +d297 6 +a302 3 + printf ("fcntl flags = 0x%x, lmode = 0x%x,\nsgttyb.sg_flags = 0x%x, owner pid = %d.\n", + tflags_inferior, lmode_inferior, + sg_inferior.sg_flags, pgrp_inferior); +d307 3 +d314 2 +d317 3 +a319 1 +#endif /* not HAVE_TERMIO */ +d383 1 +a383 1 + pid = vfork (); +d385 1 +a385 1 + perror_with_name ("vfork"); +d497 3 +a500 1 + ioctl (0, TIOCGETC, &tc_ours); +d502 2 +d505 1 +a505 1 +#endif /* TIOCGLTC */ +@ + + +1.1 +log +@Initial revision +@ +text +@d418 1 +@ diff --git a/gdb/RCS/infrun.c,v b/gdb/RCS/infrun.c,v new file mode 100644 index 0000000..983922f --- /dev/null +++ b/gdb/RCS/infrun.c,v @@ -0,0 +1,1855 @@ +head 1.3; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.3 +date 89.03.27.20.15.05; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.02.09.23.25.40; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.09.17.11.52; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.3 +log +@A/UX-specific change: define X_OK since Apple fucked it up. +@ +text +@/* Start and stop the inferior process, for GDB. + Copyright (C) 1986, 1987, 1988 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! +*/ + +/* 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 "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + +#include +#include + +/* unistd.h is needed to #define X_OK */ +#ifdef USG +#include +#else +#include +#endif + +/* The idiots at Apple only define X_OK if POSIX is defined. Fuck 'em. */ +#ifndef X_OK +#define X_OK 1 /* Execute permission for access() */ +#endif + +#ifdef UMAX_PTRACE +#include +#include +#endif /* UMAX_PTRACE */ + +extern char *sys_siglist[]; +extern int errno; + +/* 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; + +/* Save register contents here when about to pop a stack dummy frame. */ + +char stop_registers[REGISTER_BYTES]; + +/* 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 remote-debugging of a machine over a serial link. */ + +void +start_remote () +{ + clear_proceed_status (); + running_in_shell = 0; + trap_expected = 0; + inferior_pid = 3; + breakpoints_inserted = 0; + mark_breakpoints_out (); + wait_for_inferior (); + normal_stop(); +} + +#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);*/ + 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; + CORE_ADDR prologue_pc; + int stop_step_resume_break; + CORE_ADDR step_resume_break_sp; + int newmisc; + int newfun_pc; + struct symbol *newfun; + struct symtab_and_line sal; + int prev_pc; + extern CORE_ADDR text_end; + + prev_pc = read_pc (); + prev_func_start = get_pc_function_start (prev_pc) + 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 (WRETCODE (w)) + printf ("\nProgram exited with code 0%o.\n", WRETCODE (w)); + else + printf ("\nProgram exited normally.\n"); + fflush (stdout); + inferior_died (); +#ifdef NO_SINGLE_STEP + one_stepped = 0; /* Clear single_step state since proc gone */ +#endif /* NO_SINGLE_STEP */ + 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; /* Clear single_step state since proc gone */ +#endif /* NO_SINGLE_STEP */ + 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 ())); +#ifdef CONVEX_PTRACE + /* pop frame stored by user-mode trap, if present */ + if (stop_pc == BREAK_TRAP_ADDR) + { + POP_FRAME; + stop_pc = read_pc () - 2; + write_register (PC_REGNUM, stop_pc); +#ifdef NPC_REGNUM + write_register (NPC_REGNUM, stop_pc + 4); +#endif + pc_changed = 0; + } + else if (stop_pc > STACK_END_ADDR) + { + POP_FRAME; + stop_pc = read_pc (); + } +#endif /* CONVEX_PTRACE */ + stop_frame_address = FRAME_FP (get_current_frame ()); + stop_sp = read_register (SP_REGNUM); + stop_func_start = + get_pc_function_start (stop_pc) + 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 +#ifndef CONVEX_PTRACE + || (breakpoints_inserted && + (stop_signal == SIGILL + || stop_signal == SIGEMT)) +#endif /* not CONVEX_PTRACE */ + || 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 */ + { + /* For condition exprs. */ + select_frame (get_current_frame (), 0); + 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; + } + } + /* 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; + } + } + } + + if (stop_signal == SIGTRAP) + random_signal + = !(stop_breakpoint || trap_expected + || stop_step_resume_break +#ifndef CONVEX_PTRACE + || (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 news800 + || (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 +#if 0 +#ifndef HAVE_REGISTER_WINDOWS + && step_resume_break_sp INNER_THAN stop_sp +#endif +#endif + ))) + { + 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 CONVEX_PTRACE + if (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) +#else + /* "stack" dummy must be in text segment for Convex Unix */ + if (stop_pc == text_end - 2) +#endif + { + stop_print_frame = 0; + stop_stack_dummy = 1; +#ifdef HP9K320 + 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 != 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); + } + + /* ==> See comments at top of file on this algorithm. <==*/ + + if (stop_pc == stop_func_start + && (stop_func_start != prev_func_start + || prologue_pc != stop_func_start + || stop_sp != prev_sp)) + { + newfun = find_pc_function (stop_pc); + /* It's a subroutine call */ + if (step_over_calls > 0 || (step_over_calls && newfun == 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 convex + /* 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_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 + { + /* 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 (!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. */ + +/* FIXME, normal_stop is ALWAYS called immediately after wait_for_inferior. + They should probably be merged into a single function, since that + would avoid numerous tests (e.g. of inferior_pid). */ + +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) + delete_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 + 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 \"unset-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 \"unset-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 (); + } + } + + /* Save the function value return registers + We might be about to restore their previous contents. */ + read_register_bytes (0, stop_registers, REGISTER_BYTES); + + if (stop_stack_dummy) + { + /* Pop the empty frame that contains the stack dummy. + POP_FRAME ends with a setting of the current frame, so we + can use that next. */ + POP_FRAME; + select_frame (get_current_frame (), 0); + } +} + +static void +insert_step_breakpoint () +{ + if (step_resume_break_address && !step_resume_break_duplicate) + { + 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 ("Number\tStop\tPrint\tPass to program\tDescription\n"); + + if (signum_exp) + { + i = parse_and_eval_address (signum_exp); + printf ("%d\t", i); + printf ("%s\t", signal_stop[i] ? "Yes" : "No"); + printf ("%s\t", signal_print[i] ? "Yes" : "No"); + printf ("%s\t\t", signal_program[i] ? "Yes" : "No"); + printf ("%s\n", sys_siglist[i]); + return; + } + + printf ("\n"); + for (i = 0; i < NSIG; i++) + { + QUIT; + if (i > 0 && i % 16 == 0) + { + printf ("[Type Return to see more]"); + fflush (stdout); + gdb_read_line (0, 0); + } + printf ("%d\t", i); + printf ("%s\t", signal_stop[i] ? "Yes" : "No"); + printf ("%s\t", signal_print[i] ? "Yes" : "No"); + printf ("%s\t\t", signal_program[i] ? "Yes" : "No"); + printf ("%s\n", sys_siglist[i]); + } + + printf ("\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; + + bcopy (stop_registers, inf_status->stop_registers, REGISTER_BYTES); + + record_selected_frame (&(inf_status->selected_frame_address), + &(inf_status->selected_level)); + return; +} + +void +restore_inferior_status (inf_status) + struct inferior_status *inf_status; +{ + FRAME fid; + int level = inf_status->selected_level; + + pc_changed = inf_status->pc_changed; + stop_signal = inf_status->stop_signal; + stop_pc = inf_status->stop_pc; + stop_frame_address = inf_status->stop_frame_address; + stop_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); + + bcopy (inf_status->stop_registers, stop_registers, REGISTER_BYTES); + + if (inf_status->restore_stack_info) + { + fid = find_relative_frame (get_current_frame (), + &level); + + if (FRAME_FP (fid) != inf_status->selected_frame_address || + level != 0) + { + 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 */ +} + +@ + + +1.2 +log +@Avoid accessing inferior process if it just exited or terminated with +a signal. Clean up stack frame stuff in that case too, so that the +various stack commands ("i frame", "up", "frame", "where") don't get +confused. +@ +text +@d137 5 +@ + + +1.1 +log +@Initial revision +@ +text +@d472 4 +d485 35 +a524 2 + pc_changed = 0; + flush_cached_frames (); +d569 1 +a569 30 + if (WIFEXITED (w)) + { + terminal_ours_for_output (); + if (WRETCODE (w)) + printf ("\nProgram exited with code 0%o.\n", WRETCODE (w)); + else + printf ("\nProgram exited normally.\n"); + fflush (stdout); + inferior_died (); + 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); + break; + } + else + { + stop_signal = WSTOPSIG (w); +d571 6 +a576 6 + /* 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. */ +d578 1 +a578 1 + if (stop_signal == SIGTRAP +d580 3 +a582 3 + || (breakpoints_inserted && + (stop_signal == SIGILL + || stop_signal == SIGEMT)) +d584 15 +a598 1 + || stop_after_attach) +d600 1 +a600 15 + 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. */ +d602 8 +a609 8 + /* 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)) +d611 9 +d621 2 +a622 11 + /* For condition exprs. */ + select_frame (get_current_frame (), 0); + 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); +d624 1 +a624 1 + write_register (NPC_REGNUM, stop_pc + 4); +d626 1 +a626 2 + pc_changed = 0; + } +d628 12 +a639 12 + /* 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; + } +d642 1 +d644 4 +a647 4 + if (stop_signal == SIGTRAP) + random_signal + = !(stop_breakpoint || trap_expected + || stop_step_resume_break +d649 2 +a650 2 + || (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) +d652 1 +a652 1 + || stop_pc == text_end - 2 +d654 6 +a659 6 + || (step_range_end && !step_resume_break_address)); + else + { + random_signal + = !(stop_breakpoint + || stop_step_resume_break +d661 2 +a662 2 + || (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) +d665 3 +a667 4 + ); + if (!random_signal) + stop_signal = SIGTRAP; + } +d669 3 +a671 2 + else + random_signal = 1; +d673 2 +a674 2 + /* For the program's own signals, act according to + the signal handling tables. */ +d676 50 +a725 19 + 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); +d727 1 +a727 7 + 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 (); +d729 20 +a748 45 + + /* 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 +d751 1 +a751 1 + && step_resume_break_sp INNER_THAN stop_sp +d754 13 +a766 20 + ))) + { + 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. */ +d769 9 +a777 2 + /* If this is the breakpoint at the end of a stack dummy, + just stop silently. */ +d779 2 +a780 2 + if (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) +d782 2 +a783 2 + /* "stack" dummy must be in text segment for Convex Unix */ + if (stop_pc == text_end - 2) +d785 3 +a787 3 + { + stop_print_frame = 0; + stop_stack_dummy = 1; +d789 1 +a789 1 + trap_expected_after_continue = 1; +d791 2 +a792 2 + break; + } +d794 22 +a815 18 + 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 != prev_sp + || stop_frame_address != step_frame_address))) +d817 2 +a818 7 + /* 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; + } +d820 1 +d822 43 +a864 43 + /* 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); + } + + /* ==> See comments at top of file on this algorithm. <==*/ + + if (stop_pc == stop_func_start + && (stop_func_start != prev_func_start + || prologue_pc != stop_func_start + || stop_sp != prev_sp)) + { + newfun = find_pc_function (stop_pc); + /* It's a subroutine call */ + if (step_over_calls > 0 || (step_over_calls && newfun == 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. */ +d866 2 +a867 2 + /* no, don't either. It skips any code that's + legitimately on the first line. */ +d869 2 +a870 2 + if (sal.end && sal.pc != stop_func_start) + stop_func_start = sal.end; +d872 6 +a877 24 + + 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; + } +d880 1 +d882 13 +a894 7 + /* 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; +a896 1 + /* No subroutince call; stop now. */ +d899 5 +d908 6 +d983 4 +d993 2 +a994 1 + (get_current_frame ())->pc = read_pc (); +@ diff --git a/gdb/RCS/m-aux.h,v b/gdb/RCS/m-aux.h,v new file mode 100644 index 0000000..2bf0702 --- /dev/null +++ b/gdb/RCS/m-aux.h,v @@ -0,0 +1,591 @@ +head 1.4; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.4 +date 89.04.26.00.51.42; author gnu; state Exp; +branches ; +next 1.3; + +1.3 +date 89.03.27.20.16.05; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.03.26.20.13.28; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.13.19.16.52; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.4 +log +@(1) Defined the big-endianness of the target machine. +(2) Define float to be IEEE compatible. +(3) Define invalid floats to be NaNs. +@ +text +@/* Parameters for execution on A/UX, for GDB, the GNU debugger. + Copyright (C) 1989 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! +*/ + +#ifndef aux +#define aux +#endif + +/* It's a USG system */ +#define USG + +/* Assembler instructions in USG "SGS" (sw generation system) format */ +#define USG_SGS_ASM + +/* Debugger information will be in COFF format. */ +#define COFF_FORMAT +#define COFF_NO_LONG_FILE_NAMES + +/* Terminal interface via termio */ +#define HAVE_TERMIO + +/* Unisoft fucked up the include files */ +#define UNISOFT_ASSHOLES + +/* Big or Little-Endian target machine + BITS: defined if bit #0 is the high-order bit of a byte. + BYTES:defined if byte#0 is the high-order byte of an int. + WORDS:defined if word#0 is the high-order word of a double. */ +#define BITS_BIG_ENDIAN +#define BYTES_BIG_ENDIAN +#define WORDS_BIG_ENDIAN + +/* Floating point is IEEE compatible */ +#define IEEE_FLOAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) \ +{ register int op = read_memory_integer (pc, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ +} + +/* Immediately after a function call, return the saved pc. + Can't 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) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x20000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ +/* A/UX uses "trap &1" */ + +#define BREAKPOINT {0x4e, 0x41} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#define DECR_PC_AFTER_BREAK 0 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75) + +/* Return 1 if P points to an invalid floating point value. */ +/* FIXME, it's not clear what "invalid" means here. I take it to mean + "something that coredumps gdb if gdb tries to manipulate it" */ + +#define INVALID_FLOAT(p, len) is_nan(p, len) + +/* 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 29 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "ps", "pc", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr" } + +/* 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 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PS_REGNUM 16 /* Contains processor status */ +#define PC_REGNUM 17 /* Contains program counter */ +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ + +/* This is a piece of magic that is given a register number REGNO + and as BLOCKEND the address in the system of the end of the user structure + and stores in ADDR the address in the kernel or core dump + of that register. */ + +#define REGISTER_U_ADDR(addr, blockend, regno) { \ + struct user u; \ + if (regno <= SP_REGNUM) \ + addr = blockend + regno * 4; \ + else if (regno == PS_REGNUM) \ + addr = blockend + RPS * 4; /* From reg.h */ \ + else if (regno == PC_REGNUM) \ + addr = blockend + PC * 4; /* From reg.h */ \ + else if (regno < FPC_REGNUM) \ + addr = (char *) u.u_fpdreg [regno-FP0_REGNUM] - (char *)&u; \ + else \ + addr = (char *)&u.u_fpsysreg[regno-FPC_REGNUM] - (char *)&u; \ +} + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8*12+8+20) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 12 bytes. */ +/* Note that the unsigned cast here forces the result of the + subtractiion to very high positive values if N < FP0_REGNUM */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 8-byte doubles. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 12 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_from_68881 ((FROM), (TO)); \ + else \ + 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) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_to_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : 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) \ + { write_register (9, (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. */ + +/* In the case of the 68k, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#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) + +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +#if 0 +#define FRAME_NUM_ARGS(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } +#endif + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + int nextinsn; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info)->pc); \ + /* Verify we have a link a6 instruction next; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ + if (044016 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \ + else if (047126 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \ + else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + regmask = read_memory_integer (pc + 2, 2); \ + /* But before that can come an fmovem. Check for it. */ \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf227 == nextinsn \ + && (regmask & 0xff00) == 0xe000) \ + { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 12); \ + regmask = read_memory_integer (pc + 2, 2); } \ + if (0044327 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 0, the first written */ \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \ + else if (0044347 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) \ + { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* fmovemx to index of sp may follow. */ \ + regmask = read_memory_integer (pc + 2, 2); \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf236 == nextinsn \ + && (regmask & 0xff00) == 0xf000) \ + { pc += 10; /* Regmask's low bit is for register fp0, the first written */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \ + regmask = read_memory_integer (pc + 2, 2); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (0x426742e7 == read_memory_integer (pc, 4)) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 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 sequence of words is the instructions + fmovem 0xff,-(sp) + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @@#32323232 + addl #69696969,sp + trap #15 + nop +Note this is 28 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* 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 *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } + +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movel #end, sp"); \ + asm ("movel #0,a6"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel a6,sp@@-"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl sp@@,a6"); + +/* 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 \ +{ asm ("clrw -(sp)"); \ + asm ("pea sp@@(10)"); \ + asm ("movem #0xfffe,sp@@-"); } + +/* 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 \ +{ asm ("subil #8,sp@@(28)"); \ + asm ("movem sp@@,#0xffff"); \ + asm ("rte"); } +@ + + +1.3 +log +@Fix DECR_PC_AFTER_BREAK; A/UX reports breaks at the breakpoint addr, +not there+2. +@ +text +@d41 11 +d100 2 +d103 1 +a103 1 +#define INVALID_FLOAT(p, len) 1 /* FIXME! Just a first guess; not checked */ +@ + + +1.2 +log +@Mostly works! +@ +text +@d82 1 +a82 1 +#define DECR_PC_AFTER_BREAK 2 +@ + + +1.1 +log +@Initial revision +@ +text +@d1 504 +@ diff --git a/gdb/RCS/m-hp9k320.h,v b/gdb/RCS/m-hp9k320.h,v new file mode 100644 index 0000000..8df1709 --- /dev/null +++ b/gdb/RCS/m-hp9k320.h,v @@ -0,0 +1,607 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.03.27.20.17.11; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.20.19.29.58; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Change "HPUX_ASM" define to "USG_SGS_ASM", since it's really the USG +Software Generation System assembler that we're fighting here. +., +@ +text +@/* Parameters for execution on an HP 9000 model 320, for GDB, the GNU debugger. + Copyright (C) 1986, 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! +*/ + +#ifndef HP9K320 +#define HP9K320 +#endif + +/* Set flag to indicate whether HP's assembler is in use. */ +#ifdef __GNU__ +#ifdef __HPUX_ASM__ +#define USG_SGS_ASM +#endif +#else +#define USG_SGS_ASM +#endif + +/* Define this for versions of hp-ux older than 6.0 */ +/* #define HPUX_VERSION_5 */ + +/* define USG if you are using sys5 /usr/include's */ +#define USG + +#define HAVE_TERMIO + +/* 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 + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) \ +{ register int op = read_memory_integer (pc, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ +} + +/* Immediately after a function call, return the saved pc. + Can't 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 HPUX_VERSION_5 +#define KERNEL_U_ADDR 0x00979000 +#else +#define KERNEL_U_ADDR 0x00C01000 +#endif + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xFFF00000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x41} + +/* 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 2 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* 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 29 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "ps", "pc", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr" } + +/* 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 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PS_REGNUM 16 /* Contains processor status */ +#define PC_REGNUM 17 /* Contains program counter */ +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8*12+8+12) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 12 bytes. */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 8-byte doubles. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 12 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_from_68881 ((FROM), (TO)); \ + else \ + 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) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_to_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : 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) \ + { write_register (9, (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)) + +#define REGISTER_ADDR(u_ar0, regno) \ + (((regno) < PS_REGNUM) \ + ? (&((struct exception_stack *) (u_ar0))->e_regs[(regno + R0)]) \ + : (((regno) == PS_REGNUM) \ + ? ((int *) (&((struct exception_stack *) (u_ar0))->e_PS)) \ + : (&((struct exception_stack *) (u_ar0))->e_PC))) + +#define FP_REGISTER_ADDR(u, regno) \ + (((char *) \ + (((regno) < FPC_REGNUM) \ + ? (&u.u_pcb.pcb_mc68881[FMC68881_R0 + (((regno) - FP0_REGNUM) * 3)]) \ + : (&u.u_pcb.pcb_mc68881[FMC68881_C + ((regno) - FPC_REGNUM)]))) \ + - ((char *) (& u))) + +/* It is safe to look for symsegs on a Sun, because Sun's ld + does not screw up with random garbage at end of file. */ + +#define READ_GDB_SYMSEGS + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +/* In the case of the Sun, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#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) + +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +#if 0 +#define FRAME_NUM_ARGS(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } +#endif + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + int nextinsn; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info)->pc); \ + /* Verify we have a link a6 instruction next; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ + if (044016 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \ + else if (047126 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \ + else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + regmask = read_memory_integer (pc + 2, 2); \ + /* But before that can come an fmovem. Check for it. */ \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf227 == nextinsn \ + && (regmask & 0xff00) == 0xe000) \ + { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 12); \ + regmask = read_memory_integer (pc + 2, 2); } \ + if (0044327 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 0, the first written */ \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \ + else if (0044347 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \ + { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* fmovemx to index of sp may follow. */ \ + regmask = read_memory_integer (pc + 2, 2); \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf236 == nextinsn \ + && (regmask & 0xff00) == 0xf000) \ + { pc += 10; /* Regmask's low bit is for register fp0, the first written */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \ + regmask = read_memory_integer (pc + 2, 2); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (0x426742e7 == read_memory_integer (pc, 4)) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 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 sequence of words is the instructions + fmovem 0xff,-(sp) + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @@#32323232 + addl #69696969,sp + bpt + nop +Note this is 28 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e414e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* 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 *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } + +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +#ifndef HPUX_ASM + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movel $ end, sp"); \ + asm ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } + +/* 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 \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } + +#else /* HPUX_ASM */ + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm ("global end"); \ + asm ("mov.l &end,%sp"); \ + asm ("clr.l %a6"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("mov.l %fp,-(%sp)"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("mov.l (%sp),%fp"); + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS \ +{ asm ("clr.w -(%sp)"); \ + asm ("pea 10(%sp)"); \ + asm ("movm.l &0xfffe,-(%sp)"); } + +/* 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 \ +{ asm ("subi.l &8,28(%sp)"); \ + asm ("mov.m (%sp),&0xffff"); \ + asm ("rte"); } + +#endif /* HPUX_ASM */ +@ + + +1.1 +log +@Initial revision +@ +text +@d28 1 +a28 1 +#define HPUX_ASM +d31 1 +a31 1 +#define HPUX_ASM +@ diff --git a/gdb/RCS/m-sparc.h,v b/gdb/RCS/m-sparc.h,v new file mode 100644 index 0000000..1720dfe --- /dev/null +++ b/gdb/RCS/m-sparc.h,v @@ -0,0 +1,747 @@ +head 1.3; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.3 +date 89.04.26.00.52.29; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.03.16.21.10.29; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.14.15.28.32; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.3 +log +@(1) Define big-endianness of SPARC. +(2) Define IEEE compatible float. +@ +text +@/* Parameters for execution on a Sun 4, for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@@mcc.com) + +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! +*/ + +#ifndef sun4 +#define sun4 +#endif + +/* 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 + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* Big or Little-Endian target machine + BITS: defined if bit #0 is the high-order bit of a byte. + BYTES:defined if byte#0 is the high-order byte of an int. + WORDS:defined if word#0 is the high-order word of a double. */ +#define BITS_BIG_ENDIAN +#define BYTES_BIG_ENDIAN +#define WORDS_BIG_ENDIAN + +/* Floating point is IEEE compatible. */ +#define IEEE_FLOAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) \ + { pc = skip_prologue (pc); } + +/* Immediately after a function call, return the saved pc. + Can't go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +/* On the Sun 4 under SunOS, the compile will leave a fake insn which + encodes the structure size being returned. If we detect such + a fake insn, step past it. */ + +#define PC_ADJUST(pc) ((read_memory_integer (pc + 8, 4) & 0xfffffe00) == 0 ? \ + pc+12 : pc+8) + +#define SAVED_PC_AFTER_CALL(frame) PC_ADJUST (read_register (RP_REGNUM)) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xf8000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Stack has strict alignment. */ + +#define STACK_ALIGN(ADDR) (((ADDR)+7)&-8) + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x91, 0xd0, 0x20, 0x01} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#define DECR_PC_AFTER_BREAK 0 + +/* Nonzero if instruction at PC is a return instruction. */ +/* For SPARC, this is either a "jmpl %o7+8,%g0" or "jmpl %i7+8,%g0". + + Note: this does not work for functions returning structures under SunOS. */ +#define ABOUT_TO_RETURN(pc) \ + ((read_memory_integer (pc, 4)|0x00040000) == 0x81c7e008) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* 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 72 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ +{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", \ + "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", \ + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", \ + "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", \ + \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \ + \ + "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" }; + +/* 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 30 /* Contains address of executing stack frame */ +#define RP_REGNUM 15 /* Contains return address value, *before* \ + any windows get switched. */ +#define SP_REGNUM 14 /* Contains address of top of stack, \ + which is also the bottom of the frame. */ +#define Y_REGNUM 64 /* Temp register for multiplication, etc. */ +#define PS_REGNUM 65 /* Contains processor status */ +#define PC_REGNUM 68 /* Contains program counter */ +#define NPC_REGNUM 69 /* Contains next PC */ +#define FP0_REGNUM 32 /* Floating point register 0 */ +#define FPS_REGNUM 70 /* Floating point status register */ +#define CPS_REGNUM 71 /* Coprocessor status register */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (32*4+32*4+8*4) + +/* Index within `registers' of the first byte of the space for + register N. */ +/* ?? */ +#define REGISTER_BYTE(N) ((N)*4) + +/* The SPARC processor has register windows. */ + +#define HAVE_REGISTER_WINDOWS + +/* Is this register part of the register window system? A yes answer + implies that 1) The name of this register will not be the same in + other frames, and 2) This register is automatically "saved" (out + registers shifting into ins counts) upon subroutine calls and thus + there is no need to search more than one stack frame for it. */ + +#define REGISTER_IN_WINDOW_P(regnum) \ + ((regnum) >= 8 && (regnum) < 32) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +/* On the SPARC, all regs are 4 bytes. */ + +#define REGISTER_RAW_SIZE(N) (4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +/* On the SPARC, all regs are 4 bytes. */ + +#define REGISTER_VIRTUAL_SIZE(N) (4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 8 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* 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) \ + ((N) < 32 ? builtin_type_int : (N) < 64 ? builtin_type_float : \ + builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { write_memory ((SP)+(16*4), &(ADDR), 4); } + +/* 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 (((int *)(REGBUF))+8, (VALBUF), TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ +/* On sparc, values are returned in register %o0. */ +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (REGISTER_BYTE (8), 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) \ + (read_memory_integer (((int *)(REGBUF))[SP_REGNUM]+(16*4), 4)) + +/* Enable use of alternate code to read and write registers. */ + +#define NEW_SUN_PTRACE + +/* Enable use of alternate code for Sun's format of core dump file. */ + +#define NEW_SUN_CORE + +/* Do implement the attach and detach commands. */ + +#define ATTACH_DETACH + +/* It is safe to look for symsegs on a Sun, because Sun's ld + does not screw up with random garbage at end of file. */ + +#define READ_GDB_SYMSEGS + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ +#include + +#define GET_RWINDOW_REG(FRAME, REG) \ + (read_memory_integer (&((struct rwindow *)FRAME)->REG, 4)) + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +/* In the case of the Sun 4, the frame-chain's nominal address + is held in the frame pointer register. + + On the Sun4, the frame (in %fp) is %sp for the previous frame. + From the previous frame's %sp, we can find the previous frame's + %fp: it is in the save area just above the previous frame's %sp. + + If we are setting up an arbitrary frame, we'll need to know where + it ends. Hence the following. This part of the frame cache + structure should be checked before it is assumed that this frame's + bottom is in the stack pointer. + + If there isn't a frame below this one, the bottom of this frame is + in the stack pointer. + + If there is a frame below this one, and the frame pointers are + identical, it's a leaf frame and the bottoms are the same also. + + Otherwise the bottom of this frame is the top of the next frame. */ + +#define EXTRA_FRAME_INFO FRAME_ADDR bottom; +#define INIT_EXTRA_FRAME_INFO(fci) \ + (fci)->bottom = \ + ((fci)->next ? \ + ((fci)->frame == (fci)->next_frame ? \ + (fci)->next->bottom : (fci)->next->frame) : \ + read_register (SP_REGNUM)); + +#define FRAME_CHAIN(thisframe) \ + GET_RWINDOW_REG ((thisframe)->frame, rw_in[6]) + +/* Avoid checking FRAME_SAVED_PC since that screws us due to + improperly set up saved PC on a signal trampoline call */ +#if 0 +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) +#else +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0) +#endif + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* Where is the PC for a specific frame */ + +#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME) + +/* If the argument is on the stack, it will be here. */ +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_STRUCT_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 68 + +/* 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. + + Note that on register window machines, we are currently making the + assumption that window registers are being saved somewhere in the + frame in which they are being used. If they are stored in an + inferior frame, find_saved_register will break. + + On the Sun 4, the only time all registers are saved is when + a dummy frame is involved. Otherwise, the only saved registers + are the LOCAL and IN registers which are saved as a result + of the "save/restore" opcodes. This condition is determined + by address rather than by value. */ + +#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \ +{ register int regnum; \ + register CORE_ADDR pc; \ + FRAME_ADDR frame = read_register (FP_REGNUM); \ + FRAME fid = FRAME_INFO_ID (fi); \ + if (!fid) fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS"); \ + bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \ + if ((fi)->pc >= frame - CALL_DUMMY_LENGTH - 0x140 \ + && (fi)->pc <= frame) \ + { \ + for (regnum = 1; regnum < 8; regnum++) \ + (frame_saved_regs).regs[regnum] = \ + frame + regnum * 4 - 0xa0; \ + for (regnum = 24; regnum < 32; regnum++) \ + (frame_saved_regs).regs[regnum] = \ + frame + (regnum - 24) * 4 - 0xc0; \ + for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++) \ + (frame_saved_regs).regs[regnum] = \ + frame + (regnum - FP0_REGNUM) * 4 - 0x80; \ + for (regnum = 64; regnum < NUM_REGS; regnum++) \ + (frame_saved_regs).regs[regnum] = \ + frame + (regnum - 64) * 4 - 0xe0; \ + frame = (fi)->bottom ? \ + (fi)->bottom : read_register (SP_REGNUM); \ + } \ + else \ + { \ + frame = (fi)->bottom ? \ + (fi)->bottom : read_register (SP_REGNUM); \ + for (regnum = 16; regnum < 32; regnum++) \ + (frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \ + } \ + if ((fi)->next) \ + { \ + /* Pull off either the next frame pointer or \ + the stack pointer */ \ + FRAME_ADDR next_next_frame = \ + ((fi)->next->bottom ? \ + (fi)->next->bottom : \ + read_register (SP_REGNUM)); \ + for (regnum = 8; regnum < 16; regnum++) \ + (frame_saved_regs).regs[regnum] = next_next_frame + regnum * 4; \ + } \ + /* Otherwise, whatever we would get from ptrace(GETREGS) */ \ + /* is accurate */ \ + for (regnum = 30; regnum < 32; regnum++) \ + (frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \ + (frame_saved_regs).regs[SP_REGNUM] = frame; \ + (frame_saved_regs).regs[PC_REGNUM] = frame + 15*4; \ +} + +/* Things needed for making the inferior call functions. */ +/* + * First of all, let me give my opinion of what the DUMMY_FRAME + * actually looks like. + * + * | | + * | | + * + - - - - - - - - - - - - - - - - +<-- fp (level 0) + * | | + * | | + * | | + * | | + * | Frame of innermost program | + * | function | + * | | + * | | + * | | + * | | + * | | + * |---------------------------------|<-- sp (level 0), fp (c) + * | | + * DUMMY | fp0-31 | + * | | + * | ------ |<-- fp - 0x80 + * FRAME | g0-7 |<-- fp - 0xa0 + * | i0-7 |<-- fp - 0xc0 + * | other |<-- fp - 0xe0 + * | ? | + * | ? | + * |---------------------------------|<-- sp' = fp - 0x140 + * | | + * xcution start | | + * sp' + 0x94 -->| CALL_DUMMY (x code) | + * | | + * | | + * |---------------------------------|<-- sp'' = fp - 0x200 + * | align sp to 8 byte boundary | + * | ==> args to fn <== | + * Room for | | + * i & l's + agg | CALL_DUMMY_STACK_ADJUST = 0x0x44| + * |---------------------------------|<-- final sp (variable) + * | | + * | Where function called will | + * | build frame. | + * | | + * | | + * + * I understand everything in this picture except what the space + * between fp - 0xe0 and fp - 0x140 is used for. Oh, and I don't + * understand why there's a large chunk of CALL_DUMMY that never gets + * executed (its function is superceeded by PUSH_DUMMY_FRAME; they + * are designed to do the same thing). + * + * PUSH_DUMMY_FRAME saves the registers above sp' and pushes the + * register file stack down one. + * + * call_function then writes CALL_DUMMY, pushes the args onto the + * stack, and adjusts the stack pointer. + * + * run_stack_dummy then starts execution (in the middle of + * CALL_DUMMY, as directed by call_function). + */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +/* Note: to be perfectly correct, we have to restore the + IN registers (which were the OUT registers of the calling frame). */ +/* Note that the write's are of registers in the context of the newly + pushed frame. Thus the the fp*'s, the g*'s, the i*'s, and + the others, of the new frame, are being saved. + The locals are new; they don't need to be saved. The i's and l's of + the last frame were saved by the do_save_insn in the register + file (ie. on the stack, since a context switch happended imm after) */ +/* We note that the return pointer register does not *need* to have + the pc saved into it (return from this frame will be accomplished + by a POP_FRAME), however, just in case it might be needed, we will + leave it. However, we will write the original value of RP into the + location on the stack for saving i7 (what rp turns into upon call); + this way we don't loose the value with our function call. */ +/* Note that the pc saved must be 8 less than the actual pc, since + both POP_FRAME and the normal return sequence on the sparc return + to 8 more than the value of RP_REGNUM */ + +#define PUSH_DUMMY_FRAME \ +{ extern char registers[]; \ + register int regnum; \ + CORE_ADDR fp = read_register (FP_REGNUM); \ + CORE_ADDR pc = read_register (PC_REGNUM) - 8; \ + CORE_ADDR rp = read_register (RP_REGNUM); \ + void do_save_insn (); \ + supply_register (RP_REGNUM, &pc); \ + do_save_insn (0x140); \ + fp = read_register (FP_REGNUM); \ + write_memory (fp - 0x80, ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * 4);\ + write_memory (fp - 0xa0, ®isters[REGISTER_BYTE (0)], 8 * 4); \ + write_memory (fp - 0xc0, ®isters[REGISTER_BYTE (24)], 7 * 4); \ + write_memory (fp - 0xa4, &rp, 4); \ + write_memory (fp - 0xe0, ®isters[REGISTER_BYTE (64)], 8 * 4); \ +} + +/* Discard from the stack the innermost frame, + restoring all saved registers. + Note that the values stored in fsr by get_frame_saved_regs are *in + the context of the inferior frame*. What this means is that the i + regs of fsr must be restored into the o regs of the frame popped + into. We don't care about the output regs of the inferior frame. + + This is true for dummy frames. Is it true for normal frames? It + really does appear so. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register CORE_ADDR pc; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + char raw_buffer[REGISTER_BYTES]; \ + void do_restore_insn (); \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + pc = read_memory_integer (fsr.regs[PC_REGNUM], 4); \ + do_restore_insn (PC_ADJUST (pc)); \ + if (fsr.regs[FP0_REGNUM]) \ + { \ + read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4); \ + write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer, 32 * 4); \ + } \ + if (fsr.regs[1]) \ + { \ + read_memory (fsr.regs[1], raw_buffer, 7 * 4); \ + write_register_bytes (REGISTER_BYTE (1), raw_buffer, 7 * 4); \ + } \ + if (fsr.regs[24]) \ + { \ + read_memory (fsr.regs[24], raw_buffer, 8 * 4); \ + write_register_bytes (REGISTER_BYTE (8), raw_buffer, 8 * 4); \ + } \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + if (fsr.regs[Y_REGNUM]) \ + write_register (Y_REGNUM, read_memory_integer (fsr.regs[Y_REGNUM], 4)); \ + if (fsr.regs[NPC_REGNUM]) \ + write_register (NPC_REGNUM, read_memory_integer (fsr.regs[NPC_REGNUM], 4)); \ + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM), \ + read_pc ())); } + +/* This sequence of words is the instructions + + save %sp,-0x140,%sp + std %f30,[%fp-0x08] + std %f28,[%fp-0x10] + std %f26,[%fp-0x18] + std %f24,[%fp-0x20] + std %f22,[%fp-0x28] + std %f20,[%fp-0x30] + std %f18,[%fp-0x38] + std %f16,[%fp-0x40] + std %f14,[%fp-0x48] + std %f12,[%fp-0x50] + std %f10,[%fp-0x58] + std %f8,[%fp-0x60] + std %f6,[%fp-0x68] + std %f4,[%fp-0x70] + std %f2,[%fp-0x78] + std %f0,[%fp-0x80] + std %g6,[%fp-0x88] + std %g4,[%fp-0x90] + std %g2,[%fp-0x98] + std %g0,[%fp-0xa0] + std %i6,[%fp-0xa8] + std %i4,[%fp-0xb0] + std %i2,[%fp-0xb8] + std %i0,[%fp-0xc0] + nop ! stcsr [%fp-0xc4] + nop ! stfsr [%fp-0xc8] + nop ! wr %npc,[%fp-0xcc] + nop ! wr %pc,[%fp-0xd0] + rd %tbr,%o0 + st %o0,[%fp-0xd4] + rd %wim,%o1 + st %o0,[%fp-0xd8] + rd %psr,%o0 + st %o0,[%fp-0xdc] + rd %y,%o0 + st %o0,[%fp-0xe0] + + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following ld instruction. *../ + + ld [%sp+0x58],%o5 + ld [%sp+0x54],%o4 + ld [%sp+0x50],%o3 + ld [%sp+0x4c],%o2 + ld [%sp+0x48],%o1 + call 0x00000000 + ld [%sp+0x44],%o0 + nop + ta 1 + nop + + note that this is 192 bytes, which is a multiple of 8 (not only 4) bytes. + note that the `call' insn is a relative, not an absolute call. + note that the `nop' at the end is needed to keep the trap from + clobbering things (if NPC pointed to garbage instead). + +We actually start executing at the `sethi', since the pushing of the +registers (as arguments) is done by PUSH_DUMMY_FRAME. If this were +real code, the arguments for the function called by the CALL would be +pushed between the list of ST insns and the CALL, and we could allow +it to execute through. But the arguments have to be pushed by GDB +after the PUSH_DUMMY_FRAME is done, and we cannot allow these ST +insns to be performed again, lest the registers saved be taken for +arguments. */ + +#define CALL_DUMMY { 0x9de3bee0, 0xfd3fbff8, 0xf93fbff0, 0xf53fbfe8, \ + 0xf13fbfe0, 0xed3fbfd8, 0xe93fbfd0, 0xe53fbfc8, \ + 0xe13fbfc0, 0xdd3fbfb8, 0xd93fbfb0, 0xd53fbfa8, \ + 0xd13fbfa0, 0xcd3fbf98, 0xc93fbf90, 0xc53fbf88, \ + 0xc13fbf80, 0xcc3fbf78, 0xc83fbf70, 0xc43fbf68, \ + 0xc03fbf60, 0xfc3fbf58, 0xf83fbf50, 0xf43fbf48, \ + 0xf03fbf40, 0x01000000, 0x01000000, 0x01000000, \ + 0x01000000, 0x91580000, 0xd027bf50, 0x93500000, \ + 0xd027bf4c, 0x91480000, 0xd027bf48, 0x91400000, \ + 0xd027bf44, 0xda03a058, 0xd803a054, 0xd603a050, \ + 0xd403a04c, 0xd203a048, 0x40000000, 0xd003a044, \ + 0x01000000, 0x91d02001, 0x01000000, 0x01000000} + +#define CALL_DUMMY_LENGTH 192 + +#define CALL_DUMMY_START_OFFSET 148 + +#define CALL_DUMMY_STACK_ADJUST 68 + +/* 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 *)((char *) dummyname+168) = (0x40000000|((fun-(pc+168))>>2)); \ + if (TYPE_CODE (type) == TYPE_CODE_STRUCT \ + || TYPE_CODE (type) == TYPE_CODE_UNION) \ + *(int *)((char *) dummyname+176) = (TYPE_LENGTH (type) & 0x1fff); \ +} + + +/* Sparc has no reliable single step ptrace call */ + +#define NO_SINGLE_STEP 1 + +/* It does have a wait structure, and it might help things out . . . */ + +#define HAVE_WAIT_STRUCT + +/* Handle a feature in the sun4 compiler ("call .stret4" at the end of + functions returning structures). */ + +#define SUN4_COMPILER_FEATURE + +/* We need two arguments (in general) to the "info frame" command. + Note that the definition of this macro implies that there exists a + function "setup_arbitrary_frame" in mach-dep.c */ + +#define FRAME_SPECIFICATION_DYADIC + +/* KDB stuff flushed for now. */ +@ + + +1.2 +log +@Don't stop the stack trace until the "next frame pointer" is zero. +@ +text +@d39 11 +@ + + +1.1 +log +@Initial revision +@ +text +@d66 1 +a66 1 +#define STACK_END_ADDR 0xff000000 +d307 3 +d312 4 +@ diff --git a/gdb/RCS/m68k-pinsn.c,v b/gdb/RCS/m68k-pinsn.c,v new file mode 100644 index 0000000..d8c7f84 --- /dev/null +++ b/gdb/RCS/m68k-pinsn.c,v @@ -0,0 +1,824 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.03.27.20.19.34; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.20.19.29.33; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Change HPUX_ASM to USG_SGS_ASM since it's really the Sys V +"Software Generation System" that we are fighting here. +@ +text +@/* Print m68k instructions for GDB, the GNU debugger. + Copyright (C) 1986, 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! +*/ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "opcode.h" + +/* 68k instructions are never longer than this many bytes. */ +#define MAXLEN 22 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0]) + +extern char *reg_names[]; +char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr", + "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"}; + +static unsigned char *print_insn_arg (); +static unsigned char *print_indexed (); +static void print_base (); +static int fetch_arg (); + +#define NEXTBYTE(p) (p += 2, ((char *)p)[-1]) + +#define NEXTWORD(p) \ + (p += 2, ((((char *)p)[-2]) << 8) + p[-1]) + +#define NEXTLONG(p) \ + (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) + +#define NEXTSINGLE(p) \ + (p += 4, *((float *)(p - 4))) + +#define NEXTDOUBLE(p) \ + (p += 8, *((double *)(p - 8))) + +#define NEXTEXTEND(p) \ + (p += 12, 0.0) /* Need a function to convert from extended to double + precision... */ + +#define NEXTPACKED(p) \ + (p += 12, 0.0) /* Need a function to convert from packed to double + precision. Actually, it's easier to print a + packed number than a double anyway, so maybe + there should be a special case to handle this... */ + +/* Print the m68k instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + register int i; + register unsigned char *p; + register char *d; + register int bestmask; + int best; + + read_memory (memaddr, buffer, MAXLEN); + + bestmask = 0; + best = -1; + for (i = 0; i < NOPCODES; i++) + { + register unsigned int opcode = m68k_opcodes[i].opcode; + register unsigned int match = m68k_opcodes[i].match; + if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) + && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) + && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) + && ((0xff & buffer[3] & match) == (0xff & opcode))) + { + /* Don't use for printout the variants of divul and divsl + that have the same register number in two places. + The more general variants will match instead. */ + for (d = m68k_opcodes[i].args; *d; d += 2) + if (d[1] == 'D') + break; + + /* Don't use for printout the variants of most floating + point coprocessor instructions which use the same + register number in two places, as above. */ + if (*d == 0) + for (d = m68k_opcodes[i].args; *d; d += 2) + if (d[1] == 't') + break; + + if (*d == 0 && match > bestmask) + { + best = i; + bestmask = match; + } + } + } + + /* Handle undefined instructions. */ + if (best < 0) + { + fprintf (stream, "0%o", (buffer[0] << 8) + buffer[1]); + return 2; + } + + fprintf (stream, "%s", m68k_opcodes[best].name); + + /* Point at first word of argument data, + and at descriptor for first argument. */ + p = buffer + 2; + + /* Why do this this way? -MelloN */ + for (d = m68k_opcodes[best].args; *d; d += 2) + { + if (d[0] == '#') + { + if (d[1] == 'l' && p - buffer < 6) + p = buffer + 6; + else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' ) + p = buffer + 4; + } + if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4) + p = buffer + 4; + if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6) + p = buffer + 6; + } + + d = m68k_opcodes[best].args; + + if (*d) + fputc (' ', stream); + + while (*d) + { + p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream); + d += 2; + if (*d && *(d - 2) != 'I' && *d != 'k') + fprintf (stream, ","); + } + return p - buffer; +} + +static unsigned char * +print_insn_arg (d, buffer, p, addr, stream) + char *d; + unsigned char *buffer; + register unsigned char *p; + CORE_ADDR addr; /* PC for this arg to be relative to */ + FILE *stream; +{ + register int val; + register int place = d[1]; + int regno; + register char *regname; + register unsigned char *p1; + register double flval; + int flt_p; + + switch (*d) + { + case 'C': + fprintf (stream, "ccr"); + break; + + case 'S': + fprintf (stream, "sr"); + break; + + case 'U': + fprintf (stream, "usp"); + break; + + case 'J': + { + static struct { char *name; int value; } names[] + = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002}, + {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802}, + {"msp", 0x803}, {"isp", 0x804}}; + + val = fetch_arg (buffer, place, 12); + for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) + if (names[regno].value == val) + { + fprintf (stream, names[regno].name); + break; + } + if (regno < 0) + fprintf (stream, "%d", val); + } + break; + + case 'Q': + val = fetch_arg (buffer, place, 3); + if (val == 0) val = 8; + fprintf (stream, "#%d", val); + break; + + case 'M': + val = fetch_arg (buffer, place, 8); + if (val & 0x80) + val = val - 0x100; + fprintf (stream, "#%d", val); + break; + + case 'T': + val = fetch_arg (buffer, place, 4); + fprintf (stream, "#%d", val); + break; + + case 'D': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]); + break; + + case 'A': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3) + 010]); + break; + + case 'R': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]); + break; + + case 'F': + fprintf (stream, "fp%d", fetch_arg (buffer, place, 3)); + break; + + case 'O': + val = fetch_arg (buffer, place, 6); + if (val & 0x20) + fprintf (stream, "%s", reg_names [val & 7]); + else + fprintf (stream, "%d", val); + break; + + case '+': + fprintf (stream, "(%s)+", reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case '-': + fprintf (stream, "-(%s)", reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case 'k': + if (place == 'k') + fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]); + else if (place == 'C') + { + val = fetch_arg (buffer, place, 7); + if ( val > 63 ) /* This is a signed constant. */ + val -= 128; + fprintf (stream, "{#%d}", val); + } + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + break; + + case '#': + p1 = buffer + 2; + if (place == 's') + val = fetch_arg (buffer, place, 4); + else if (place == 'C') + val = fetch_arg (buffer, place, 7); + else if (place == '8') + val = fetch_arg (buffer, place, 3); + else if (place == '3') + val = fetch_arg (buffer, place, 8); + else if (place == 'b') + val = NEXTBYTE (p1); + else if (place == 'w') + val = NEXTWORD (p1); + else if (place == 'l') + val = NEXTLONG (p1); + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + fprintf (stream, "#%d", val); + break; + + case '^': + if (place == 's') + val = fetch_arg (buffer, place, 4); + else if (place == 'C') + val = fetch_arg (buffer, place, 7); + else if (place == '8') + val = fetch_arg (buffer, place, 3); + else if (place == 'b') + val = NEXTBYTE (p); + else if (place == 'w') + val = NEXTWORD (p); + else if (place == 'l') + val = NEXTLONG (p); + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + fprintf (stream, "#%d", val); + break; + + case 'B': + if (place == 'b') + val = NEXTBYTE (p); + else if (place == 'w') + val = NEXTWORD (p); + else if (place == 'l') + val = NEXTLONG (p); + else if (place == 'g') + { + val = ((char *)buffer)[1]; + if (val == 0) + val = NEXTWORD (p); + else if (val == -1) + val = NEXTLONG (p); + } + else if (place == 'c') + { + if (buffer[1] & 0x40) /* If bit six is one, long offset */ + val = NEXTLONG (p); + else + val = NEXTWORD (p); + } + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + + print_address (addr + val, stream); + break; + + case 'd': + val = NEXTWORD (p); + fprintf (stream, "%d(%s)", val, reg_names[fetch_arg (buffer, place, 3)]); + break; + + case 's': + fprintf (stream, "%s", fpcr_names[fetch_arg (buffer, place, 3)]); + break; + + case 'I': + val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */ + if (val != 1) /* Unusual coprocessor ID? */ + fprintf (stream, "(cpid=%d) ", val); + if (place == 'i') + p += 2; /* Skip coprocessor extended operands */ + break; + + case '*': + case '~': + case '%': + case ';': + case '@@': + case '!': + case '$': + case '?': + case '/': + case '&': + + if (place == 'd') + { + val = fetch_arg (buffer, 'x', 6); + val = ((val & 7) << 3) + ((val >> 3) & 7); + } + else + val = fetch_arg (buffer, 's', 6); + + /* Get register number assuming address register. */ + regno = (val & 7) + 8; + regname = reg_names[regno]; + switch (val >> 3) + { + case 0: + fprintf (stream, "%s", reg_names[val]); + break; + + case 1: + fprintf (stream, "%s", regname); + break; + + case 2: + fprintf (stream, "(%s)", regname); + break; + + case 3: + fprintf (stream, "(%s)+", regname); + break; + + case 4: + fprintf (stream, "-(%s)", regname); + break; + + case 5: + val = NEXTWORD (p); + fprintf (stream, "%d(%s)", val, regname); + break; + + case 6: + p = print_indexed (regno, p, addr, stream); + break; + + case 7: + switch (val & 7) + { + case 0: + val = NEXTWORD (p); + fprintf (stream, "@@#"); + print_address (val, stream); + break; + + case 1: + val = NEXTLONG (p); + fprintf (stream, "@@#"); + print_address (val, stream); + break; + + case 2: + val = NEXTWORD (p); + print_address (addr + val, stream); + break; + + case 3: + p = print_indexed (-1, p, addr, stream); + break; + + case 4: + flt_p = 1; /* Assume it's a float... */ + switch( place ) + { + case 'b': + val = NEXTBYTE (p); + flt_p = 0; + break; + + case 'w': + val = NEXTWORD (p); + flt_p = 0; + break; + + case 'l': + val = NEXTLONG (p); + flt_p = 0; + break; + + case 'f': + flval = NEXTSINGLE(p); + break; + + case 'F': + flval = NEXTDOUBLE(p); + break; + + case 'x': + flval = NEXTEXTEND(p); + break; + + case 'p': + flval = NEXTPACKED(p); + break; + + default: + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + } + if ( flt_p ) /* Print a float? */ + fprintf (stream, "#%g", flval); + else + fprintf (stream, "#%d", val); + break; + + default: + fprintf (stream, "", val); + } + } + break; + + default: + error ("Invalid arg format in opcode table: \"%c\".", *d); + } + + return (unsigned char *) p; +} + +/* Fetch BITS bits from a position in the instruction specified by CODE. + CODE is a "place to put an argument", or 'x' for a destination + that is a general address (mode and register). + BUFFER contains the instruction. */ + +static int +fetch_arg (buffer, code, bits) + unsigned char *buffer; + char code; + int bits; +{ + register int val; + switch (code) + { + case 's': + val = buffer[1]; + break; + + case 'd': /* Destination, for register or quick. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 9; + break; + + case 'x': /* Destination, for general arg */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 6; + break; + + case 'k': + val = (buffer[3] >> 4); + break; + + case 'C': + val = buffer[3]; + break; + + case '1': + val = (buffer[2] << 8) + buffer[3]; + val >>= 12; + break; + + case '2': + val = (buffer[2] << 8) + buffer[3]; + val >>= 6; + break; + + case '3': + case 'j': + val = (buffer[2] << 8) + buffer[3]; + break; + + case '4': + val = (buffer[4] << 8) + buffer[5]; + val >>= 12; + break; + + case '5': + val = (buffer[4] << 8) + buffer[5]; + val >>= 6; + break; + + case '6': + val = (buffer[4] << 8) + buffer[5]; + break; + + case '7': + val = (buffer[2] << 8) + buffer[3]; + val >>= 7; + break; + + case '8': + val = (buffer[2] << 8) + buffer[3]; + val >>= 10; + break; + + default: + abort (); + } + + switch (bits) + { + case 3: + return val & 7; + case 4: + return val & 017; + case 5: + return val & 037; + case 6: + return val & 077; + case 7: + return val & 0177; + case 8: + return val & 0377; + case 12: + return val & 07777; + default: + abort (); + } +} + +/* Print an indexed argument. The base register is BASEREG (-1 for pc). + P points to extension word, in buffer. + ADDR is the nominal core address of that extension word. */ + +static unsigned char * +print_indexed (basereg, p, addr, stream) + int basereg; + unsigned char *p; + FILE *stream; + CORE_ADDR addr; +{ + register int word; + static char *scales[] = {"", "*2", "*4", "*8"}; + register int base_disp; + register int outer_disp; + char buf[40]; + + word = NEXTWORD (p); + + /* Generate the text for the index register. + Where this will be output is not yet determined. */ + sprintf (buf, "[%s.%c%s]", + reg_names[(word >> 12) & 0xf], + (word & 0x800) ? 'l' : 'w', + scales[(word >> 9) & 3]); + + /* Handle the 68000 style of indexing. */ + + if ((word & 0x100) == 0) + { + print_base (basereg, + ((word & 0x80) ? word | 0xff00 : word & 0xff) + + ((basereg == -1) ? addr : 0), + stream); + fprintf (stream, "%s", buf); + return p; + } + + /* Handle the generalized kind. */ + /* First, compute the displacement to add to the base register. */ + + if (word & 0200) + basereg = -2; + if (word & 0100) + buf[0] = 0; + base_disp = 0; + switch ((word >> 4) & 3) + { + case 2: + base_disp = NEXTWORD (p); + break; + case 3: + base_disp = NEXTLONG (p); + } + if (basereg == -1) + base_disp += addr; + + /* Handle single-level case (not indirect) */ + + if ((word & 7) == 0) + { + print_base (basereg, base_disp, stream); + fprintf (stream, "%s", buf); + return p; + } + + /* Two level. Compute displacement to add after indirection. */ + + outer_disp = 0; + switch (word & 3) + { + case 2: + outer_disp = NEXTWORD (p); + break; + case 3: + outer_disp = NEXTLONG (p); + } + + fprintf (stream, "%d(", outer_disp); + print_base (basereg, base_disp, stream); + + /* If postindexed, print the closeparen before the index. */ + if (word & 4) + fprintf (stream, ")%s", buf); + /* If preindexed, print the closeparen after the index. */ + else + fprintf (stream, "%s)", buf); + + return p; +} + +/* Print a base register REGNO and displacement DISP, on STREAM. + REGNO = -1 for pc, -2 for none (suppressed). */ + +static void +print_base (regno, disp, stream) + int regno; + int disp; + FILE *stream; +{ + if (regno == -2) + fprintf (stream, "%d", disp); + else if (regno == -1) + fprintf (stream, "0x%x", disp); + else + fprintf (stream, "%d(%s)", disp, reg_names[regno]); +} + +/* This is not part of insn printing, but it is machine-specific, + so this is a convenient place to put it. + + Convert a 68881 extended float to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +convert_from_68881 (from, to) + char *from; + double *to; +{ +#ifdef USG_SGS_ASM + asm ("mov.l 8(%a6),%a0"); + asm ("mov.l 12(%a6),%a1"); + asm ("fmove.x (%a0),%fp0"); + asm ("fmove.d %fp0,(%a1)"); +#else /* not USG_SGS_ASM */ +#if 0 + asm ("movl a6@@(8),a0"); + asm ("movl a6@@(12),a1"); + asm ("fmovex a0@@,fp0"); + asm ("fmoved fp0,a1@@"); +#else + /* Hand-assemble those insns since some assemblers lose + and some have different syntax. */ + asm (".word 020156"); + asm (".word 8"); + asm (".word 021156"); + asm (".word 12"); + asm (".long 0xf2104800"); + asm (".long 0xf2117400"); +#endif +#endif /* not USG_SGS_ASM */ +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. */ + +convert_to_68881 (from, to) + double *from; + char *to; +{ +#ifdef USG_SGS_ASM + asm ("mov.l 8(%a6),%a0"); + asm ("mov.l 12(%a6),%a1"); + asm ("fmove.d (%a0),%fp0"); + asm ("fmove.x %fp0,(%a1)"); +#else /* not USG_SGS_ASM */ +#if 0 + asm ("movl a6@@(8),a0"); + asm ("movl a6@@(12),a1"); + asm ("fmoved a0@@,fp0"); + asm ("fmovex fp0,a1@@"); +#else + /* Hand-assemble those insns since some assemblers lose. */ + asm (".word 020156"); + asm (".word 8"); + asm (".word 021156"); + asm (".word 12"); + asm (".long 0xf2105400"); + asm (".long 0xf2116800"); +#endif +#endif /* not USG_SGS_ASM */ +} +@ + + +1.1 +log +@Initial revision +@ +text +@d717 1 +a717 1 +#ifdef HPUX_ASM +d722 1 +a722 1 +#else /* not HPUX_ASM */ +d738 1 +a738 1 +#endif /* not HPUX_ASM */ +d748 1 +a748 1 +#ifdef HPUX_ASM +d753 1 +a753 1 +#else /* not HPUX_ASM */ +d768 1 +a768 1 +#endif /* not HPUX_ASM */ +@ diff --git a/gdb/RCS/main.c,v b/gdb/RCS/main.c,v new file mode 100644 index 0000000..1e6fafa --- /dev/null +++ b/gdb/RCS/main.c,v @@ -0,0 +1,1348 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.03.27.21.15.02; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.27.21.11.51; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Fix up "munch" so it generates a name that doesn't match its own +"grep" conventions. Change main so that it calls the new name, +and also doesn't use the conventions for functions that should NOT +be called by init.c. +@ +text +@/* Top level for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1988 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! +*/ +#include "defs.h" +#include "command.h" +#include "param.h" + +#ifdef USG +#include +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef SET_STACK_LIMIT_HUGE +#include +#include + +int original_stack_limit; +#endif + +/* 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; + +/* 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]; + +/* 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; + +void free_command_lines (); +char *gdb_read_line (); +static void init_main (); +static void init_cmd_lists (); +void command_loop (); +static void source_command (); +static void print_gdb_version (); + +/* 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 (); + delete_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; +} + + +int +main (argc, argv, envp) + int argc; + char **argv; + char **envp; +{ + extern void request_quit (); + int count; + int inhibit_gdbinit = 0; + int quiet = 0; + int batch = 0; + register int i; + + quit_flag = 0; + linesize = 100; + line = (char *) xmalloc (linesize); + 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 (argv[i][0] == '-') + i++; + } + + /* Run the init function of each source file */ + + init_cmd_lists (); /* This needs to be done first */ + init_all_files (); + init_main (); /* But that omits this file! Do it now */ + + signal (SIGINT, request_quit); + signal (SIGQUIT, SIG_IGN); + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, disconnect); + + 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")) + /* 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")) + { + int len = strlen (argv[i]); + current_directory = argv[i]; + if (len > 1 && current_directory[len - 1] == '/') + current_directory = savestring (current_directory, len-1); + chdir (current_directory); + 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) ? "" : " ..."); + } + } + } + + /* Read init file, if it exists in home directory */ + if (getenv ("HOME")) + { + char *s; + s = (char *) xmalloc (strlen (getenv ("HOME")) + 10); + strcpy (s, getenv ("HOME")); + strcat (s, "/.gdbinit"); + if (!inhibit_gdbinit && access (s, R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (s); + } + + /* Read init file, if it exists in current directory. */ + if (!inhibit_gdbinit && access (".gdbinit", R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (".gdbinit"); + + if (batch) + fatal ("Attempt to read commands from stdin in batch mode."); + + if (!quiet) + printf ("Type \"help\" for a list of commands.\n"); + + /* The command loop. */ + + while (1) + { + if (!setjmp (to_top_level)) + command_loop (); + clearerr (stdin); /* Don't get hung if C-d is typed. */ + } +} + +/* 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 (); + while (*p == ' ' || *p == '\t') p++; + if (*p) + { + c = lookup_cmd (&p, cmdlist, "", 0); + 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; + + if (*p) + error ("User-defined commands cannot take arguments."); + cmdlines = (struct command_line *) c->function; + if (cmdlines == (struct command_line *) 0) + /* Null command */ + return; + + /* Set the instream to 0, indicating execution of a + user-defined function. */ + old_chain = make_cleanup (source_cleanup, instream); + instream = (FILE *) 0; + while (cmdlines) + { + execute_command (cmdlines->line, 0); + cmdlines = cmdlines->next; + } + do_cleanups (old_chain); + } + else + /* Pass null arg rather than an empty one. */ + (*c->function) (*p ? p : 0, from_tty); + } +} + +static void +do_nothing () +{ +} + +/* Read commands from `instream' and execute them + until end of file. */ +void +command_loop () +{ + struct cleanup *old_chain; + while (!feof (instream)) + { + if (window_hook && instream == stdin) + (*window_hook) (instream, prompt); + + quit_flag = 0; + old_chain = make_cleanup (do_nothing, 0); + execute_command (gdb_read_line (instream == stdin ? prompt : 0, + instream == stdin), + instream == stdin); + /* Do any commands attached to breakpoint we stopped at. */ + do_breakpoint_commands (); + do_cleanups (old_chain); + } +} + +#ifdef SIGTSTP +static void +stop_sig () +{ + signal (SIGTSTP, SIG_DFL); + sigsetmask (0); + kill (getpid (), SIGTSTP); + signal (SIGTSTP, stop_sig); + printf ("%s", prompt); + fflush (stdout); + + /* Forget about any previous command -- null line now will do nothing. */ + *line = 0; +} +#endif /* SIGTSTP */ + +/* Commands call this if they do not want to be repeated by null lines. */ + +void +dont_repeat () +{ + *line = 0; +} + +/* Read one line from the command input stream `instream' + into the buffer `line' (whose current length is `linesize'). + The buffer is made bigger as necessary. + Returns the address of the start of the line. */ + +char * +gdb_read_line (prompt, repeat) + char *prompt; + int repeat; +{ + register char *p = line; + register char *p1; + register int c; + char *nline; + + /* Control-C quits instantly if typed while in this loop + since it should not wait until the user types a newline. */ + immediate_quit++; +#ifdef SIGTSTP + signal (SIGTSTP, stop_sig); +#endif + + if (prompt) + { + printf (prompt); + fflush (stdout); + } + + while (1) + { + c = fgetc (instream); + if (c == -1 || c == '\n') + break; + /* Ignore backslash-newline; keep adding to the same line. */ + else if (c == '\\') + { + int c1 = fgetc (instream); + if (c1 == '\n') + continue; + else + ungetc (c1, instream); + } + + if (p - line == linesize - 1) + { + linesize *= 2; + nline = (char *) xrealloc (line, linesize); + p += nline - line; + line = nline; + } + *p++ = c; + } + +#ifdef SIGTSTP + signal (SIGTSTP, SIG_DFL); +#endif + immediate_quit--; + + /* If we just got an empty line, and that is supposed + to repeat the previous command, leave the last input unchanged. */ + if (p == line && repeat) + return line; + + /* If line is a comment, clear it out. */ + p1 = line; + while ((c = *p1) == ' ' || c == '\t') p1++; + if (c == '#') + p = line; + + *p = 0; + + return line; +} + +/* Read lines from the input stream + and accumulate them in a chain of struct command_line's + which is then returned. */ + +struct command_line * +read_command_lines () +{ + struct command_line *first = 0; + register struct command_line *next, *tail = 0; + register char *p, *p1; + struct cleanup *old_chain = 0; + + while (1) + { + dont_repeat (); + p = gdb_read_line (0, 1); + /* Remove leading and trailing blanks. */ + while (*p == ' ' || *p == '\t') p++; + p1 = p + strlen (p); + while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--; + + /* Is this "end"? */ + if (p1 - p == 3 && !strncmp (p, "end", 3)) + break; + + /* No => add this line to the chain of command lines. */ + next = (struct command_line *) xmalloc (sizeof (struct command_line)); + next->line = savestring (p, p1 - p); + next->next = 0; + if (tail) + { + tail->next = next; + } + else + { + /* We just read the first line. + From now on, arrange to throw away the lines we have + if we quit or get an error while inside this function. */ + first = next; + old_chain = make_cleanup (free_command_lines, &first); + } + tail = next; + } + + dont_repeat (); + + /* Now we are about to return the chain to our caller, + so freeing it becomes his responsibility. */ + if (first) + discard_cleanups (old_chain); + return first; +} + +/* Free a chain of struct command_line's. */ + +void +free_command_lines (lptr) + struct command_line **lptr; +{ + register struct command_line *l = *lptr; + register struct command_line *next; + + while (l) + { + next = l->next; + free (l->line); + free (l); + l = next; + } +} + +/* Add an element to the list of info subcommands. */ + +void +add_info (name, fun, doc) + char *name; + void (*fun) (); + char *doc; +{ + add_cmd (name, no_class, fun, doc, &infolist); +} + +/* Add an alias to the list of info subcommands. */ + +void +add_info_alias (name, oldname, abbrev_flag) + char *name; + char *oldname; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist); +} + +/* The "info" command is defined as a prefix, with allow_unknown = 0. + Therefore, its own definition is called only for "info" with no args. */ + +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); + 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 (); + + 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; +{ + struct command_line *doclines; + register struct cmd_list_element *c; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", 0); + + if (c->class != (int) class_user) + error ("Command \"%s\" is built-in.", comname); + + if (from_tty) + printf ("Type documentation for \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + + doclines = read_command_lines (); + + if (c->doc) free (c->doc); + + { + register struct command_line *cl1; + register int len = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + len += strlen (cl1->line) + 1; + + c->doc = (char *) xmalloc (len + 1); + *c->doc = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + { + strcat (c->doc, cl1->line); + if (cl1->next) + strcat (c->doc, "\n"); + } + } + + free_command_lines (&doclines); +} + +static void +copying_info () +{ + immediate_quit++; + printf (" GDB GENERAL PUBLIC LICENSE\n\ + (Clarified 11 Feb 1988)\n\ +\n\ + Copyright (C) 1988 Richard M. Stallman\n\ + Everyone is permitted to copy and distribute verbatim copies\n\ + of this license, but changing it is not allowed.\n\ + You can also use this wording to make the terms for other programs.\n\ +\n\ + The license agreements of most software companies keep you at the\n\ +mercy of those companies. By contrast, our general public license is\n\ +intended to give everyone the right to share GDB. To make sure that\n\ +you get the rights we want you to have, we need to make restrictions\n\ +that forbid anyone to deny you these rights or to ask you to surrender\n\ +the rights. Hence this license agreement.\n\ +\n\ + Specifically, we want to make sure that you have the right to give\n\ +away copies of GDB, that you receive source code or else can get it\n\ +if you want it, that you can change GDB or use pieces of it in new\n\ +free programs, and that you know you can do these things.\n\ +--Type Return to print more--"); + fflush (stdout); + gdb_read_line (0, 0); + + printf ("\ + To make sure that everyone has such rights, we have to forbid you to\n\ +deprive anyone else of these rights. For example, if you distribute\n\ +copies of GDB, you must give the recipients all the rights that you\n\ +have. You must make sure that they, too, receive or can get the\n\ +source code. And you must tell them their rights.\n\ +\n\ + Also, for our own protection, we must make certain that everyone\n\ +finds out that there is no warranty for GDB. If GDB is modified by\n\ +someone else and passed on, we want its recipients to know that what\n\ +they have is not what we distributed, so that any problems introduced\n\ +by others will not reflect on our reputation.\n\ +\n\ + Therefore we (Richard Stallman and the Free Software Foundation,\n\ +Inc.) make the following terms which say what you must do to be\n\ +allowed to distribute or change GDB.\n\ +--Type Return to print more--"); + fflush (stdout); + gdb_read_line (0, 0); + + printf ("\ + COPYING POLICIES\n\ +\n\ + 1. You may copy and distribute verbatim copies of GDB source code as\n\ +you receive it, in any medium, provided that you conspicuously and\n\ +appropriately publish on each copy a valid copyright notice \"Copyright\n\ +\(C) 1988 Free Software Foundation, Inc.\" (or with whatever year is\n\ +appropriate); keep intact the notices on all files that refer\n\ +to this License Agreement and to the absence of any warranty; and give\n\ +any other recipients of the GDB program a copy of this License\n\ +Agreement along with the program. You may charge a distribution fee\n\ +for the physical act of transferring a copy.\n\ +\n\ + 2. You may modify your copy or copies of GDB or any portion of it,\n\ +and copy and distribute such modifications under the terms of\n\ +Paragraph 1 above, provided that you also do the following:\n\ +\n\ + a) cause the modified files to carry prominent notices stating\n\ + that you changed the files and the date of any change; and\n\ +--Type Return to print more--"); + fflush (stdout); + gdb_read_line (0, 0); + + printf ("\ + b) cause the whole of any work that you distribute or publish,\n\ + that in whole or in part contains or is a derivative of GDB\n\ + or any part thereof, to be licensed to all third parties on terms\n\ + identical to those contained in this License Agreement (except that\n\ + you may choose to grant more extensive warranty protection to some\n\ + or all third parties, at your option).\n\ +\n"); + printf ("\ + c) if the modified program serves as a debugger, cause it\n\ + when started running in the simplest and usual way, to print\n\ + an announcement including a valid copyright notice\n\ + \"Copyright (C) 1988 Free Software Foundation, Inc.\" (or with\n\ + the year that is appropriate), saying that there is no warranty\n\ + (or else, saying that you provide a warranty) and that users may\n\ + redistribute the program under these conditions, and telling the user\n\ + how to view a copy of this License Agreement.\n\ +\n\ + d) You may charge a distribution fee for the physical act of\n\ + transferring a copy, and you may at your option offer warranty\n\ + protection in exchange for a fee.\n\ +\n\ +Mere aggregation of another unrelated program with this program (or its\n\ +derivative) on a volume of a storage or distribution medium does not bring\n\ +the other program under the scope of these terms.\n\ +--Type Return to print more--"); + fflush (stdout); + gdb_read_line (0, 0); + + printf ("\ + 3. You may copy and distribute GDB (or a portion or derivative of it,\n\ +under Paragraph 2) in object code or executable form under the terms of\n\ +Paragraphs 1 and 2 above provided that you also do one of the following:\n\ +\n\ + a) accompany it with the complete corresponding machine-readable\n\ + source code, which must be distributed under the terms of\n\ + Paragraphs 1 and 2 above; or,\n\ +\n\ + b) accompany it with a written offer, valid for at least three\n\ + years, to give any third party free (except for a nominal\n\ + shipping charge) a complete machine-readable copy of the\n\ + corresponding source code, to be distributed under the terms of\n\ + Paragraphs 1 and 2 above; or,\n\n"); + + printf ("\ + c) accompany it with the information you received as to where the\n\ + corresponding source code may be obtained. (This alternative is\n\ + allowed only for noncommercial distribution and only if you\n\ + received the program in object code or executable form alone.)\n\ +\n\ +For an executable file, complete source code means all the source code for\n\ +all modules it contains; but, as a special exception, it need not include\n\ +source code for modules which are standard libraries that accompany the\n\ +operating system on which the executable file runs.\n\ +--Type Return to print more--"); + fflush (stdout); + gdb_read_line (0, 0); + + printf ("\ + 4. You may not copy, sublicense, distribute or transfer GDB\n\ +except as expressly provided under this License Agreement. Any attempt\n\ +otherwise to copy, sublicense, distribute or transfer GDB is void and\n\ +your rights to use the program under this License agreement shall be\n\ +automatically terminated. However, parties who have received computer\n\ +software programs from you with this License Agreement will not have\n\ +their licenses terminated so long as such parties remain in full compliance.\n\ +\n\ +"); + printf ("\ + 5. If you wish to incorporate parts of GDB into other free\n\ +programs whose distribution conditions are different, write to the Free\n\ +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet\n\ +worked out a simple rule that can be stated here, but we will often permit\n\ +this. We will be guided by the two goals of preserving the free status of\n\ +all derivatives of our free software and of promoting the sharing and reuse\n\ +of software.\n\ +\n\ +In other words, go ahead and share GDB, but don't try to stop\n\ +anyone else from sharing it farther. Help stamp out software hoarding!\n\ +"); + immediate_quit--; +} + +static void +warranty_info () +{ + immediate_quit++; + printf (" NO WARRANTY\n\ +\n\ + BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY NO\n\ +WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT\n\ +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,\n\ +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB \"AS IS\" WITHOUT\n\ +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT\n\ +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\ +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND\n\ +PERFORMANCE OF GDB IS WITH YOU. SHOULD GDB PROVE DEFECTIVE, YOU\n\ +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n"); + + printf ("\ + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.\n\ +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY\n\ +WHO MAY MODIFY AND REDISTRIBUTE GDB, BE LIABLE TO\n\ +YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER\n\ +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR\n\ +INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA\n\ +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A\n\ +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GDB, EVEN\n\ +IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR\n\ +ANY CLAIM BY ANY OTHER PARTY.\n"); + immediate_quit--; +} + +static void +print_gdb_version () +{ + printf ("GDB %s, Copyright (C) 1988 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--; +} + +/* xgdb calls this to reprint the usual GDB prompt. */ + +void +print_prompt () +{ + printf ("%s", prompt); + fflush (stdout); +} + +/* Command to specify a prompt string instead of "(gdb) ". */ + +static 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 (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."); + } + 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"); + + 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 (file) + char *file; +{ + FILE *stream; + struct cleanup *cleanups; + + if (file == 0) + error_no_arg ("file to read commands from"); + + 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); + } +} + +static void +dump_me_command () +{ + if (query ("Should GDB dump core? ")) + { + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + } +} + +static void +init_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; +} + +static void +init_main () +{ + prompt = savestring ("(gdb) ", 6); + + /* 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 ("dump-me", class_obscure, dump_me_command, + "Get fatal error; make debugger dump its core."); + + 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 ("copying", copying_info, "Conditions for redistributing copies of GDB."); + add_info ("warranty", warranty_info, "Various kinds of warranty you do not have."); + add_info ("version", version_info, "Report what version of GDB this is."); +} +@ + + +1.1 +log +@Initial revision +@ +text +@d103 2 +a104 2 +static void initialize_main (); +static void initialize_cmd_lists (); +d247 3 +a249 3 + initialize_cmd_lists (); /* This needs to be done first */ + initialize_all_files (); + initialize_main (); /* But that omits this file! Do it now */ +d1206 1 +a1206 1 +initialize_cmd_lists () +d1218 1 +a1218 1 +initialize_main () +@ diff --git a/gdb/RCS/munch,v b/gdb/RCS/munch,v new file mode 100755 index 0000000..bac6946 --- /dev/null +++ b/gdb/RCS/munch,v @@ -0,0 +1,75 @@ +head 1.3; +access ; +symbols ; +locks ; strict; +comment @# @; + + +1.3 +date 89.03.27.21.15.45; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.03.27.20.18.28; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.20.18.58.17; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.3 +log +@Fix up "munch" so it generates a name that doesn't match its own +"grep" conventions. Change main so that it calls the new name, +and also doesn't use the conventions for functions that should NOT +be called by init.c. +@ +text +@#! /bin/sh + +# create an initialization procedure from a list of .o files +# Look in object files, find symbols including the string _initialize_, +# and call each one as a function. + +echo '/* Do not modify this file. It is created automatically by "munch". */' +echo 'void init_all_files () {' + +nm $* | egrep '_initialize_' | \ + sed -e 's/^.*\(initialize_[a-zA-Z_0-9]*\).*$/ _\1 ();/' | \ + sort -u + +echo '}' +@ + + +1.2 +log +@Generic change: make it not care much about the output format of "nm". +Now as long as _initialize_foo is not touching any other +symbol or alphanumeric, we'll find it and use it. +@ +text +@d8 1 +a8 1 +echo 'void initialize_all_files () {' +@ + + +1.1 +log +@Initial revision +@ +text +@d4 2 +d10 3 +a12 1 +nm -p $* | egrep 'T *__?initialize_' | sed -e 's/^.*T *_*\(.*\)/ _\1 ();/' +@ diff --git a/gdb/RCS/printcmd.c,v b/gdb/RCS/printcmd.c,v new file mode 100644 index 0000000..2ab3acc --- /dev/null +++ b/gdb/RCS/printcmd.c,v @@ -0,0 +1,1707 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.04.26.00.54.22; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.04.25.15.38.49; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@(1) Depend on XXX_BIG_ENDIAN rather than testing gdb's object code. +(2) Print to the STREAM parameter, not to stdout. +(3) Use is_nan with new arguments. +(4) Use unpack_double with new args, and deal with invalid results. +(5) Don't print history numbers in the "print" command for things +that weren't recorded in history (because they were invalid values). +@ +text +@/* Print values for GNU debugger GDB. + Copyright (C) 1986, 1987, 1988 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! +*/ + +#include +#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_scalar_formatted (); + + +/* Decode a format specification. *STRING_PTR should point to it. + OFORMAT and OSIZE are used as defaults for the format and size + if none are given in the format specification. + 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 = oformat; + val.size = osize; + val.count = 1; + + if (*p >= '0' && *p <= '9') + val.count = atoi (p); + while (*p >= '0' && *p <= '9') p++; + + /* Now process size or format letters that follow. */ + + while (1) + { + if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g') + val.size = *p++; +#ifdef LONG_LONG + else if (*p == 'l') + { + val.size = 'g'; + p++; + } +#endif + else if (*p >= 'a' && *p <= 'z') + val.format = *p++; + else + break; + } + +#ifndef LONG_LONG + /* Make sure 'g' size is not used on integer types. + Well, actually, we can handle hex. */ + if (val.size == 'g' && val.format != 'f' && val.format != 'x') + val.size = 'w'; +#endif + + while (*p == ' ' || *p == '\t') p++; + *string_ptr = p; + + 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); + 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); + 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 (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 (stream, "0x%02llx", val_long); + break; + case 'h': + fprintf (stream, "0x%04llx", val_long); + break; + case 0: /* no size specified, like in print */ + case 'w': + fprintf (stream, "0x%08llx", val_long); + break; + case 'g': + fprintf (stream, "0x%16llx", val_long); + break; + default: + error ("Undefined output size \"%c\".", size); + } +#else + switch (size) + { + case 'b': + fprintf (stream, "0x%02x", val_long); + break; + case 'h': + fprintf (stream, "0x%04x", val_long); + break; + case 0: /* no size specified, like in print */ + case 'w': + fprintf (stream, "0x%08x", val_long); + break; + case 'g': + fprintf (stream, "0x%16x", val_long); + break; + default: + error ("Undefined output size \"%c\".", size); + } +#endif /* not LONG_LONG */ + break; + + case 'd': +#ifdef LONG_LONG + fprintf (stream, "%lld", val_long); +#else + fprintf (stream, "%d", val_long); +#endif + break; + + case 'u': +#ifdef LONG_LONG + fprintf (stream, "%llu", val_long); +#else + fprintf (stream, "%u", val_long); +#endif + break; + + case 'o': + if (val_long) +#ifdef LONG_LONG + fprintf (stream, "0%llo", val_long); +#else + fprintf (stream, "0%o", val_long); +#endif + else + fprintf (stream, "0"); + break; + + case 'a': + print_address ((CORE_ADDR) val_long, stream); + break; + + case 'c': + value_print (value_from_long (builtin_type_char, val_long), stream, 0); + break; + + case 'f': + if (len == sizeof (float)) + type = builtin_type_float; + else if (len == sizeof (double)) + type = builtin_type_double; + else abort(); + +#ifdef IEEE_FLOAT + if (is_nan (valaddr, len)) + { + fprintf (stream, "NaN"); + break; + } +#endif + { + double doub; + int inv; + + doub = unpack_double (type, valaddr, &inv); + if (inv) + fprintf (stream, "Invalid float value"); + else + fprintf (stream, len > 4? "%.16g": "%.6g", doub); + } + break; + + case 0: + abort (); + + default: + error ("Undefined output format \"%c\".", format); + } +} + +/* Specify default address for `x' command. + `info lines' uses this. */ + +void +set_next_address (addr) + CORE_ADDR addr; +{ + next_address = addr; + + /* Make address available to the user as $_. */ + set_internalvar (lookup_internalvar ("_"), + value_from_long (builtin_type_int, (LONGEST) addr)); +} + +/* Print address ADDR symbolically on STREAM. + First print it as a number. Then perhaps print + after the number. */ + +void +print_address (addr, stream) + CORE_ADDR addr; + FILE *stream; +{ + register int i; + struct symbol *fs; + char *name; + int name_location; + + fprintf (stream, "0x%x", addr); + + fs = find_pc_function (addr); + + if (!fs) + { + i = find_pc_misc_function (addr); + + if (i < 0) return; /* If nothing comes through, don't + print anything symbolic */ + + name = misc_function_vector[i].name; + name_location = misc_function_vector[i].address; + } + else + { + name = fs->name; + name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (fs)); + } + + if (addr - name_location) + fprintf (stream, " <%s+%d>", + name, + addr - name_location); + else + fprintf (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); + fputc (':', stdout); + for (i = maxelts; + i > 0 && count > 0; + i--, count--) + { + fputc ('\t', stdout); + /* 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); + } + fputc ('\n', stdout); + 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 ("$%d = ", histindex); + + print_formatted (val, format, fmt.size); + printf ("\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_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; + + 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); + next_address = (CORE_ADDR) value_as_long (evaluate_expression (expr)); + 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 ("type = "); + type_print (VALUE_TYPE (val), "", stdout, 1); + printf ("\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 ("No type named %s, but there is a ", + typename); + switch (TYPE_CODE (SYMBOL_TYPE (sym))) + { + case TYPE_CODE_STRUCT: + printf ("struct"); + break; + + case TYPE_CODE_UNION: + printf ("union"); + break; + + case TYPE_CODE_ENUM: + printf ("enum"); + } + printf (" %s. Type \"help ptype\".\n", typename); + type = SYMBOL_TYPE (sym); + } + } + + type_print (type, "", stdout, 1); + printf ("\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 ("%d: ", d->number); + if (d->format.size) + { + printf ("x/"); + if (d->format.count != 1) + printf ("%d", d->format.count); + printf ("%c", d->format.format); + if (d->format.format != 'i' && d->format.format != 's') + printf ("%c", d->format.size); + printf (" "); + print_expression (d->exp, stdout); + if (d->format.count != 1) + printf ("\n"); + else + printf (" "); + do_examine (d->format, + (CORE_ADDR) value_as_long (evaluate_expression (d->exp))); + + } + else + { + if (d->format.format) + printf ("/%c ", d->format.format); + print_expression (d->exp, stdout); + printf (" = "); + print_formatted (evaluate_expression (d->exp), + d->format.format, d->format.size); + printf ("\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 +delete_current_display () +{ + if (current_display_number >= 0) + { + delete_display (current_display_number); + fprintf (stderr, "Deleting 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 ("Auto-display expressions now in effect:\n\ +Num Enb Expression\n"); + + for (d = display_chain; d; d = d->next) + { + printf ("%d: %c ", d->number, "ny"[(int)d->status]); + if (d->format.size) + printf ("/%d%c%c ", d->format.count, d->format.size, + d->format.format); + else if (d->format.format) + printf ("/%c ", d->format.format); + print_expression (d->exp, stdout); + if (d->block && !contained_in (get_selected_block (), d->block)) + printf (" (cannot be evaluated in the current context)"); + printf ("\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->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 (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->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); + + for (d = display_chain; d; d = d->next) + if (d->number == num) + { + d->status = disabled; + goto win; + } + printf ("No display number %d.\n", num); + win: + 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; + CORE_ADDR frame; + FILE *stream; +{ + value val = read_var_value (var, frame); + value_print (val, stream, 0); +} + +/* 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_offset = FRAME_ARGS_SKIP; + register int last_regparm = 0; + register struct symbol *lastsym, *sym, *nextsym; + register value val; + register CORE_ADDR addr = FRAME_ARGS_ADDRESS (fi); + + if (func) + { + b = SYMBOL_BLOCK_VALUE (func); + nsyms = BLOCK_NSYMS (b); + } + + lastsym = 0; + while (1) + { + /* Find first arg that is not before LAST_OFFSET. */ + nextsym = 0; + for (i = 0; i < nsyms; i++) + { + QUIT; + sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (sym) == LOC_ARG) + { + if (SYMBOL_VALUE (sym) >= last_offset + && (nextsym == 0 + || SYMBOL_VALUE (sym) < SYMBOL_VALUE (nextsym))) + nextsym = sym; + } + else if (SYMBOL_CLASS (sym) == LOC_REGPARM) + { + /* This shouldn't be sorted by number. Since we can't + find nameless args with register parameters, print + this out in order by .stabs. */ + if (sym > lastsym && nextsym == 0) + nextsym = sym; + } + } + if (nextsym == 0) + break; + sym = nextsym; + /* Print any nameless args between the last arg printed + and the next arg. */ + if (SYMBOL_CLASS (sym) == LOC_ARG + && last_offset != (SYMBOL_VALUE (sym) / sizeof (int)) * sizeof (int)) + { + print_frame_nameless_args (addr, last_offset, SYMBOL_VALUE (sym), + stream); + first = 0; + } + /* 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 + val = value_at (SYMBOL_TYPE (sym), addr + SYMBOL_VALUE (sym)); + + if (! first) + fprintf (stream, ", "); + fprintf (stream, "%s=", SYMBOL_NAME (sym)); + value_print (val, stream, 0); + first = 0; + if (SYMBOL_CLASS (sym) == LOC_ARG) + last_offset = SYMBOL_VALUE (sym) + TYPE_LENGTH (SYMBOL_TYPE (sym)); + else + { + last_regparm = SYMBOL_VALUE (sym) + 1; + last_offset += TYPE_LENGTH (SYMBOL_TYPE (sym)); + } + + /* Round up address of next arg to multiple of size of int. */ + last_offset + = ((last_offset + sizeof (int) - 1) / sizeof (int)) * sizeof (int); + lastsym = sym; + } + if (num >= 0 && num * sizeof (int) + FRAME_ARGS_SKIP > last_offset) + print_frame_nameless_args (addr, last_offset, + num * sizeof (int) + FRAME_ARGS_SKIP, stream); +} + +static void +print_frame_nameless_args (argsaddr, start, end, stream) + CORE_ADDR argsaddr; + int start; + int end; + FILE *stream; +{ + while (start < end) + { + QUIT; + if (start != FRAME_ARGS_SKIP) + fprintf (stream, ", "); + fprintf (stream, "%d", + read_memory_integer (argsaddr + start, sizeof (int))); + start += sizeof (int); + } +} + +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; + char *argclass; + int i; + int argindex; + int nargs_wanted; + + 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] is set to 1 if the Ith arg should be a string. + It's set to 2 if the Ith arg should be floating point. */ + + argclass = (char *) alloca (strlen (s)); + nargs_wanted = 0; + f = string; + while (*f) + if (*f++ == '%') + { + while (index ("0123456789.hlL-+ #", *f)) f++; + if (*f == 's') + argclass[nargs_wanted++] = 1; + else if (*f == 'e' || *f == 'f' || *f == 'g') + argclass[nargs_wanted++] = 2; + else if (*f != '%') + argclass[nargs_wanted++] = 0; + 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] == 2) + { + argclass[nargs] = 0; + 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]) + { + 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 (TYPE_LENGTH (VALUE_TYPE (val_args[i])) == sizeof (long long)) + { + *(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); +} + +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 ("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_abbrev_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, + "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); +} + +@ + + +1.1 +log +@Initial revision +@ +text +@a191 1 + int bigendian = 0; +d196 7 +a202 5 + { + union { + char a, b, c, d; + long i; + } x; +a203 10 + x.i = 1; + if (x.a) + { + /* Little endian */ + tmp = v1; + v1 = v2; + v2 = tmp; + } + } + +d207 1 +a207 1 + printf ("0x%08x%08x", v1, v2); +d238 1 +a238 1 + printf ("0x%02llx", val_long); +d241 1 +a241 1 + printf ("0x%04llx", val_long); +d245 1 +a245 1 + printf ("0x%08llx", val_long); +d248 1 +a248 1 + printf ("0x%16llx", val_long); +d257 1 +a257 1 + printf ("0x%02x", val_long); +d260 1 +a260 1 + printf ("0x%04x", val_long); +d264 1 +a264 1 + printf ("0x%08x", val_long); +d267 1 +a267 1 + printf ("0x%16x", val_long); +d277 1 +a277 1 + printf ("%lld", val_long); +d279 1 +a279 1 + printf ("%d", val_long); +d285 1 +a285 1 + printf ("%llu", val_long); +d287 1 +a287 1 + printf ("%u", val_long); +d294 1 +a294 1 + printf ("0%llo", val_long); +d296 1 +a296 1 + printf ("0%o", val_long); +d299 1 +a299 1 + printf ("0"); +d313 1 +a313 1 + if (len == sizeof (double)) +d315 2 +d318 1 +a318 1 + if (is_nan (unpack_double (type, valaddr))) +d320 1 +a320 1 + printf ("Nan"); +d324 10 +a333 4 + if (len > 4) + printf ("%.16g", unpack_double (type, valaddr)); + else + printf ("%.6g", unpack_double (type, valaddr)); +d515 1 +a515 1 + printf ("$%d = ", histindex); +@ diff --git a/gdb/RCS/remote.c,v b/gdb/RCS/remote.c,v new file mode 100644 index 0000000..213113d --- /dev/null +++ b/gdb/RCS/remote.c,v @@ -0,0 +1,662 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.03.27.20.21.22; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.20.18.45.46; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Avoid . +@ +text +@/* Memory-access and commands for inferior process, for GDB. + Copyright (C) 1988 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! +*/ + +/* Remote communication protocol. + All values are encoded in ascii hex digits. + + Request Packet + + read registers g + reply XX....X Each byte of register data + is described by two hex digits. + Registers are in the internal order + for GDB, and the bytes in a register + are in the same order the machine uses. + or ENN for an error. + + write regs GXX..XX Each byte of register data + is described by two hex digits. + reply OK for success + ENN for an error + + read mem mAA..AA,LLLL AA..AA is address, LLLL is length. + reply XX..XX XX..XX is mem contents + or ENN NN is errno + + write mem MAA..AA,LLLL:XX..XX + AA..AA is address, + LLLL is number of bytes, + XX..XX is data + reply OK for success + ENN for an error + + cont cAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + step sAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + There is no immediate reply to step or cont. + The reply comes when the machine stops. + It is SAA AA is the "signal number" + + kill req k +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include "wait.h" + +#ifdef USG +#include +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_TERMIO +#include +#undef TIOCGETP +#define TIOCGETP TCGETA +#undef TIOCSETN +#define TIOCSETN TCSETA +#undef TIOCSETP +#define TIOCSETP TCSETAF +#define TERMINAL struct termio +#else +#include +#define TERMINAL struct sgttyb +#endif + +int kiodebug; + +int icache; + +/* Descriptor for I/O to remote machine. */ +int remote_desc; + +#define PBUFSIZ 400 + +static void remote_send (); +static void putpkt (); +static void getpkt (); +static void dcache_flush (); + + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +void +remote_open (name, from_tty) + char *name; + int from_tty; +{ + TERMINAL sg; + + remote_debugging = 0; + dcache_init (); + + remote_desc = open (name, O_RDWR); + if (remote_desc < 0) + perror_with_name (name); + + ioctl (remote_desc, TIOCGETP, &sg); +#ifdef HAVE_TERMIO + sg.c_lflag &= ~ICANON; +#else + sg.sg_flags = RAW; +#endif + ioctl (remote_desc, TIOCSETP, &sg); + + if (from_tty) + printf ("Remote debugging using %s\n", name); + remote_debugging = 1; +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + error ("Reply contains invalid hex digit"); +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0'+nib; + else + return 'a'+nib-10; +} + +/* Tell the remote machine to resume. */ + +int +remote_resume (step, signal) + int step, signal; +{ + char buf[PBUFSIZ]; + + dcache_flush (); + + strcpy (buf, step ? "s": "c"); + + putpkt (buf); +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +int +remote_wait (status) + WAITTYPE *status; +{ + char buf[PBUFSIZ]; + + WSETEXIT ((*status), 0); + getpkt (buf); + if (buf[0] == 'E') + error ("Remote failure reply: %s", buf); + if (buf[0] != 'S') + error ("Invalid remote reply: %s", buf); + WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2])))); +} + +/* Read the remote registers into the block REGS. */ + +void +remote_fetch_registers (regs) + char *regs; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + sprintf (buf, "g"); + remote_send (buf); + + /* Reply describes registers byte by byte, + each byte encoded as two hex characters. */ + + p = buf; + for (i = 0; i < REGISTER_BYTES; i++) + { + if (p[0] == 0 || p[1] == 0) + error ("Remote reply is too short: %s", buf); + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } +} + +/* Store the remote registers from the contents of the block REGS. */ + +void +remote_store_registers (regs) + char *regs; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + buf[0] = 'G'; + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + p = buf + 1; + for (i = 0; i < REGISTER_BYTES; i++) + { + *p++ = tohex ((regs[i] >> 4) & 0xf); + *p++ = tohex (regs[i] & 0xf); + } + + remote_send (buf); +} + +/* Read a word from remote address ADDR and return it. + This goes through the data cache. */ + +int +remote_fetch_word (addr) + CORE_ADDR addr; +{ + if (icache) + { + extern CORE_ADDR text_start, text_end; + + if (addr >= text_start && addr < text_end) + { + int buffer; + xfer_core_file (addr, &buffer, sizeof (int)); + return buffer; + } + } + return dcache_fetch (addr); +} + +/* Write a word WORD into remote address ADDR. + This goes through the data cache. */ + +void +remote_store_word (addr, word) + CORE_ADDR addr; + int word; +{ + dcache_poke (addr, word); +} + +/* Write memory data directly to the remote machine. + This does not inform the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. */ + +void +remote_write_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + if (len > PBUFSIZ / 2 - 20) + abort (); + + sprintf (buf, "M%x,%x:", memaddr, len); + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + p = buf + strlen (buf); + for (i = 0; i < len; i++) + { + *p++ = tohex ((myaddr[i] >> 4) & 0xf); + *p++ = tohex (myaddr[i] & 0xf); + } + + remote_send (buf); +} + +/* Read memory data directly from the remote machine. + This does not use the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. */ + +void +remote_read_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + if (len > PBUFSIZ / 2 - 1) + abort (); + + sprintf (buf, "m%x,%x", memaddr, len); + remote_send (buf); + + /* Reply describes registers byte by byte, + each byte encoded as two hex characters. */ + + p = buf; + for (i = 0; i < len; i++) + { + if (p[0] == 0 || p[1] == 0) + error ("Remote reply is too short: %s", buf); + myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } +} + +/* + +A debug packet whose contents are +is encapsulated for transmission in the form: + + $ # CSUM1 CSUM2 + + must be ASCII alphanumeric and cannot include characters + '$' or '#' + + CSUM1 and CSUM2 are ascii hex representation of an 8-bit + checksum of , the most significant nibble is sent first. + the hex digits 0-9,a-f are used. + +Receiver responds with: + + + - if CSUM is correct and ready for next packet + - - if CSUM is incorrect + +*/ + +/* Send the command in BUF to the remote machine, + and read the reply into BUF. + Report an error if we get an error reply. */ + +static void +remote_send (buf) + char *buf; +{ + int i; + putpkt (buf); + getpkt (buf); + + if (buf[0] == 'E') + error ("Remote failure reply: %s", buf); +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. */ + +static void +putpkt (buf) + char *buf; +{ + int i; + char csum = 0; + char buf2[500]; + char buf3[1]; + int cnt = strlen (buf); + char *p; + + if (kiodebug) + fprintf (stderr, "Sending packet: %s\n", buf); + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) + { + csum += buf[i]; + *p++ = buf[i]; + } + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + do { + write (remote_desc, buf2, p - buf2); + read (remote_desc, buf3, 1); + } while (buf3[0] != '+'); +} + +static int +readchar () +{ + char buf[1]; + while (read (remote_desc, buf, 1) != 1) ; + return buf[0] & 0x7f; +} + +/* Read a packet from the remote machine, with error checking, + and store it in BUF. */ + +static void +getpkt (buf) + char *buf; +{ + char *bp; + unsigned char csum; + unsigned int c, c1, c2; + extern kiodebug; + + while (1) + { + /* Force csum to be zero here because of possible error retry. */ + csum = 0; + + while ((c = readchar()) != '$'); + + bp = buf; + while (1) + { + c = readchar (); + if (c == '#') + break; + *bp++ = c; + csum += c; + } + *bp = 0; + + c1 = fromhex (readchar ()); + c2 = fromhex (readchar ()); + if (csum == (c1 << 4) + c2) + break; + printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", + (c1 << 4) + c2, csum, buf); + write (remote_desc, "-", 1); + } + + write (remote_desc, "+", 1); + + if (kiodebug) + fprintf (stderr,"Packet received :%s\n", buf); +} + +/* The data cache records all the data read from the remote machine + since the last time it stopped. + + Each cache block holds 16 bytes of data + starting at a multiple-of-16 address. */ + +#define DCACHE_SIZE 64 /* Number of cache blocks */ + +struct dcache_block { + struct dcache_block *next, *last; + unsigned int addr; /* Address for which data is recorded. */ + int data[4]; +}; + +struct dcache_block dcache_free, dcache_valid; + +/* Free all the data cache blocks, thus discarding all cached data. */ + +static void +dcache_flush () +{ + register struct dcache_block *db; + + while ((db = dcache_valid.next) != &dcache_valid) + { + remque (db); + insque (db, &dcache_free); + } +} + +/* + * If addr is present in the dcache, return the address of the block + * containing it. + */ + +struct dcache_block * +dcache_hit (addr) +{ + register struct dcache_block *db; + + if (addr & 3) + abort (); + + /* Search all cache blocks for one that is at this address. */ + db = dcache_valid.next; + while (db != &dcache_valid) + { + if ((addr & 0xfffffff0) == db->addr) + return db; + db = db->next; + } + return NULL; +} + +/* Return the int data at address ADDR in dcache block DC. */ + +int +dcache_value (db, addr) + struct dcache_block *db; + unsigned int addr; +{ + if (addr & 3) + abort (); + return (db->data[(addr>>2)&3]); +} + +/* Get a free cache block, put it on the valid list, + and return its address. The caller should store into the block + the address and data that it describes. */ + +struct dcache_block * +dcache_alloc () +{ + register struct dcache_block *db; + + if ((db = dcache_free.next) == &dcache_free) + /* If we can't get one from the free list, take last valid */ + db = dcache_valid.last; + + remque (db); + insque (db, &dcache_valid); + return (db); +} + +/* Return the contents of the word at address ADDR in the remote machine, + using the data cache. */ + +int +dcache_fetch (addr) + CORE_ADDR addr; +{ + register struct dcache_block *db; + + db = dcache_hit (addr); + if (db == 0) + { + db = dcache_alloc (); + remote_read_bytes (addr & ~0xf, db->data, 16); + db->addr = addr & ~0xf; + } + return (dcache_value (db, addr)); +} + +/* Write the word at ADDR both in the data cache and in the remote machine. */ + +dcache_poke (addr, data) + CORE_ADDR addr; + int data; +{ + register struct dcache_block *db; + + /* First make sure the word is IN the cache. DB is its cache block. */ + db = dcache_hit (addr); + if (db == 0) + { + db = dcache_alloc (); + remote_read_bytes (addr & ~0xf, db->data, 16); + db->addr = addr & ~0xf; + } + + /* Modify the word in the cache. */ + db->data[(addr>>2)&3] = data; + + /* Send the changed word. */ + remote_write_bytes (addr, &data, 4); +} + +/* Initialize the data cache. */ + +dcache_init () +{ + register i; + register struct dcache_block *db; + + db = (struct dcache_block *) xmalloc (sizeof (struct dcache_block) * + DCACHE_SIZE); + dcache_free.next = dcache_free.last = &dcache_free; + dcache_valid.next = dcache_valid.last = &dcache_valid; + for (i=0;i +@ diff --git a/gdb/RCS/source.c,v b/gdb/RCS/source.c,v new file mode 100644 index 0000000..f19ff1d --- /dev/null +++ b/gdb/RCS/source.c,v @@ -0,0 +1,990 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.03.27.20.21.45; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.20.18.45.48; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Avoid . +@ +text +@/* List lines of source files for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1988 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! +*/ + +#include "defs.h" +#include "symtab.h" +#include "param.h" + +#ifdef USG +#include +#include +#endif + +#include +#include +#include +#include + +/* 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. */ + +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; + + /* 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 = sal.line - 9; + return; + } + + /* If there is no `main', use the last symtab in the list, + which is actually the first found in the file's symbol table. + But ignore .h files. */ + if (s) + { + 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 + { + 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) + 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; + + if (dirname == 0) + { + if (query ("Reinitialize source path to %s? ", current_directory)) + { + init_source_path (); + free (old); + } + } + else + { + struct stat st; + register int len = strlen (dirname); + register char *tem; + extern char *index (); + + if (index (dirname, ':')) + error ("Please add one directory at a time to the source path."); + if (dirname[len - 1] == '/') + /* Sigh. "foo/" => "foo" */ + dirname[--len] == '\0'; + + while (dirname[len - 1] == '.') + { + if (len == 1) + { + /* "." => getwd () */ + dirname = current_directory; + goto append; + } + else if (dirname[len - 2] == '/') + { + if (len == 2) + { + /* "/." => "/" */ + dirname[--len] = '\0'; + goto append; + } + else + { + /* "...foo/." => "...foo" */ + dirname[len -= 2] = '\0'; + continue; + } + } + break; + } + + if (dirname[0] != '/') + dirname = concat (current_directory, "/", dirname); + else + dirname = savestring (dirname, len); + make_cleanup (free, dirname); + + if (stat (dirname, &st) < 0) + perror_with_name (dirname); + if ((st.st_mode & S_IFMT) != S_IFDIR) + error ("%s is not a directory.", dirname); + + append: + len = strlen (dirname); + tem = source_path; + while (1) + { + if (!strncmp (tem, dirname, len) + && (tem[len] == '\0' || tem[len] == ':')) + { + printf ("\"%s\" is already in the source path.\n", + dirname); + break; + } + tem = index (tem, ':'); + if (tem) + tem++; + else + { + source_path = concat (old, ":", dirname); + free (old); + break; + } + } + 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; + + /* ./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; + + fstat (desc, &st); + 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); + myread (desc, data, st.st_size); + 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\n", s->fullname, + line, s->line_charpos[line - 1], + mid_statement ? "middle" : "beg"); + 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) + 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 out of range; %s has %d lines.", + 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 ("%d\t", current_source_line++); + do + { + if (c < 040 && c != '\t' && c != '\n') + { + fputc ('^', stdout); + fputc (c + 0100, stdout); + } + else if (c == 0177) + printf ("^?"); + else + fputc (c, stdout); + } while (c != '\n' && (c = fgetc (stream)) >= 0); + } + + fclose (stream); +} + + + +/* + C++ + Print a list of files and line numbers which a user may choose from + in order to list a function which was specified ambiguously + (as with `list classname::overloadedfuncname', for example). + The vector in SALS provides the filenames and line numbers. + */ +static void +ambiguous_line_spec (sals) + struct symtabs_and_lines *sals; +{ + int i; + + for (i = 0; i < sals->nelts; ++i) + printf("file: \"%s\", line number: %d\n", + sals->sals[i].symtab->filename, sals->sals[i].line); +} + + +static void +list_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals, sals_end; + struct symtab_and_line sal, sal_end; + struct symbol *sym; + char *arg1; + int no_end = 1; + int dummy_end = 0; + int dummy_beg = 0; + int linenum_beg = 0; + char *p; + + if (symtab_list == 0 && partial_symtab_list == 0) + error ("Listing source lines requires symbols."); + + /* Pull in a current source symtab if necessary */ + if (current_source_symtab == 0 && + (arg == 0 || arg[0] == '+' || arg[0] == '-')) + select_source_symtab (symtab_list); + + /* "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) + error ("No default source file yet. Do \"help list\"."); + + /* 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) + error ("No default source file yet. Do \"help list\"."); + + /* 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."); +} + +@ + + +1.1 +log +@Initial revision +@ +text +@d27 1 +a27 1 +#include +@ diff --git a/gdb/RCS/sparc-dep.c,v b/gdb/RCS/sparc-dep.c,v new file mode 100644 index 0000000..8178e00 --- /dev/null +++ b/gdb/RCS/sparc-dep.c,v @@ -0,0 +1,1091 @@ +head 1.3; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.3 +date 89.04.04.21.31.02; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.02.10.01.47.27; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.10.01.46.36; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.3 +log +@Fix handling of annulled branches in single step. "b foo; bcc,a bar" +annuls the instruction at foo, not just after the bcc,a. Also, +handle CBcc (coprocessor) annulled branch, and improve doc. +@ +text +@/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + This code is for the sparc cpu. + +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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "obstack.h" +#include "sparc-opcode.h" +#include "gdbcore.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +extern int errno; +extern int attach_flag; + +/* 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); +} + +void +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.*/ + +void +kill_inferior_fast () +{ + if (remote_debugging) + return; + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); +} + +/* Simulate single-step ptrace call for sun4. Code written by Gary + Beihl (beihl@@mcc.com). */ + +/* + * Duplicated from breakpoint.c because (at least for now) this is a + * machine dependent routine. + */ +static char break_insn[] = BREAKPOINT; + +/* From infrun.c */ +extern int stop_after_trap, stop_after_attach; + +static CORE_ADDR next_pc, npc4, target; +static int brknpc4, brktrg; +typedef char binsn_quantum[sizeof break_insn]; +static binsn_quantum break_mem[3]; + +/* Non-zero if we just simulated a single-step ptrace call. This is + needed because we cannot remove the breakpoints in the inferior + process until after the `wait' in `wait_for_inferior'. Used for + sun4. */ + +int one_stepped; + +void +single_step (signal) + int signal; +{ + branch_type br, isannulled(); + CORE_ADDR pc; + + next_pc = read_register (NPC_REGNUM); + npc4 = next_pc + 4; /* branch not taken */ + + if (!one_stepped) + { + /* Always set breakpoint for NPC. */ + read_memory (next_pc, break_mem[0], sizeof break_insn); + write_memory (next_pc, break_insn, sizeof break_insn); + /* printf ("set break at %x\n",next_pc); */ + + pc = read_register (PC_REGNUM); + br = isannulled (pc, &target); + brknpc4 = brktrg = 0; + + if (br == bicca) + { + /* Conditional annulled branch will either end up at + npc (if taken) or at npc+4 (if not taken). Trap npc+4. */ + brknpc4 = 1; + read_memory (npc4, break_mem[1], sizeof break_insn); + write_memory (npc4, break_insn, sizeof break_insn); + } + else if (br == baa && target != next_pc) + { + /* Unconditional annulled branch will always end up at + the target. */ + brktrg = 1; + read_memory (target, break_mem[2], sizeof break_insn); + write_memory (target, break_insn, sizeof break_insn); + } + + /* Let it go */ + ptrace (7, inferior_pid, 1, signal); + one_stepped = 1; + return; + } + else + { + /* Remove breakpoints */ + write_memory (next_pc, break_mem[0], sizeof break_insn); + + if (brknpc4) + { + write_memory (npc4, break_mem[1], sizeof break_insn); + } + if (brktrg) + { + write_memory (target, break_mem[2], sizeof break_insn); + } + one_stepped = 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 + { + /* Sparc doesn't have single step on ptrace */ + if (step) + single_step (signal); + else + ptrace (7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + } +} + +#ifdef ATTACH_DETACH + +/* Start debugging the process whose number is PID. */ + +int +attach (pid) + int pid; +{ + errno = 0; + ptrace (PTRACE_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 (PTRACE_DETACH, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + int cwp; + struct rwindow local_and_ins; + + if (remote_debugging) + remote_fetch_registers (registers); + else + { + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); + + registers[REGISTER_BYTE (0)] = 0; + bcopy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (1)], 15 * 4); + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fpu_fr); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y; +/* *(int *)®isters[REGISTER_BYTE (RP_REGNUM)] = + inferior_registers.r_o7 + 8; + bcopy (&inferior_fp_registers.Fpu_fsr, + ®isters[REGISTER_BYTE (FPS_REGNUM)], + sizeof (FPU_FSR_TYPE)); */ + + read_inferior_memory (inferior_registers.r_sp, + ®isters[REGISTER_BYTE (16)], + 16*4); + } +} + +/* 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). */ + +void +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + if (remote_debugging) + remote_store_registers (registers); + else + { + int in_regs = 1, in_fpregs = 1, in_fparegs, in_cpregs = 1; + + if (regno >= 0) + if (FP0_REGNUM <= regno && regno <= FP0_REGNUM + 32) + in_regs = 0; + else + in_fpregs = 0; + + if (in_regs) + { + bcopy (®isters[REGISTER_BYTE (1)], + &inferior_registers.r_g1, 15 * 4); + + inferior_registers.r_ps = + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + inferior_registers.r_npc = + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)]; + inferior_registers.r_y = + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)]; + + write_inferior_memory (*(int *)®isters[REGISTER_BYTE (SP_REGNUM)], + ®isters[REGISTER_BYTE (16)], + 16*4); + } + if (in_fpregs) + { + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], + &inferior_fp_registers, + sizeof inferior_fp_registers.fpu_fr); + + /* bcopy (®isters[REGISTER_BYTE (FPS_REGNUM)], + &inferior_fp_registers.Fpu_fsr, + sizeof (FPU_FSR_TYPE)); + ****/ + } + + if (in_regs) + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + if (in_fpregs) + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); + } +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes 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; +} + + +/* Machine-dependent code which would otherwise be in core.c */ +/* Work with core dump and executable files, for GDB. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#define AOUTHDR struct exec +#endif + +extern char *sys_siglist[]; + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +#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 (); + +void +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) + { + 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); + + { + struct core corestr; + + val = myread (corechan, &corestr, sizeof corestr); + if (val < 0) + perror_with_name (filename); + if (corestr.c_magic != CORE_MAGIC) + error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", + filename, corestr.c_magic, (int) CORE_MAGIC); + else if (sizeof (struct core) != corestr.c_len) + error ("\"%s\" has an invalid struct core length (%d, expected %d)", + filename, corestr.c_len, (int) sizeof (struct core)); + + /* Note that data_start and data_end don't depend on the exec file */ + data_start = N_DATADDR (corestr.c_aouthdr); + data_end = data_start + corestr.c_dsize; + stack_start = stack_end - corestr.c_ssize; + data_offset = sizeof corestr; + stack_offset = sizeof corestr + corestr.c_dsize; + + /* G0 *always* holds 0. */ + *(int *)®isters[REGISTER_BYTE (0)] = 0; + /* The globals and output registers. */ + + bcopy (&corestr.c_regs.r_g1, ((int *) registers) + 1, 15 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = corestr.c_regs.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = corestr.c_regs.r_y; + + /* My best guess at where to get the locals and input + registers is exactly where they usually are, right above + the stack pointer. If the core dump was caused by a bus + writing off the stack pointer (as is possible) then this + won't work, but it's worth the try. */ + { + int sp; + + sp = *(int *)®isters[REGISTER_BYTE (SP_REGNUM)]; + lseek (corechan, sp - stack_start + stack_offset, L_SET); + if (16 * 4 != myread (corechan, + ®isters[REGISTER_BYTE (16)], + 16 * 4)) + /* fprintf so user can still use gdb */ + fprintf (stderr, "Couldn't read input and local registers from core file\n"); + } + + bcopy (corestr.c_fpu.fpu_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof corestr.c_fpu.fpu_regs); +#ifdef FPU + bcopy (&corestr.c_fpu.fpu_fsr, + ®isters[REGISTER_BYTE (FPS_REGNUM)], + sizeof (FPU_FSR_TYPE)); +#endif + + bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); + + printf ("Core file is from \"%s\".\n", corestr.c_cmdname); + if (corestr.c_signo > 0) + printf ("Program terminated with signal %d, %s.\n", + corestr.c_signo, + corestr.c_signo < NSIG + ? sys_siglist[corestr.c_signo] + : "(undocumented)"); + } + 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"); +} + +void +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + 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; + + 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); +} + +/* + * Find the pc saved in frame FRAME. + */ +CORE_ADDR +frame_saved_pc (frame) + FRAME frame; +{ + CORE_ADDR prev_pc; + + /* If it's at the bottom, the return value's stored in i7/rp */ + if (get_current_frame () == frame) + prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]); + else + /* Wouldn't this always work? This would allow this routine to + be completely a macro. */ + prev_pc = GET_RWINDOW_REG (frame->bottom, rw_in[7]); + + return PC_ADJUST (prev_pc); +} + +/* + * Since an individual frame in the frame cache is defined by two + * arguments (a frame pointer and a stack pointer), we need two + * arguments to get info for an arbitrary stack frame. This routine + * takes two arguments and makes the cached frames look as if these + * two arguments defined a frame on the cache. This allows the rest + * of info frame to extract the important arguments without + * difficulty. + */ +FRAME +setup_arbitrary_frame (frame, stack) + FRAME_ADDR frame, stack; +{ + struct frame_info *fci; + FRAME fid = create_new_frame (frame, 0); + + if (!fid) + fatal ("internal: create_new_frame returned invalid frame id"); + + fid->bottom = stack; + + return fid; +} + +/* This code was written by Gary Beihl (beihl@@mcc.com). + It was modified by Michael Tiemann (tiemann@@corto.inria.fr). */ + +struct command_line *get_breakpoint_commands (); + +/* + * This routine appears to be passed a size by which to increase the + * stack. It then executes a save instruction in the inferior to + * increase the stack by this amount. Only the register window system + * should be affected by this; the program counter & etc. will not be. + * + * This instructions used for this purpose are: + * + * sethi %hi(0x0),g1 * + * add g1,0x1ee0,g1 * + * save sp,g1,sp + * sethi %hi(0x0),g1 * + * add g1,0x1ee0,g1 * + * t g0,0x1,o0 + * sethi %hi(0x0),g0 (nop) + * + * I presume that these set g1 to be the negative of the size, do a + * save (putting the stack pointer at sp - size) and restore the + * original contents of g1. A * indicates that the actual value of + * the instruction is modified below. + */ +static int save_insn_opcodes[] = { + 0x03000000, 0x82007ee0, 0x9de38001, 0x03000000, + 0x82007ee0, 0x91d02001, 0x01000000 }; + +/* Neither do_save_insn or do_restore_insn save stack configuration + (since the stack is in an indeterminate state through the call to + each of them); that responsibility of the routine which calls them. */ + +void +do_save_insn (size) + int size; +{ + int g1 = read_register (1); + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR pc = read_register (PC_REGNUM); + CORE_ADDR npc = read_register (NPC_REGNUM); + CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes); + struct inferior_status inf_status; + + save_inferior_status (&inf_status, 0); /* Don't restore stack info */ + /* + * See above. + */ + save_insn_opcodes[0] = 0x03000000 | ((-size >> 10) & 0x3fffff); + save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff); + save_insn_opcodes[3] = 0x03000000 | ((g1 >> 10) & 0x3fffff); + save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff); + write_memory (fake_pc, save_insn_opcodes, sizeof (save_insn_opcodes)); + + clear_proceed_status (); + stop_after_trap = 1; + proceed (fake_pc, 0, 0); + + write_register (PC_REGNUM, pc); + write_register (NPC_REGNUM, npc); + restore_inferior_status (&inf_status); +} + +/* + * This routine takes a program counter value. It restores the + * register window system to the frame above the current one, and sets + * the pc and npc to the correct values. + */ + +/* The following insns translate to: + + restore + t g0,0x1,o0 + sethi %hi(0x0), g0 */ + +static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 }; + +void +do_restore_insn (pc) + CORE_ADDR pc; +{ + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR npc = pc + 4; + CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes); + struct inferior_status inf_status; + + save_inferior_status (&inf_status, 0); /* Don't restore stack info */ + + if (!pc) + abort(); + + write_memory (fake_pc, restore_insn_opcodes, sizeof (restore_insn_opcodes)); + + clear_proceed_status (); + stop_after_trap = 1; + proceed (fake_pc, 0, 0); + + write_register (PC_REGNUM, pc); + write_register (NPC_REGNUM, npc); + restore_inferior_status (&inf_status); +} + +/* + * This routine should be more specific in it's actions; making sure + * that it uses the same register in the initial prologue section. + */ +CORE_ADDR +skip_prologue (pc) + CORE_ADDR pc; +{ + union + { + union insn_fmt insn; + int i; + } x; + int dest = -1; + + x.i = read_memory_integer (pc, 4); + + /* Recognize sethi insn. Record destination. */ + if (x.insn.sethi.op == 0 + && x.insn.sethi.op2 == 4) + { + dest = x.insn.sethi.rd; + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* Recognizes an add immediate value to register to either %g1 or + the destination register recorded above. Actually, this might + well recognize several different arithmetic operations.*/ + if (x.insn.arith_imm.op == 2 + && x.insn.arith_imm.i == 1 + && (x.insn.arith_imm.rd == 1 + || x.insn.arith_imm.rd == dest)) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* This recognizes any SAVE insn. But why do the XOR and then + the compare? That's identical to comparing against 60 (as long + as there isn't any sign extension). */ + if (x.insn.arith.op == 2 + && (x.insn.arith.op3 ^ 32) == 28) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* Now we need to recognize stores into the frame from the input + registers. This recognizes all non alternate stores of input + register, into a location offset from the frame pointer. */ + while (x.insn.arith_imm.op == 3 + && (x.insn.arith_imm.op3 & 0x3c) == 4 /* Store, non-alt */ + && (x.insn.arith_imm.rd & 0x18) == 0x18 /* Input register */ + && x.insn.arith_imm.i == 1 /* Immediate mode */ + && x.insn.arith_imm.rs1 == 30 /* Off of frame pointer */ + && x.insn.arith_imm.simm >= 0x44 /* Into reserved */ + && x.insn.arith_imm.simm < 0x5b) /* stack space. */ + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + return pc; +} + +/* + * Check instruction at "addr" to see if it is an annulled branch. + * All other instructions will go to NPC or will trap. + * + * Set *target if we find a candidate branch; set to zero if not. + */ + +branch_type +isannulled (addr, target) + CORE_ADDR addr, *target; +{ + union insn_fmt instr; + branch_type val = not_branch; + long offset; /* Must be signed for sign-extend */ + + *target = 0; + instr.intval = read_memory_integer (addr, 4); + /* printf("intval = %x\n",instr.intval); */ + switch (instr.op1.op1) + { + case 0: /* Format 2 */ + switch(instr.op2.op2) + { + case 2: case 6: case 7: /* Bcc, FBcc, CBcc */ + if (instr.branch.cond == 8) + val = instr.branch.a ? baa : ba; + else + val = instr.branch.a ? bicca : bicc; + /* 22 bits, sign extended */ + offset = 4 * ((int) (instr.branch.disp << 10) >> 10); + *target = addr + offset; + break; + } + break; + } + /*printf("isannulled ret: %d\n",val); */ + return val; +} +@ + + +1.2 +log +@ * Use gdbcore.h rather than a bunch of externs. + * Avoid dependency on "exec file" when figuring out data_start and data_end +of core file. +@ +text +@d97 2 +a98 2 +static CORE_ADDR next_pc, pc8, target; +static int brkpc8, brktrg; +d113 2 +a114 1 + branch_type br, isabranch(); +d117 1 +a117 1 + pc8 = read_register (PC_REGNUM) + 8; /* branch not taken */ +d124 1 +d126 3 +a128 3 + /* printf ("set break at %x\n",next_pc); */ + br = isabranch (pc8 - 8, &target); + brkpc8 = brktrg = 0; +d130 7 +a136 6 + if (br == bicca && pc8 != next_pc) + { + /* Handle branches with care */ + brkpc8 = 1; + read_memory (pc8, break_mem[1], sizeof break_insn); + write_memory (pc8, break_insn, sizeof break_insn); +d140 2 +d157 1 +a157 1 + if (brkpc8) +d159 1 +a159 1 + write_memory (pc8, break_mem[1], sizeof break_insn); +d895 6 +a900 1 +/* Set *target if we find a branch. */ +d903 1 +a903 1 +isabranch (addr, target) +d918 1 +a918 1 + case 2: case 6: /* BICC & FBCC */ +d930 1 +a930 1 + /*printf("isabranch ret: %d\n",val); */ +@ + + +1.1 +log +@Initial revision +@ +text +@d29 1 +a453 49 +/* 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; + +d520 2 +a521 1 + data_start = exec_data_start; +a601 2 + data_start = 0; + data_end -= exec_data_start; +a644 2 + data_start = exec_data_start; + data_end += exec_data_start; +a661 2 + data_start = exec_data_start; + data_end += exec_data_start; +@ diff --git a/gdb/RCS/stack.c,v b/gdb/RCS/stack.c,v new file mode 100644 index 0000000..fc755c2 --- /dev/null +++ b/gdb/RCS/stack.c,v @@ -0,0 +1,882 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.02.09.23.53.05; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.02.09.15.03.51; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Avoid coredumps if stack commands are used when there is no stack. +@ +text +@/* Print and select stack frames for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 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! +*/ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.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; + +/* Error message when selected_frame is zero when it's needed */ +char no_sel_frame[] = "There is no current stack frame."; + +/* 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 address + 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. */ + +/* FIXME, the argument "frame" is always "selected_frame". This is why + we can say "No selected frame" if it == 0. Probably shouldn't be an + argument anymore... */ + +static void +print_stack_frame (frame, level, source) + FRAME frame; + int level; + int source; +{ + struct frame_info *fi; + + if (frame == 0) + error (no_sel_frame); + fi = get_frame_info (frame); + + print_frame_info (fi, level, source, 1); +} + +void +print_frame_info (fi, level, source, args) + struct frame_info *fi; + register int level; + int source; + int args; +{ + struct symtab_and_line sal; + struct symbol *func; + register char *funname = 0; + int numargs; + + sal = find_pc_line (fi->pc, fi->next_frame); + func = find_pc_function (fi->pc); + 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; + } + + if (source >= 0 || !sal.symtab) + { + if (level >= 0) + printf ("#%-2d ", level); + if (fi->pc != sal.pc || !sal.symtab) + printf ("0x%x in ", fi->pc); + printf ("%s (", funname ? funname : "??"); + if (args) + { + FRAME_NUM_ARGS (numargs, fi); + print_frame_args (func, fi, numargs, stdout); + } + printf (")"); + if (sal.symtab) + printf (" (%s line %d)", sal.symtab->filename, sal.line); + printf ("\n"); + } + + if (source != 0 && sal.symtab) + { + int done = 0; + int mid_statement = source < 0 && fi->pc != sal.pc; + if (frame_file_full_name) + done = identify_source_line (sal.symtab, sal.line, mid_statement); + if (!done) + { + if (mid_statement) + printf ("0x%x\t", fi->pc); + print_source_lines (sal.symtab, sal.line, sal.line + 1, 1); + } + current_source_line = max (sal.line - 5, 1); + } + if (source != 0) + set_default_breakpoint (1, fi->pc, sal.symtab, sal.line); + + fflush (stdout); +} + +/* Call here to print info on selected frame, after a trap. */ + +void +print_sel_frame (just_source) + int just_source; +{ + print_stack_frame (selected_frame, -1, just_source ? -1 : 1); +} + +/* Print info on the selected frame, including level number + but not source. */ + +void +print_selected_frame () +{ + print_stack_frame (selected_frame, selected_frame_level, 0); +} + +void flush_cached_frames (); /* FIXME, never called! */ + +#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: + if (selected_frame == 0) + error (no_sel_frame); + 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 */ +} + +/* 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; + int numargs; + + frame = parse_frame_specification (addr_exp); + + 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"); + printf (" Arglist at 0x%x,", FRAME_ARGS_ADDRESS (fi)); + FRAME_NUM_ARGS (i, fi); + if (i < 0) + printf (" args: "); + else if (i == 0) + printf (" no args."); + else if (i == 1) + printf (" 1 arg: "); + else + printf (" %d args: ", i); + + FRAME_NUM_ARGS (numargs, fi); + print_frame_args (func, fi, numargs, stdout); + printf ("\n"); + count = 0; + for (i = 0; i < NUM_REGS; i++) + if (fsr.regs[i]) + { + 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; + + if (have_inferior_p () == 0 && corefile == 0) + error ("There is no running program or core file."); + + /* 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 +#if 0 + count = backtrace_limit; +#else + count = -1; +#endif + + 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 ("(More stack frames follow...)\n"); +} + +/* Print the local variables of a block B active in FRAME. */ + +static void +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; + + 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) + { + fprintf (stream, "%s = ", SYMBOL_NAME (sym)); + print_variable_value (sym, frame, stream); + fprintf (stream, "\n"); + fflush (stream); + } + } +} + +/* 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; + + block = get_frame_block (frame); + if (block == 0) + return 0; + while (block != 0) + { + print_block_frame_locals (block, frame, stream); + /* 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); + } + return 1; +} + +static void +locals_info () +{ + if (selected_frame == 0) + error(no_sel_frame); + print_frame_local_vars (selected_frame, stdout); +} + +static int +print_frame_arg_vars (frame, stream) + register FRAME frame; + register FILE *stream; +{ + struct symbol *func; + register struct block *b; + int nsyms; + register int i; + register struct symbol *sym; + + func = get_frame_function (frame); + if (func == 0) + 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_REGPARM) + { + fprintf (stream, "%s = ", SYMBOL_NAME (sym)); + print_variable_value (sym, frame, stream); + fprintf (stream, "\n"); + fflush (stream); + } + } + + return 1; +} + +static void +args_info () +{ + if (selected_frame == 0) + error(no_sel_frame); + 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; +} + +/* 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; + + if (frame == 0) + error (no_sel_frame); + /* 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; + + frame = parse_frame_specification (level_exp); + + for (frame1 = get_prev_frame (0); + frame1 && frame1 != frame; + frame1 = get_prev_frame (frame1)) + level++; + + if (!frame1) + level = 0; + + select_frame (frame, level); + + if (!from_tty) + return; + + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +/* Select the frame up one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +static void +up_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 ("Initial frame selected; you cannot go up."); + select_frame (frame, selected_frame_level + count - count1); + + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +/* Select the frame down one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +static void +down_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); +} + +static void +return_command (retval_exp, from_tty) + char *retval_exp; + int from_tty; +{ + struct symbol *thisfun = get_frame_function (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. */ + + while (selected_frame != get_current_frame ()) + POP_FRAME; + + /* Then pop that frame. */ + + POP_FRAME; + + /* Compute the return value (if any) and store in the place + for return values. */ + + if (retval_exp) + set_return_value (parse_and_eval (retval_exp)); + + /* If interactive, print the frame that is now current. */ + + if (from_tty) + frame_command ("0", 1); +} + +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 +} + +@ + + +1.1 +log +@Initial revision +@ +text +@d2 1 +a2 1 + Copyright (C) 1986, 1987 Free Software Foundation, Inc. +d27 2 +d42 3 +d64 4 +d76 2 +d162 1 +a162 1 +void flush_cached_frames (); +d212 2 +d392 3 +d489 3 +a491 1 + register struct block *block = get_frame_block (frame); +d510 2 +d520 1 +a520 1 + struct symbol *func = get_frame_function (frame); +d526 1 +d551 2 +d610 2 +@ diff --git a/gdb/RCS/utils.c,v b/gdb/RCS/utils.c,v new file mode 100644 index 0000000..1d8000d --- /dev/null +++ b/gdb/RCS/utils.c,v @@ -0,0 +1,726 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.03.27.20.22.34; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.03.23.14.27.48; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@Portability changes. If USG, we need to re-enable the SIGINT +signal handler when it is called. Also, build the sys_siglist +table at runtime, based on the actual values of the signal +#define's. Too many USG systems added Berkeley signal names +as various numbers. +@ +text +@/* General utility routines for GDB, the GNU debugger. + Copyright (C) 1986 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! +*/ + +#include +#include +#include +#include +#include "defs.h" +#include "param.h" +#ifdef HAVE_TERMIO +#include +#endif + +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 () +{ + fflush (stdout); +#ifdef HAVE_TERMIO + ioctl (fileno (stdout), TCFLSH, 1); +#else /* not HAVE_TERMIO */ + ioctl (fileno (stdout), TIOCFLUSH, 0); +#endif /* not HAVE_TERMIO */ + +#ifdef TIOCGPGRP + error ("Quit"); +#else + error ("Quit (expect signal %d when inferior is resumed)", SIGINT); +#endif /* TIOCGPGRP */ +} + +/* Control C comes here */ + +void +request_quit () +{ + quit_flag = 1; + +#ifdef USG + /* Restore the signal handler */ + signal(SIGINT, request_quit); +#endif + + if (immediate_quit) + quit (); +} + +/* 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; +{ + 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); +} + +/* 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) + { + if (c == '\n') + fprintf (stream, "\\n"); + else if (c == '\b') + fprintf (stream, "\\b"); + else if (c == '\t') + fprintf (stream, "\\t"); + else if (c == '\f') + fprintf (stream, "\\f"); + else if (c == '\r') + fprintf (stream, "\\r"); + else if (c == 033) + fprintf (stream, "\\e"); + else if (c == '\a') + fprintf (stream, "\\a"); + else + fprintf (stream, "\\%03o", c); + } + else + { + if (c == '\\' || c == quoter) + fputc ('\\', stream); + fputc (c, 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); +} + +/* 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; +} + + +/* + * There is too much variation in Sys V signal numbers and names, so + * we must initialize them at runtime. If C provided a way to initialize + * an array based on subscript and value, this would not be necessary. + */ +static char undoc[] = "(undocumented)"; + +char *sys_siglist[NSIG]; + +_initialize_utils() +{ + int i; + + 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 */ + +@ + + +1.1 +log +@Initial revision +@ +text +@d223 1 +d237 6 +a506 26 +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", +}; + +d530 124 +@ diff --git a/gdb/RCS/valprint.c,v b/gdb/RCS/valprint.c,v new file mode 100644 index 0000000..52d89b0 --- /dev/null +++ b/gdb/RCS/valprint.c,v @@ -0,0 +1,1117 @@ +head 1.3; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.3 +date 89.04.26.01.49.11; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 89.04.26.00.57.15; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.04.25.15.16.40; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.3 +log +@Fix spelling Nan => NaN +@ +text +@/* Print values for GNU debugger gdb. + Copyright (C) 1986, 1988 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! +*/ + +#include +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "value.h" + +/* Maximum number of chars to print for a string pointer value + or vector contents. */ + +static 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 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) + value val; + FILE *stream; + char format; +{ + register 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)); + fputc ('{', stream); + /* Print arrays of characters using string syntax. */ + if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT + && format == 0) + { + fputc ('"', stream); + for (i = 0; i < n && i < print_max; i++) + { + QUIT; + printchar (VALUE_CONTENTS (val)[i], stream, '"'); + } + if (i < n) + fprintf (stream, "..."); + fputc ('"', stream); + } + else + { + for (i = 0; i < n && i < print_max; i++) + { + if (i) + fprintf (stream, ", "); + val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i, + VALUE_ADDRESS (val) + typelen * i, + stream, format, 1); + } + if (i < n) + fprintf (stream, "..."); + } + fputc ('}', 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 (stream, "("); + type_print (VALUE_TYPE (val), "", stream, -1); + fprintf (stream, ") "); + } + return val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), + VALUE_ADDRESS (val), stream, format, 1); + } +} + +/* 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. */ + +int +val_print (type, valaddr, address, stream, format, deref_ref) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + char format; + int deref_ref; +{ + register int i; + int len, n_baseclasses; + struct type *elttype; + int eltlen; + LONGEST val; + unsigned char c; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (TYPE_LENGTH (type) >= 0) + { + elttype = TYPE_TARGET_TYPE (type); + eltlen = TYPE_LENGTH (elttype); + len = TYPE_LENGTH (type) / eltlen; + fprintf (stream, "{"); + /* For an array of chars, print with string syntax. */ + if (eltlen == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT + && format == 0) + { + fputc ('"', stream); + for (i = 0; i < len && i < print_max; i++) + { + QUIT; + printchar (valaddr[i], stream, '"'); + } + if (i < len) + fprintf (stream, "..."); + fputc ('"', stream); + } + else + { + for (i = 0; i < len && i < print_max; i++) + { + if (i) fprintf (stream, ", "); + val_print (elttype, valaddr + i * eltlen, + 0, stream, format, deref_ref); + } + if (i < len) + fprintf (stream, "..."); + } + fprintf (stream, "}"); + break; + } + /* Array of unspecified length: treat like pointer. */ + + case TYPE_CODE_PTR: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + 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)); + struct fn_field *f; + int j, len2; + char *kind = ""; + + val = unpack_long (builtin_type_int, valaddr); + if (TYPE_CODE (target) == TYPE_CODE_FUNC) + { + 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) + { + fputc ('&', 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), stream); + else + type_print_method_args + (TYPE_FN_FIELD_ARGS (f, j), "", + TYPE_FN_FIELDLIST_NAME (domain, i), stream); + break; + } + } + else + { + /* 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); + val <<= 3; /* @@@@ Make VAL into bit offset */ + 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) + { + fputc ('&', stream); + type_print_base (domain, stream, 0, 0); + fprintf (stream, "::"); + fprintf (stream, "%s", TYPE_FIELD_NAME (domain, i)); + if (extra) + fprintf (stream, " + %d bytes", extra); + if (bits) + fprintf (stream, " (offset in bits)"); + break; + } + } + fputc ('(', stream); + type_print (type, "", stream, -1); + fprintf (stream, ") %d", val >> 3); + } + else + { + fprintf (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 + /* Convex needs this typecast to a long */ + && (long) unpack_long (type, valaddr) != 0 + && print_max) + { + fputc (' ', stream); + + /* Get first character. */ + if (read_memory ( (CORE_ADDR) unpack_long (type, valaddr), + &c, 1)) + { + /* First address out of bounds. */ + fprintf (stream, "
", + (* (int *) valaddr)); + break; + } + else + { + /* A real string. */ + int out_of_bounds = 0; + + fputc ('"', stream); + while (c) + { + QUIT; + printchar (c, stream, '"'); + if (++i >= print_max) + break; + if (read_memory ((CORE_ADDR) unpack_long (type, valaddr) + + i, &c, 1)) + { + /* This address was out of bounds. */ + fprintf (stream, + "\"***
", + (* (int *) valaddr) + i); + out_of_bounds = 1; + break; + } + } + if (!out_of_bounds) + { + fputc ('"', stream); + if (i == print_max) + fprintf (stream, "..."); + } + } + 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 (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); + } + else + fprintf (stream, "???"); + } + break; + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + fprintf (stream, "{"); + len = TYPE_NFIELDS (type); + n_baseclasses = TYPE_N_BASECLASSES (type); + for (i = 1; i <= n_baseclasses; i++) + { + fprintf (stream, "\n<%s> = ", TYPE_NAME (TYPE_BASECLASS (type, i))); + val_print (TYPE_FIELD_TYPE (type, 0), + valaddr + TYPE_FIELD_BITPOS (type, i-1) / 8, + 0, stream, 0, 0); + } + if (i > 1) fprintf (stream, "\nmembers of %s: ", TYPE_NAME (type)); + for (i -= 1; i < len; i++) + { + if (i > n_baseclasses) fprintf (stream, ", "); + fprintf (stream, "%s = ", TYPE_FIELD_NAME (type, i)); + /* 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); + } + else if (TYPE_FIELD_PACKED (type, i)) + { + val = unpack_field_as_long (type, valaddr, i); + val_print (TYPE_FIELD_TYPE (type, i), &val, 0, + stream, format, deref_ref); + } + else + { + val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / 8, + 0, stream, format, deref_ref); + } + } + fprintf (stream, "}"); + break; + + case TYPE_CODE_ENUM: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + len = TYPE_NFIELDS (type); + val = (long) unpack_long (builtin_type_int, valaddr); + for (i = 0; i < len; i++) + { + QUIT; + if (val == TYPE_FIELD_BITPOS (type, i)) + break; + } + if (i < len) + fprintf (stream, "%s", TYPE_FIELD_NAME (type, i)); + else + fprintf (stream, "%d", val); + break; + + case TYPE_CODE_FUNC: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + fprintf (stream, "{"); + type_print (type, "", stream, -1); + fprintf (stream, "} "); + fprintf (stream, "0x%x", address); + break; + + case TYPE_CODE_INT: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + fprintf (stream, + TYPE_UNSIGNED (type) ? "%u" : "%d", + unpack_long (type, valaddr)); + if (TYPE_LENGTH (type) == 1) + { + fprintf (stream, " '"); + printchar ((unsigned char) unpack_long (type, valaddr), + stream, '\''); + fputc ('\'', stream); + } + break; + + case TYPE_CODE_FLT: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + /* FIXME: When printing NaNs or invalid floats, print them + in raw hex in addition to the message. */ +#ifdef IEEE_FLOAT + if (is_nan ((void *)valaddr, TYPE_LENGTH(type))) + { + fprintf (stream, "NaN"); + break; + } +#endif + { + double doub; + int inv; + + doub = unpack_double (type, valaddr, &inv); + if (inv) + fprintf (stream, "Invalid float value"); + else + fprintf (stream, TYPE_LENGTH (type) <= 4? "%.6g": "%.16g", doub); + } + break; + + case TYPE_CODE_VOID: + fprintf (stream, "void"); + break; + + default: + error ("Invalid type code in symbol table."); + } + fflush (stream); +} + +#ifdef IEEE_FLOAT + +/* Nonzero if ARG (a double) is a NAN. */ + +int +is_nan (fp, len) + void *fp; + int len; +{ + int lowhalf, highhalf; + union ieee { + long i[2]; /* ASSUMED 32 BITS */ + float f; /* ASSUMED 32 BITS */ + double d; /* ASSUMED 64 BITS */ + } *arg; + + arg = (union ieee *)fp; + + /* + * Single precision float. + */ + if (len == sizeof(long)) { + highhalf = arg->i[0]; + return ((((highhalf >> 23) & 0xFF) == 0xFF) + && 0 != (highhalf & 0x7FFFFF)); + } + + /* Separate the high and low words of the double. + Distinguish big and little-endian machines. */ +#ifdef WORDS_BIG_ENDIAN + lowhalf = arg->i[1], highhalf = arg->i[0]; +#else + lowhalf = arg->i[0], highhalf = arg->i[1]; +#endif + + /* Nan: exponent is the maximum possible, and fraction is nonzero. */ + return (((highhalf>>20) & 0x7ff) == 0x7ff + && + ! ((highhalf & 0xfffff == 0) && (lowhalf == 0))); +} +#endif + +/* 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_ARRAY + || code == TYPE_CODE_MEMBER + || code == TYPE_CODE_REF))) + fprintf (stream, " "); + type_print_varspec_prefix (type, stream, show, 0); + fprintf (stream, "%s", varstring); + 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, stream) + struct type **args; + char *prefix, *varstring; + FILE *stream; +{ + int i; + + fprintf (stream, " %s%s (", prefix, varstring); + if (args[1] && args[1]->code != TYPE_CODE_VOID) + { + i = 1; /* skip the class variable */ + while (1) + { + type_print (args[i++], "", stream, 0); + if (!args[i]) + { + fprintf (stream, " ..."); + break; + } + else if (args[i]->code != TYPE_CODE_VOID) + { + fprintf (stream, ", "); + } + else break; + } + } + fprintf (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 (stream, ": %s%s %s ", + TYPE_VIA_PUBLIC (basetype) ? "public" : "private", + TYPE_VIA_VIRTUAL (basetype) ? " virtual" : "", + name + 1); + } + n_baseclasses = TYPE_N_BASECLASSES (basetype); + type = basetype; + } + + if (type) + { + if (n_baseclasses != 0) + fprintf (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 (stream, "%s%s %s", + TYPE_VIA_PUBLIC (basetype) ? "public" : "private", + TYPE_VIA_VIRTUAL (basetype) ? " virtual" : "", + name + 1); + } + if (i < n_baseclasses) + fprintf (stream, ", "); + } + putc (' ', 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); + fputc ('*', stream); + break; + + case TYPE_CODE_MEMBER: + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); + fputc (' ', stream); + type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, + passed_a_ptr); + fprintf (stream, "::"); + break; + + case TYPE_CODE_REF: + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + fputc ('&', stream); + break; + + case TYPE_CODE_FUNC: + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); + if (passed_a_ptr) + fputc ('(', stream); + break; + + case TYPE_CODE_ARRAY: + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); + } +} + +/* 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: + type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); + fprintf (stream, "["); + if (TYPE_LENGTH (type) >= 0 + && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) + fprintf (stream, "%d", + TYPE_LENGTH (type) / TYPE_LENGTH (TYPE_TARGET_TYPE (type))); + fprintf (stream, "]"); + break; + + case TYPE_CODE_MEMBER: + if (passed_a_ptr) + fputc (')', stream); + type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0); + 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 (stream, ")"); + fprintf (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 (stream, "type unknown"); + return; + } + + if (TYPE_NAME (type) && show <= 0) + { + fprintf (stream, TYPE_NAME (type)); + 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: + type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + + case TYPE_CODE_STRUCT: + fprintf (stream, "struct "); + goto struct_union; + + case TYPE_CODE_UNION: + fprintf (stream, "union "); + struct_union: + if (TYPE_NAME (type) && (name = TYPE_NAME (type))) + { + while (*name != ' ') name++; + fprintf (stream, "%s ", name + 1); + } + if (show < 0) + fprintf (stream, "{...}"); + else + { + int i; + + type_print_derivation_info (stream, type); + + fprintf (stream, "{"); + len = TYPE_NFIELDS (type); + if (len) fprintf (stream, "\n"); + else fprintf (stream, "\n"); + + /* If there is a base class for this type, + do not print the field that it occupies. */ + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + { + QUIT; + /* Don't print out virtual function table. */ + if (! strncmp (TYPE_FIELD_NAME (type, i), + "_vptr$", 6)) + continue; + + print_spaces (level + 4, stream); + if (TYPE_FIELD_STATIC (type, i)) + { + fprintf (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)) + { + /* ??? don't know what to put here ??? */; + } + fprintf (stream, ";\n"); + } + + /* C++: print out the methods */ + len = TYPE_NFN_FIELDS (type); + if (len) fprintf (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 (level + 4, stream); + if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + fprintf (stream, "virtual "); + type_print (TYPE_TARGET_TYPE (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), stream); + else + type_print_method_args + (TYPE_FN_FIELD_ARGS (f, j), "", + TYPE_FN_FIELDLIST_NAME (type, i), stream); + + fprintf (stream, ";\n"); + } + if (len2) fprintf (stream, "\n"); + } + + print_spaces (level, stream); + fputc ('}', stream); + } + break; + + case TYPE_CODE_ENUM: + fprintf (stream, "enum "); + if (TYPE_NAME (type)) + { + name = TYPE_NAME (type); + while (*name != ' ') name++; + fprintf (stream, "%s ", name + 1); + } + if (show < 0) + fprintf (stream, "{...}"); + else + { + fprintf (stream, "{"); + len = TYPE_NFIELDS (type); + lastval = 0; + for (i = 0; i < len; i++) + { + QUIT; + if (i) fprintf (stream, ", "); + fprintf (stream, "%s", TYPE_FIELD_NAME (type, i)); + if (lastval != TYPE_FIELD_BITPOS (type, i)) + { + fprintf (stream, " : %d", TYPE_FIELD_BITPOS (type, i)); + lastval = TYPE_FIELD_BITPOS (type, i); + } + lastval++; + } + fprintf (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)]; + fprintf (stream, "%s", name); + break; + + case TYPE_CODE_FLT: + name = float_type_table[TYPE_LENGTH (type)]; + fprintf (stream, "%s", name); + break; + + case TYPE_CODE_VOID: + fprintf (stream, "void"); + break; + + case 0: + fprintf (stream, "struct unknown"); + break; + + default: + error ("Invalid type code in symbol table."); + } +} + +static void +set_maximum_command (arg) + char *arg; +{ + if (!arg) error_no_arg ("value for maximum elements to print"); + print_max = atoi (arg); +} + +extern struct cmd_list_element *setlist; + +void +_initialize_valprint () +{ + add_cmd ("array-max", class_vars, set_maximum_command, + "Set NUMBER as limit on string chars or array elements to print.", + &setlist); + + 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"; +} + +@ + + +1.2 +log +@(1) Use XXX_BIG_ENDIAN macros rather than testing at runtime. +(2) Change args to is_nan, support floats, change one call to it. +(3) Change args to unpack_double. +@ +text +@d488 1 +a488 1 + fprintf (stream, "Nan"); +@ + + +1.1 +log +@Initial revision +@ +text +@d483 2 +d486 1 +a486 1 + if (is_nan (unpack_double (type, valaddr))) +d492 10 +a501 4 + if (TYPE_LENGTH (type) <= 4) + fprintf (stream, "%.6g", unpack_double (type, valaddr)); + else + fprintf (stream, "%.16g", unpack_double (type, valaddr)); +a515 5 +union ieee { + int i[2]; + double d; +}; + +d519 3 +a521 2 +is_nan (arg) + union ieee arg; +d524 16 +a539 1 + union { int i; char c; } test; +d543 5 +a547 6 + test.i = 1; + if (test.c != 1) + /* Big-endian machine */ + lowhalf = arg.i[1], highhalf = arg.i[0]; + else + lowhalf = arg.i[0], highhalf = arg.i[1]; +@ diff --git a/gdb/RCS/values.c,v b/gdb/RCS/values.c,v new file mode 100644 index 0000000..bc32f31 --- /dev/null +++ b/gdb/RCS/values.c,v @@ -0,0 +1,1047 @@ +head 1.2; +access ; +symbols ; +locks ; strict; +comment @ * @; + + +1.2 +date 89.04.26.01.05.45; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 89.04.25.15.38.44; author gnu; state Exp; +branches ; +next ; + + +desc +@@ + + +1.2 +log +@(1) use XXX_BIG_ENDIAN macros rather than runtime tests. +(2) Invalid values aren't stored in the value history, but they do +not cause an error; a -1 is returned as their value index. +(3) unpack_double takes a new arg, and callers check it. +@ +text +@ +/* Low level packing and unpacking of values for GDB. + Copyright (C) 1986, 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! +*/ + +#include +#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; + + 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 +history_info (num_exp) + char *num_exp; +{ + register int i; + register value val; + register int num; + + if (num_exp) + num = parse_and_eval_address (num_exp) - 5; + else + 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 ("$%d = ", i); + value_print (val, stdout, 0); + printf ("\n"); + } +} + +/* 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 = 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; + 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; +{ + 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; + + if (internalvars) + printf ("Debugger convenience variables:\n\n"); + else + 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"); + + for (var = internalvars; var; var = var->next) + { + printf ("$%s: ", var->name); + value_print (var->value, stdout, 0); + printf ("\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; + } + 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."); +} + +/* 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, + (LONGEST) 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); + + /* Pretend that this array is just an array of pointers to integers. + This will have to change for multiple inheritance. */ + vtbl = value_copy (value_field (arg1, TYPE_VPTR_FIELDNO (type))); + VALUE_TYPE (vtbl) = lookup_pointer_type (builtin_type_int); + + /* Index into the virtual function table. */ + vfn = value_subscript (vtbl, vi); + + /* 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 target 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; + + bcopy (addr, &oword, sizeof oword); + + /* Shifting for bit field depends on endianness of the target 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_ENUM || + 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 ("history", history_info, + "Elements of value history (around item number IDX, or last ten)."); +} + +@ + + +1.1 +log +@Initial revision +@ +text +@d182 2 +a183 1 + register int i; +d185 6 +a190 3 + /* Get error now if about to store an invalid float. */ + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT) + value_as_double (val); +d427 7 +a433 1 + return unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val)); +d510 5 +d516 1 +a516 1 +unpack_double (type, valaddr) +d519 1 +d525 1 +d528 4 +a531 2 + if (INVALID_FLOAT (valaddr, len)) + error ("Invalid floating value found in program."); +a770 1 + union { int i; char c; } test; +d774 6 +a779 7 + /* Extracting bits depends on endianness of the machine. */ + test.i = 1; + if (test.c == 1) + /* Little-endian. */ + val = val >> (bitpos % 8); + else + val = val >> (sizeof val * 8 - bitpos % 8 - bitsize); +a791 1 + union { int i; char c; } test; +d795 4 +a798 5 + /* Shifting for bit field depends on endianness of the machine. */ + test.i = 1; + if (test.c != 1) + /* not little-endian: assume big-endian. */ + bitpos = sizeof oword * 8 - bitpos - bitsize; +@ diff --git a/gdb/README b/gdb/README index 095136b..d45a905 100644 --- a/gdb/README +++ b/gdb/README @@ -1,15 +1,10 @@ This is GDB, a source-level debugger intended for GNU, presently running under un*x. -Before compiling GDB, you must set up links to four files according to +Before compiling GDB, you must set up links to five files according to the kind of machine you are running on. To do this, type `config.gdb machine', where machine is something like `vax' or `sun2'. This -creates links named `param.h', `m-init.h', `opcode.h', and `pinsn.c'. -(Note: we lack information on certain machines.) - -Also, `Makefile' must be changed to say `OBSTACK = obstack.o' instead -of `OBSTACK=-lobstack' (unless you want to install obstack.o as -/lib/libobstack.a). +creates links named `param.h', `opcode.h', `pinsn.c', and `infdep.c'. Once these files are set up, just `make' will do everything, producing an executable `gdb' in this directory. @@ -21,12 +16,52 @@ m-.h This file contains macro definitions that express information about the machine's registers, stack frame format and instructions. -m-init.h - -This file defines one macro, which says how to round up from the -address of the end of the text of one .o file to the beginning of -the text of the next .o file. - -opcode.h, -pinsn.c These files contain the information necessary to print instructions for your cpu type. + +-dep.c +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 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, you want to make sure that gdb is not compiled with shared +libraries on the Sun 4. And you want to 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. + +About languages other than C... + +C++ support has been integrated into gdb; it works, but somewhat +buggily. Pascal support has not yet been integrated in gdb; the work +is being done. + +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. + +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. + diff --git a/gdb/TAGS b/gdb/TAGS deleted file mode 100644 index 1059758..0000000 --- a/gdb/TAGS +++ /dev/null @@ -1,1265 +0,0 @@ - -command.h,0 - -defs.h,42 -#define max(24,1043 -#define min(23,1001 - -environ.h,0 - -expression.h,0 - -frame.h,0 - -inferior.h,0 - -initialize.h,0 - -m-hp9k320.h,1013 -#define ABOUT_TO_RETURN(105,3032 -#define EXTRACT_RETURN_VALUE(208,6644 -#define EXTRACT_STRUCT_VALUE_ADDRESS(221,7151 -#define FIX_CALL_DUMMY(446,16959 -#define FP_REGISTER_ADDR(230,7519 -#define FRAME_ARGS_ADDRESS(267,8872 -#define FRAME_CHAIN(256,8511 -#define FRAME_CHAIN_COMBINE(261,8700 -#define FRAME_CHAIN_VALID(258,8581 -#define FRAME_FIND_SAVED_REGS(303,10241 -#define FRAME_LOCALS_ADDRESS(269,8915 -#define FRAME_NUM_ARGS(276,9170 -#define FRAME_NUM_ARGS(279,9219 -#define FRAME_SAVED_PC(265,8804 -#define INIT_STACK(472,17773 -#define INIT_STACK(510,18982 -#define INVALID_FLOAT(109,3166 -#define REGISTER_ADDR(223,7216 -#define REGISTER_BYTE(150,4692 -#define REGISTER_CONVERTIBLE(178,5623 -#define REGISTER_CONVERT_TO_RAW(192,6086 -#define REGISTER_CONVERT_TO_VIRTUAL(183,5790 -#define REGISTER_RAW_SIZE(159,5027 -#define REGISTER_VIRTUAL_SIZE(165,5283 -#define REGISTER_VIRTUAL_TYPE(201,6367 -#define SAVED_PC_AFTER_CALL(73,2290 -#define SKIP_PROLOGUE(60,1854 -#define STORE_RETURN_VALUE(214,6848 - -m-isi-ov.h,1008 -#define ABOUT_TO_RETURN(140,5051 -#define EXTRACT_RETURN_VALUE(262,9368 -#define EXTRACT_STRUCT_VALUE_ADDRESS(275,9875 -#define FIX_CALL_DUMMY(479,18585 -#define FRAME_ARGS_ADDRESS(304,10929 -#define FRAME_CHAIN(293,10568 -#define FRAME_CHAIN_COMBINE(298,10757 -#define FRAME_CHAIN_VALID(295,10638 -#define FRAME_FIND_SAVED_REGS(334,12123 -#define FRAME_LOCALS_ADDRESS(306,10972 -#define FRAME_NUM_ARGS(311,11108 -#define FRAME_SAVED_PC(302,10861 -#define INIT_STACK(503,19381 -#define INVALID_FLOAT(144,5185 -#define N_DATADDR(124,4514 -#define N_TXTADDR(129,4693 -#define REGISTER_BYTE(204,7416 -#define REGISTER_CONVERTIBLE(232,8347 -#define REGISTER_CONVERT_TO_RAW(246,8810 -#define REGISTER_CONVERT_TO_VIRTUAL(237,8514 -#define REGISTER_RAW_SIZE(213,7751 -#define REGISTER_U_ADDR(183,6543 -#define REGISTER_VIRTUAL_SIZE(219,8007 -#define REGISTER_VIRTUAL_TYPE(255,9091 -#define SAVED_PC_AFTER_CALL(101,3958 -#define SKIP_PROLOGUE(81,3287 -#define STORE_RETURN_VALUE(268,9572 -#define vprintf(403,15501 - -m-isiinit.h,61 -#define FILEADDR_ROUND(8,252 -#define FILEADDR_ROUND(10,294 - -m-merlin.h,942 -#define ABOUT_TO_RETURN(86,2669 -#define EXTRACT_RETURN_VALUE(223,7393 -#define EXTRACT_STRUCT_VALUE_ADDRESS(236,7900 -#define FIX_CALL_DUMMY(378,12958 -#define FRAME_ARGS_ADDRESS(266,8999 -#define FRAME_CHAIN(254,8606 -#define FRAME_CHAIN_COMBINE(259,8795 -#define FRAME_CHAIN_VALID(256,8676 -#define FRAME_FIND_SAVED_REGS(308,10367 -#define FRAME_LOCALS_ADDRESS(268,9044 -#define FRAME_NUM_ARGS(273,9182 -#define FRAME_SAVED_PC(263,8899 -#define INIT_STACK(407,13935 -#define INVALID_FLOAT(90,2801 -#define REGISTER_BYTE(169,5699 -#define REGISTER_CONVERTIBLE(195,6521 -#define REGISTER_CONVERT_TO_RAW(206,6864 -#define REGISTER_CONVERT_TO_VIRTUAL(200,6655 -#define REGISTER_RAW_SIZE(176,5972 -#define REGISTER_U_ADDR(133,4302 -#define REGISTER_VIRTUAL_SIZE(182,6197 -#define REGISTER_VIRTUAL_TYPE(212,7060 -#define SAVED_PC_AFTER_CALL(58,2000 -#define SKIP_PROLOGUE(44,1503 -#define STORE_RETURN_VALUE(229,7597 -#define vprintf(327,11196 - -m-news800.h,823 -#define ABOUT_TO_RETURN(113,3361 -#define FIX_CALL_DUMMY(424,15770 -#define FRAME_ARGS_ADDRESS(252,8217 -#define FRAME_CHAIN(241,7856 -#define FRAME_CHAIN_COMBINE(246,8045 -#define FRAME_CHAIN_VALID(243,7926 -#define FRAME_FIND_SAVED_REGS(282,9411 -#define FRAME_LOCALS_ADDRESS(254,8260 -#define FRAME_NUM_ARGS(259,8396 -#define FRAME_SAVED_PC(250,8149 -#define INIT_STACK(449,16582 -#define INIT_STACK(454,16709 -#define INVALID_FLOAT(117,3495 -#define REGISTER_BYTE(171,5439 -#define REGISTER_CONVERTIBLE(199,6370 -#define REGISTER_CONVERT_TO_RAW(213,6833 -#define REGISTER_CONVERT_TO_VIRTUAL(204,6537 -#define REGISTER_RAW_SIZE(180,5774 -#define REGISTER_U_ADDR(151,4766 -#define REGISTER_VIRTUAL_SIZE(186,6030 -#define REGISTER_VIRTUAL_TYPE(222,7114 -#define SAVED_PC_AFTER_CALL(85,2672 -#define SKIP_PROLOGUE(71,2209 - -m-newsinit.h,29 -#define FILEADDR_ROUND(4,99 - -m-sparcinit.h,29 -#define FILEADDR_ROUND(5,94 - -m-sun2.h,947 -#define ABOUT_TO_RETURN(83,2582 -#define EXTRACT_RETURN_VALUE(169,5390 -#define EXTRACT_STRUCT_VALUE_ADDRESS(182,5897 -#define FIX_CALL_DUMMY(367,13680 -#define FRAME_ARGS_ADDRESS(219,7266 -#define FRAME_CHAIN(208,6905 -#define FRAME_CHAIN_COMBINE(213,7094 -#define FRAME_CHAIN_VALID(210,6975 -#define FRAME_FIND_SAVED_REGS(255,8635 -#define FRAME_LOCALS_ADDRESS(221,7309 -#define FRAME_NUM_ARGS(228,7564 -#define FRAME_NUM_ARGS(231,7613 -#define FRAME_SAVED_PC(217,7198 -#define INIT_STACK(391,14476 -#define INVALID_FLOAT(87,2716 -#define REGISTER_BYTE(125,4079 -#define REGISTER_CONVERTIBLE(148,4697 -#define REGISTER_CONVERT_TO_RAW(158,5009 -#define REGISTER_CONVERT_TO_VIRTUAL(153,4831 -#define REGISTER_RAW_SIZE(130,4244 -#define REGISTER_U_ADDR(189,6193 -#define REGISTER_VIRTUAL_SIZE(135,4399 -#define REGISTER_VIRTUAL_TYPE(163,5174 -#define SAVED_PC_AFTER_CALL(55,1913 -#define SKIP_PROLOGUE(42,1477 -#define STORE_RETURN_VALUE(175,5594 - -m-sun2init.h,29 -#define FILEADDR_ROUND(5,94 - -m-sun3.h,913 -#define ABOUT_TO_RETURN(82,2531 -#define EXTRACT_RETURN_VALUE(185,6164 -#define EXTRACT_STRUCT_VALUE_ADDRESS(198,6671 -#define FIX_CALL_DUMMY(423,16227 -#define FRAME_ARGS_ADDRESS(244,8135 -#define FRAME_CHAIN(233,7774 -#define FRAME_CHAIN_COMBINE(238,7963 -#define FRAME_CHAIN_VALID(235,7844 -#define FRAME_FIND_SAVED_REGS(280,9504 -#define FRAME_LOCALS_ADDRESS(246,8178 -#define FRAME_NUM_ARGS(253,8433 -#define FRAME_NUM_ARGS(256,8482 -#define FRAME_SAVED_PC(242,8067 -#define INIT_STACK(447,17023 -#define INVALID_FLOAT(86,2665 -#define REGISTER_BYTE(127,4212 -#define REGISTER_CONVERTIBLE(155,5143 -#define REGISTER_CONVERT_TO_RAW(169,5606 -#define REGISTER_CONVERT_TO_VIRTUAL(160,5310 -#define REGISTER_RAW_SIZE(136,4547 -#define REGISTER_VIRTUAL_SIZE(142,4803 -#define REGISTER_VIRTUAL_TYPE(178,5887 -#define SAVED_PC_AFTER_CALL(59,2006 -#define SKIP_PROLOGUE(46,1570 -#define STORE_RETURN_VALUE(191,6368 - -m-sun4.h,985 -#define ABOUT_TO_RETURN(89,2910 -#define EXTRACT_RETURN_VALUE(198,6697 -#define EXTRACT_STRUCT_VALUE_ADDRESS(211,7282 -#define FIX_CALL_DUMMY(482,17052 -#define FRAME_ARGS_ADDRESS(271,9251 -#define FRAME_CHAIN(258,8815 -#define FRAME_CHAIN_COMBINE(264,9012 -#define FRAME_CHAIN_VALID(261,8890 -#define FRAME_FIND_SAVED_REGS(300,10368 -#define FRAME_LOCALS_ADDRESS(275,9344 -#define FRAME_NUM_ARGS(282,9599 -#define FRAME_SAVED_PC(268,9116 -#define FRAME_STRUCT_ARGS_ADDRESS(273,9294 -#define GET_RWINDOW_REG(238,8005 -#define INVALID_FLOAT(94,3065 -#define PC_ADJUST(59,2068 -#define REGISTER_BYTE(147,5292 -#define REGISTER_CONVERTIBLE(174,5926 -#define REGISTER_CONVERT_TO_RAW(185,6245 -#define REGISTER_CONVERT_TO_VIRTUAL(179,6062 -#define REGISTER_RAW_SIZE(154,5462 -#define REGISTER_VIRTUAL_SIZE(161,5626 -#define REGISTER_VIRTUAL_TYPE(191,6415 -#define SAVED_PC_AFTER_CALL(61,2160 -#define SKIP_PROLOGUE(47,1624 -#define STACK_ALIGN(73,2395 -#define STORE_RETURN_VALUE(204,6963 - -m-suninit.h,29 -#define FILEADDR_ROUND(5,94 - -m-umax.h,913 -#define ABOUT_TO_RETURN(93,2734 -#define EXTRACT_RETURN_VALUE(235,7459 -#define EXTRACT_STRUCT_VALUE_ADDRESS(248,8098 -#define FIX_CALL_DUMMY(427,14369 -#define FRAME_ARGS_ADDRESS(279,9207 -#define FRAME_CHAIN(266,8812 -#define FRAME_CHAIN_COMBINE(271,9001 -#define FRAME_CHAIN_VALID(268,8882 -#define FRAME_FIND_SAVED_REGS(345,11372 -#define FRAME_LOCALS_ADDRESS(283,9332 -#define FRAME_NUM_ARGS(301,9969 -#define FRAME_SAVED_PC(275,9105 -#define INVALID_FLOAT(101,2907 -#define REGISTER_BYTE(179,5711 -#define REGISTER_CONVERTIBLE(205,6533 -#define REGISTER_CONVERT_TO_RAW(216,6876 -#define REGISTER_CONVERT_TO_VIRTUAL(210,6667 -#define REGISTER_RAW_SIZE(186,5984 -#define REGISTER_U_ADDR(143,4391 -#define REGISTER_VIRTUAL_SIZE(192,6209 -#define REGISTER_VIRTUAL_TYPE(222,7072 -#define SAVED_PC_AFTER_CALL(70,2211 -#define SKIP_PROLOGUE(56,1709 -#define STORE_RETURN_VALUE(241,7730 -#define vprintf(376,12597 - -m-umaxinit.h,30 -#define FILEADDR_ROUND(4,100 - -m-vax.h,940 -#define ABOUT_TO_RETURN(84,2628 -#define EXTRACT_RETURN_VALUE(178,5780 -#define EXTRACT_STRUCT_VALUE_ADDRESS(191,6287 -#define FIX_CALL_DUMMY(323,11747 -#define FRAME_ARGS_ADDRESS(226,7647 -#define FRAME_CHAIN(212,7106 -#define FRAME_CHAIN_COMBINE(217,7300 -#define FRAME_CHAIN_VALID(214,7181 -#define FRAME_FIND_SAVED_REGS(249,8503 -#define FRAME_LOCALS_ADDRESS(231,7822 -#define FRAME_NUM_ARGS(236,7958 -#define FRAME_SAVED_PC(221,7404 -#define INIT_STACK(346,12521 -#define INVALID_FLOAT(89,2816 -#define REGISTER_BYTE(132,4469 -#define REGISTER_CONVERTIBLE(155,5082 -#define REGISTER_CONVERT_TO_RAW(166,5397 -#define REGISTER_CONVERT_TO_VIRTUAL(160,5216 -#define REGISTER_RAW_SIZE(137,4631 -#define REGISTER_U_ADDR(117,3893 -#define REGISTER_VIRTUAL_SIZE(142,4784 -#define REGISTER_VIRTUAL_TYPE(172,5565 -#define SAVED_PC_AFTER_CALL(57,1954 -#define SKIP_PROLOGUE(46,1557 -#define STORE_RETURN_VALUE(184,5984 -#define vprintf(194,6403 - -m-vaxinit.h,29 -#define FILEADDR_ROUND(5,94 - -m68k-opcode.h,138 -#define one(130,5680 -int numopcodes=sizeof(1270,68164 -struct m68k_opcode *endop = m68k_opcodes+sizeof(1272,68226 -#define two(131,5707 - -ns32k-opcode.h,0 - -obstack.h,1054 -#define obstack_1grow(314,13600 -#define obstack_1grow(391,16272 -#define obstack_1grow_fast(277,12314 -#define obstack_alignment_mask(269,12044 -#define obstack_alloc(329,14107 -#define obstack_alloc(402,16645 -#define obstack_base(257,11715 -#define obstack_begin(274,12205 -#define obstack_blank(321,13836 -#define obstack_blank(396,16436 -#define obstack_blank_fast(279,12381 -#define obstack_chunk_size(261,11804 -#define obstack_copy(334,14262 -#define obstack_copy(405,16740 -#define obstack_copy0(339,14428 -#define obstack_copy0(408,16847 -#define obstack_finish(344,14596 -#define obstack_finish(411,16956 -#define obstack_free(356,15060 -#define obstack_free(423,17388 -#define obstack_free(430,17721 -#define obstack_grow(295,12915 -#define obstack_grow(376,15705 -#define obstack_grow0(304,13236 -#define obstack_grow0(383,15967 -#define obstack_init(271,12101 -#define obstack_next_free(265,11918 -#define obstack_object_size(287,12633 -#define obstack_object_size(370,15515 -#define obstack_room(291,12777 -#define obstack_room(373,15613 - -param.h,0 - -sparc-opcode.h,0 - -symseg.h,0 - -symtab.h,3053 -#define BLOCKLIST(110,3968 -#define BLOCKLIST_BLOCK(121,4345 -#define BLOCKLIST_NBLOCKS(120,4287 -#define BLOCKVECTOR(111,4016 -#define BLOCKVECTOR_BLOCK(123,4464 -#define BLOCKVECTOR_NBLOCKS(122,4404 -#define BLOCK_END(129,4678 -#define BLOCK_FUNCTION(132,4788 -#define BLOCK_NSYMS(130,4714 -#define BLOCK_SHOULD_SORT(136,4948 -#define BLOCK_START(128,4638 -#define BLOCK_SUPERBLOCK(133,4830 -#define BLOCK_SYM(131,4750 -#define B_CLR(153,5603 -#define B_SET(152,5557 -#define B_TST(154,5650 -#define LINELIST(115,4116 -#define LINETABLE(116,4161 -#define SET_TYPE_CHAIN(181,7118 -#define SET_TYPE_FIELD_PRIVATE(193,7827 -#define SET_TYPE_FIELD_PROTECTED(194,7915 -#define SET_TYPE_FN_PRIVATE(220,9426 -#define SET_TYPE_FN_PROTECTED(221,9511 -#define SYMBOL_BLOCK_VALUE(143,5248 -#define SYMBOL_CLASS(140,5095 -#define SYMBOL_NAME(138,4999 -#define SYMBOL_NAMESPACE(139,5042 -#define SYMBOL_TYPE(144,5305 -#define SYMBOL_VALUE(141,5140 -#define SYMBOL_VALUE_BYTES(142,5191 -#define TYPEVECTOR(113,4067 -#define TYPEVECTOR_NTYPES(125,4526 -#define TYPEVECTOR_TYPE(126,4581 -#define TYPE_BASECLASS(176,6799 -#define TYPE_BASECLASSES(175,6740 -#define TYPE_CHAIN(180,7048 -#define TYPE_CODE(165,6219 -#define TYPE_DOMAIN_TYPE(170,6437 -#define TYPE_FIELD(183,7210 -#define TYPE_FIELDS(167,6315 -#define TYPE_FIELD_BITPOS(187,7469 -#define TYPE_FIELD_BITSIZE(188,7537 -#define TYPE_FIELD_NAME(185,7328 -#define TYPE_FIELD_PACKED(189,7607 -#define TYPE_FIELD_PRIVATE(195,8007 -#define TYPE_FIELD_PRIVATE_BITS(191,7677 -#define TYPE_FIELD_PROTECTED(196,8090 -#define TYPE_FIELD_PROTECTED_BITS(192,7750 -#define TYPE_FIELD_STATIC(201,8315 -#define TYPE_FIELD_STATIC_PHYSNAME(202,8391 -#define TYPE_FIELD_TYPE(184,7264 -#define TYPE_FIELD_VALUE(186,7392 -#define TYPE_FLAGS(163,6099 -#define TYPE_FN_FIELD(210,8851 -#define TYPE_FN_FIELDLIST(205,8543 -#define TYPE_FN_FIELDLIST1(206,8611 -#define TYPE_FN_FIELDLISTS(204,8480 -#define TYPE_FN_FIELDLIST_LENGTH(208,8768 -#define TYPE_FN_FIELDLIST_NAME(207,8690 -#define TYPE_FN_FIELDS(172,6559 -#define TYPE_FN_FIELD_ARGS(213,9015 -#define TYPE_FN_FIELD_NAME(211,8897 -#define TYPE_FN_FIELD_PHYSNAME(214,9074 -#define TYPE_FN_FIELD_TYPE(212,8956 -#define TYPE_FN_FIELD_VIRTUAL_P(215,9141 -#define TYPE_FN_FIELD_VOFFSET(216,9208 -#define TYPE_FN_PRIVATE(222,9600 -#define TYPE_FN_PRIVATE_BITS(218,9278 -#define TYPE_FN_PROTECTED(223,9681 -#define TYPE_FN_PROTECTED_BITS(219,9350 -#define TYPE_FUNCTION_TYPE(160,5926 -#define TYPE_HAS_CONSTRUCTOR(199,8245 -#define TYPE_HAS_DESTRUCTOR(198,8178 -#define TYPE_LENGTH(162,6050 -#define TYPE_MAIN_VARIANT(161,5989 -#define TYPE_NAME(156,5696 -#define TYPE_NFIELDS(166,6264 -#define TYPE_NFN_FIELDS(173,6614 -#define TYPE_NFN_FIELDS_TOTAL(174,6671 -#define TYPE_N_BASECLASSES(177,6869 -#define TYPE_POINTER_TYPE(158,5800 -#define TYPE_REFERENCE_TYPE(159,5861 -#define TYPE_TARGET_TYPE(157,5741 -#define TYPE_UNSIGNED(164,6146 -#define TYPE_VIA_PUBLIC(178,6932 -#define TYPE_VIA_VIRTUAL(179,6989 -#define TYPE_VPTR_BASETYPE(169,6374 -#define TYPE_VPTR_FIELDNO(171,6498 - -value.h,465 -#define COERCE_ARRAY(63,2095 -#define COERCE_ENUM(75,2527 -#define VALUE_ADDRESS(48,1560 -#define VALUE_BITPOS(52,1752 -#define VALUE_BITSIZE(51,1710 -#define VALUE_CONTENTS(46,1469 -#define VALUE_INTERNALVAR(49,1611 -#define VALUE_LVAL(47,1524 -#define VALUE_NEXT(53,1792 -#define VALUE_OFFSET(50,1670 -#define VALUE_REGNO(56,1922 -#define VALUE_REPEATED(54,1828 -#define VALUE_REPETITIONS(55,1872 -#define VALUE_TYPE(45,1433 -typedef struct value *value;43,1403 - -vax-opcode.h,0 - -wait.h,381 -#define WCOREDUMP(13,439 -#define WCOREDUMP(22,735 -#define WIFEXITED(10,338 -#define WIFSIGNALED(9,274 -#define WIFSTOPPED(8,231 -#define WRETCODE(11,377 -#define WRETCODE(20,667 -#define WSETEXIT(15,511 -#define WSETEXIT(24,805 -#define WSETSTOP(16,556 -#define WSETSTOP(25,859 -#define WSTOPSIG(12,408 -#define WSTOPSIG(21,701 -#define WTERMSIG(14,478 -#define WTERMSIG(23,771 - -blockframe.c,436 -block_for_pc 226,5551 -block_innermost_frame 333,8062 -find_pc_function 281,6687 -find_pc_misc_function 295,7020 -get_current_block 187,4699 -get_current_frame 47,1559 -get_frame_block 177,4550 -get_frame_function 213,5267 -get_frame_info 90,2667 -get_frame_pc 155,4014 -get_frame_saved_regs 166,4200 -get_pc_function_start 193,4771 -get_prev_frame 66,1899 -get_prev_frame_info 132,3578 -initialize 354,8465 -set_current_frame 56,1711 - -breakpoint.c,1272 -#define ALL_BREAKPOINTS(71,2545 -break_command 716,17619 -break_command_1 630,15552 -breakpoint_1 394,10213 -breakpoint_auto_delete 809,19886 -breakpoint_cond_eval 326,8672 -breakpoint_here_p 310,8342 -breakpoint_stop_status 340,9123 -breakpoints_info 443,11295 -check_duplicates 508,12789 -clear_breakpoint_commands 223,6282 -clear_breakpoints 879,21268 -clear_command 732,17867 -clear_momentary_breakpoints 578,14320 -commands_command 156,4505 -condition_command 109,3533 -delete_breakpoint 826,20191 -delete_command 855,20711 -describe_other_breakpoints 462,11663 -disable_breakpoint 999,23686 -disable_command 1008,23819 -do_breakpoint_commands 205,5722 -enable_breakpoint 983,23447 -enable_command 992,23578 -enable_delete_breakpoint 1036,24304 -enable_delete_command 1045,24441 -enable_once_breakpoint 1020,24048 -enable_once_command 1029,24186 -get_breakpoint_commands 234,6567 -ignore_command 919,22160 -initialize 1059,24694 -insert_breakpoints 252,6958 -map_breakpoint_numbers 948,22766 -mark_breakpoints_out 297,8031 -remove_breakpoints 273,7497 -set_breakpoint 594,14672 -set_breakpoint_commands 240,6634 -set_default_breakpoint 491,12319 -set_ignore_count 889,21493 -set_momentary_breakpoint 566,14096 -set_raw_breakpoint 529,13309 -tbreak_command 724,17742 - -coffread.c,1050 -add_symbol_to_list 225,6438 -coff_alloc_type 202,5823 -coff_lookup_type 182,5228 -compare_misc_functions 529,14918 -compare_symbols 598,16344 -complete_symtab 413,11870 -condense_misc_bunches 555,15422 -decode_base_type 1563,39950 -decode_function_type 1548,39618 -decode_type 1479,37981 -discard_misc_bunches 542,15230 -end_symtab 429,12358 -enter_linenos 1212,30818 -finish_block 241,6832 -free_stringtab 1133,29359 -get_sym_file 759,20200 -getfilename 1161,29821 -getsymname 1141,29455 -hashname 1234,31433 -init_lineno 1188,30416 -init_misc_functions 501,14285 -init_stringtab 1103,28765 -initialize 1839,46671 -make_blockvector 320,8988 -patch_opaque_types 1282,32593 -patch_type 1255,31713 -process_coff_symbol 1343,34294 -read_aout_hdr 1039,27250 -read_coff_symtab 782,20785 -read_enum_type 1760,44558 -read_file_hdr 1020,26946 -read_one_sym 1073,27964 -read_section_hdr 1052,27503 -read_struct_type 1667,42201 -record_line 358,10096 -record_misc_function 509,14399 -sort_syms 610,16735 -start_symtab 391,11203 -symbol_file_command 634,17279 - -command.c,151 -add_alias_cmd 153,6583 -add_cmd 128,6035 -add_prefix_cmd 189,7646 -delete_cmd 210,8187 -help_cmd 242,9021 -lookup_cmd 348,12157 -savestring 458,14397 - -core.c,438 -#define N_DATADDR(61,1786 -#define N_TXTADDR(57,1716 -close_exec_file 478,13099 -core_file_command 152,3832 -exec_file_command 358,9878 -files_info 538,14419 -get_exec_file 522,14168 -have_core_file_p 532,14358 -initialize 757,19721 -myread 713,18965 -read_memory 581,15412 -register_addr 740,19450 -reopen_exec_file 485,13183 -specify_exec_file_hook 468,12870 -validate_files 501,13589 -write_memory 597,15819 -xfer_core_file 608,16084 - -dbxread.c,1462 -#define READ_FILE_HEADERS(89,2958 -#define READ_STRING_TABLE_SIZE(76,2527 -add_file_command 1992,54601 -add_new_header_file 446,13178 -add_old_header_file 417,12160 -add_symbol_to_list 597,17499 -add_this_object_header_file 397,11533 -compare_misc_functions 1100,30965 -compare_symbols 1169,32408 -condense_addl_misc_bunches 1949,53491 -condense_misc_bunches 1126,31469 -dbx_alloc_type 554,16390 -dbx_lookup_type 504,14951 -define_symbol 2110,57727 -discard_misc_bunches 1113,31277 -end_symtab 924,26590 -explicit_lookup_type 576,16967 -fill_in_vptr_fieldno 3202,88273 -fill_symbuf 1413,38804 -finish_block 662,19042 -free_header_files 373,10951 -get_sym_file 1389,38146 -hash_symsegs 1610,43975 -hashname 1583,43452 -init_header_files 360,10600 -init_misc_functions 1072,30359 -initialize 3211,88488 -make_blockvector 749,21453 -new_object_header_files 386,11261 -next_symbol_text 1429,39280 -obconcat 286,7989 -obsavestring 264,7482 -pop_subfile 1030,29518 -process_one_symbol 1641,44793 -push_subfile 1016,29167 -read_addl_syms 1807,49601 -read_args 3166,87336 -read_dbx_symtab 1444,39759 -read_enum_type 2954,81399 -read_number 3127,86628 -read_range_type 3035,83673 -read_struct_type 2537,70010 -read_type 2363,65510 -read_type_number 2336,64855 -really_free_pendings 626,18257 -record_line 788,22636 -record_misc_function 1080,30473 -sort_syms 1188,32958 -start_subfile 867,24832 -start_symtab 823,23610 -symbol_file_command 1213,33536 -xxmalloc 251,7214 - -environ.c,215 -environ_vector 172,6802 -free_environ 126,5799 -get_in_environ 181,6937 -init_environ 142,6126 -make_environ 111,5501 -#define max(104,5377 -#define min(103,5335 -set_in_environ 200,7272 -unset_in_environ 240,8026 - -eval.c,343 -evaluate_expression 113,3186 -evaluate_subexp 132,3580 -evaluate_subexp_for_address 753,21631 -evaluate_subexp_for_sizeof 822,23400 -evaluate_subexp_with_coercion 790,22587 -evaluate_type 124,3434 -initialize 863,24505 -parse_and_eval 64,1980 -parse_and_eval_address 33,1188 -parse_and_eval_address_1 50,1650 -parse_to_comma_and_eval 82,2437 - -expprint.c,49 -print_expression 88,3265 -print_subexp 102,3660 - -expread.tab.c,405 - } YYSTYPE;68,1351 -copy_name 600,13369 -end_arglist 130,2654 -free_funcalls 144,2956 -length_of_subexp 634,14273 -parse_c_1 841,18977 -parse_c_expression 882,20067 -parse_number 254,5961 -prefixify_expression 614,13705 -prefixify_subexp 720,15905 -start_arglist 116,2295 -write_exp_elt 163,3413 -write_exp_elt2 182,3891 -write_exp_string 202,4389 -yyerror 591,13214 -yylex 352,8004 -yyparse(1076,27837 - -findvar.c,309 -find_saved_register 38,1432 -initialize 418,11075 -locate_var_value 350,9332 -read_register 165,4621 -read_register_bytes 140,4050 -read_relative_register_raw_bytes 68,2095 -read_var_value 208,5693 -supply_register 196,5370 -value_of_register 102,2842 -write_register 175,4862 -write_register_bytes 151,4328 - -firstfile.c,89 -initialize_all_files 136,6474 -initialize_dummy_1 148,6803 -initialize_dummy_2 156,6962 - -infcmd.c,625 -attach_command 743,17529 -cont_command 193,4509 -detach_command 804,18802 -environment_info 520,12243 -finish_command 441,10308 -have_inferior_p 111,3062 -initialize 830,19303 -jump_command 297,6565 -next_command 230,5225 -nexti_command 244,5427 -program_info 498,11638 -read_memory_integer 583,13660 -read_pc 616,14256 -registers_info 633,14521 -run_command 136,3461 -run_stack_dummy 392,8855 -set_args_command 117,3127 -set_environment_command 540,12645 -signal_command 350,7685 -step_1 250,5504 -step_command 222,5073 -stepi_command 238,5350 -tty_command 126,3268 -unset_environment_command 572,13421 -write_pc 621,14320 - -inflow.c,863 -#define FP_REGISTER_ADDR_DIFF(597,15092 -#define INFERIOR_AR0(600,15202 -attach 447,10389 -create_inferior 337,8134 -detach 463,10694 -fetch_inferior_register 606,15358 -fetch_inferior_registers 477,10917 -fetch_inferior_registers 691,17315 -fetch_inferior_registers 737,18541 -inferior_died 405,9600 -initialize 931,23638 -kill_command 383,9216 -kill_inferior 394,9439 -new_tty 301,7373 -read_inferior_memory 818,20685 -resume 420,9929 -store_inferior_register 659,16562 -store_inferior_register_1 637,16062 -store_inferior_registers 525,12906 -store_inferior_registers 708,17865 -store_inferior_registers 768,19359 -term_status_command 261,6253 -terminal_inferior 140,3396 -terminal_init_inferior 115,2925 -terminal_ours 189,4596 -terminal_ours_1 198,4690 -terminal_ours_for_output 176,4359 -try_writing_regs_command 905,23128 -write_inferior_memory 851,21716 - -infrun.c,504 -attach_program 314,8812 -typedef char binsn_quantum[1060,30158 -} branch_type;1056,30076 -clear_proceed_status 138,4165 -do_restore_insn 1152,32540 -do_save_insn 1123,31691 -handle_command 866,24714 -initialize 986,28123 -insert_step_breakpoint 844,24137 - int 1065,30266 -normal_stop 752,21425 -proceed 166,5015 -remove_step_breakpoint 856,24439 -signals_info 948,27162 -1064,30245 -start_inferior 256,7357 -start_remote 296,8452 -static 1061,30205 -wait_for_inferior 337,9429 -writing_pc 244,7041 - -kdb-start.c,14 -start 10,140 - -lastfile.c,28 -initialize_last_file 4,144 - -m68k-pinsn.c,361 -#define NEXTBYTE(43,1554 -#define NEXTDOUBLE(54,1819 -#define NEXTEXTEND(57,1877 -#define NEXTLONG(48,1671 -#define NEXTPACKED(61,1995 -#define NEXTSINGLE(51,1762 -#define NEXTWORD(45,1602 -convert_from_68881 713,16403 -convert_to_68881 744,17120 -fetch_arg 504,12093 -print_base 693,15901 -print_indexed 603,13882 -print_insn 71,2389 -print_insn_arg 163,4738 - -main.c,898 -add_com 576,14145 -add_com_alias 588,14372 -add_info 544,13435 -add_info_alias 555,13621 -catch_errors 107,2877 -cd_command 1004,27712 -command_loop 358,9348 -copying_info 717,17065 -define_command 634,15182 -do_nothing 351,9248 -document_command 672,16144 -dont_repeat 398,10258 -dump_me_command 1122,29783 -echo_command 1096,29399 -error_no_arg 598,14570 -execute_command 316,8410 -free_command_lines 526,13126 -help_command 605,14664 -info_command 567,13949 -initialize_main 1132,29938 -input_from_terminal_p 983,27266 -main 129,3255 -print_gdb_version 898,25598 -print_prompt 918,26096 -pwd_command 989,27337 -quit_command 965,26902 -read_command_lines 475,11852 -read_line 409,10517 -return_to_top_level 90,2414 -set_prompt_command 927,26237 -source_cleanup 1065,28927 -source_command 1073,29029 -stop_sig 381,9897 -validate_comname 613,14815 -version_info 908,25948 -warranty_info 868,24187 - -ns32k-pinsn.c,239 -bit_extract 44,1387 -dbit_extract 84,1931 -fbit_extract 72,1766 -flip_bytes 104,2319 -get_displacement 374,8548 -ns32k_get_enter_addr 437,10241 -ns32k_localcount 408,9359 -print_insn 125,2670 -print_insn_arg 203,4273 -sign_extend 96,2170 - -obstack.c,333 -POINTER 235,9170 -POINTER 241,9271 -POINTER 303,10462 -POINTER 309,10567 -POINTER 316,10703 -POINTER 324,10877 -_obstack_begin 129,6001 -_obstack_free 199,8125 -_obstack_newchunk 160,6918 -int 247,9382 -int 253,9493 -obstack_free 196,8096 -void 259,9590 -void 267,9754 -void 275,9920 -void 282,10055 -void 289,10181 -void 296,10326 - -pinsn.c,0 - -printcmd.c,735 -address_info 454,10758 -clear_displays 740,17163 -decode_format 79,2326 -delete_current_display 877,19858 -delete_display 755,17374 -display_command 681,16122 -display_info 889,20136 -do_displays 865,19608 -do_examine 299,7212 -do_one_display 824,18641 -free_display 728,16945 -initialize 1219,28520 -output_command 415,9952 -print_address 276,6680 -print_command 375,9121 -print_formatted 124,3359 -print_frame_args 930,21221 -print_frame_nameless_args 1036,24443 -print_scalar_formatted 167,4519 -print_variable_value 915,20777 -printf_command 1054,24820 -ptype_command 600,14097 -set_command 443,10508 -set_next_address 261,6316 -undisplay_command 788,17991 -validate_format 360,8682 -whatis_command 575,13624 -x_command 527,12318 - -remote.c,549 -dcache_alloc 548,11397 -dcache_fetch 565,11765 -dcache_flush 496,10383 -dcache_hit 513,10675 -dcache_init 606,12650 -dcache_poke 582,12129 -dcache_value 534,11060 -fromhex 142,3412 -getpkt 439,9223 -static initialize 619,12989 -putpkt 391,8356 -readchar 428,9019 -remote_fetch_registers 201,4442 -remote_fetch_word 253,5426 -remote_open 113,2896 -remote_read_bytes 322,6929 -remote_resume 168,3801 -remote_send 376,8094 -remote_store_registers 227,4964 -remote_store_word 274,5810 -remote_wait 184,4062 -remote_write_bytes 288,6178 -tohex 156,3656 - -source.c,446 -directories_info 94,2657 -directory_command 118,3174 -find_source_lines 286,7082 -forward_search_command 676,17065 -get_filename_and_charpos 365,9017 -identify_source_line 397,9886 -init_source_path 100,2748 -initialize 823,20501 -line_info 621,15649 -list_command 476,11651 -openp 222,5609 -print_source_lines 416,10378 -reverse_search_command 746,18689 -select_source_symtab 57,1795 -source_charpos_line 339,8377 -source_line_charpos 325,8081 - -sparc-pinsn.c,267 -} branch_type;129,2729 -fprint_addr1 414,9505 -fprint_c_ldst 514,11525 -fprint_f_ldst 487,11019 -fprint_fpop 539,12023 -fprint_ldst 460,10530 -fprint_mem 435,9924 -frame_saved_pc 773,16590 -isabranch 710,15193 -print_insn 176,4188 -CORE_ADDR skip_prologue 742,15962 - -stack.c,534 -args_info 363,9268 -backtrace_command 244,6639 -down_command 522,13605 -find_relative_frame 415,10667 -frame_command 468,12280 -frame_info 161,4481 -get_selected_block 395,9963 -initialize 582,15010 -locals_info 325,8530 -print_block_frame_locals 269,7179 -print_frame_arg_vars 331,8612 -print_frame_info 75,2329 -print_frame_local_vars 304,8012 -print_sel_frame 143,4033 -print_selected_frame 152,4238 -print_stack_frame 62,2126 -record_selected_frame 383,9671 -return_command 540,14105 -select_frame 372,9468 -up_command 501,13013 - -standalone.c,1165 -_exit 437,8550 -_flsbuf 326,6852 -access 76,1743 -chdir 62,1588 -close 164,4224 -core_file_command 340,7028 -exec_file_command 337,7003 -execle 434,8536 -exit 81,1771 -fault 515,9980 -fclose 189,4597 -fdopen 183,4539 -fflush 331,6910 -fgetc 247,5466 -fopen 175,4414 -fprintf 298,6263 -fputc 314,6593 -fread 229,5154 -fstat 195,4647 -fwrite 305,6422 -get_exec_file 344,7060 -getpid 54,1543 -getrlimit 475,9022 -getwd 66,1608 -have_core_file_p 351,7193 -initialize 586,11703 -ioctl 45,1478 -kill 51,1531 -kill_command 356,7230 -lseek 266,5714 -malloc_warning 442,8592 -myread 208,4831 -open 129,3606 -printf 291,6110 -ptrace 428,8507 -read_inferior_register 373,7378 -read_memory 376,7408 -read_register 398,7781 -restore_gdb 529,10299 -resume 491,9446 -save_frame_pointer 503,9650 -save_registers 541,10644 -sbrk 452,8708 -setpgrp 431,8521 -int (* signal 48,1506 -sigsetmask 59,1570 -int kdb_stack_beg[STACK_SIZE / sizeof 582,11630 -terminal_inferior 361,7271 -terminal_init_inferior 367,7317 -terminal_ours 364,7296 -ulimit 464,8930 -vfork 418,8217 -vlimit 470,8972 -wait 555,10992 -write_inferior_register 370,7347 -write_memory 386,7581 -write_register 407,7950 - -stuff.c,70 -err 162,5253 -find_symbol 141,4686 -get_offset 97,3038 -main 32,1184 - -symmisc.c,532 -#define CORE_RELOCATE(156,4674 -#define RELOCATE(146,4235 -#define TEXT_RELOCATE(160,4829 -#define UNRELOCATE(150,4430 -block_depth 552,15350 -free_all_symtabs 38,1310 -free_symtab 92,2701 -free_symtab_block 70,1994 -initialize 561,15491 -print_symbol 451,12880 -print_symtabs 383,11097 -read_symsegs 347,10121 -relocate_block 227,6794 -relocate_blockvector 215,6485 -relocate_source 324,9379 -relocate_sourcevector 312,9108 -relocate_symbol 252,7454 -relocate_symtab 181,5623 -relocate_type 293,8716 -relocate_typevector 273,8107 - -symtab.c,1103 -block_function 650,18342 -compare_symbols 1583,42494 -decode_line_1 985,26867 -decode_line_2 1296,35899 -decode_line_spec 1281,35508 -find_line_common 895,24554 -find_line_pc 830,22800 -find_line_pc_range 852,23329 -find_pc_line 692,19389 -find_pc_line_pc_range 946,25446 -find_pc_symtab 662,18575 -functions_info 1560,42158 -init_type 1606,43102 -initialize 1631,43703 -list_symbols 1455,39402 -lookup_basetype_type 292,8824 -lookup_block_symbol 569,16313 -lookup_enum 166,4764 -lookup_function_type 351,10506 -lookup_member_type 244,7428 -lookup_misc_func 1393,38114 -lookup_pointer_type 185,5371 -lookup_reference_type 212,6279 -lookup_struct 134,3830 -lookup_symbol 524,15219 -lookup_symbol_1 468,13881 -lookup_symbol_2 490,14356 -lookup_symtab 58,1935 -lookup_typename 85,2565 -lookup_union 150,4299 -lookup_unsigned_typename 116,3352 -methods_info 1574,42330 -smash_to_function_type 445,13239 -smash_to_member_type 403,12047 -smash_to_pointer_type 382,11491 -smash_to_reference_type 422,12587 -sort_block_syms 1595,42885 -sources_info 1405,38345 -types_info 1567,42246 -variables_info 1553,42070 - -utils.c,382 -concat 267,6227 -discard_cleanups 89,2568 -do_cleanups 73,2189 -error 226,5353 -fatal 241,5712 -free_current_contents 109,2978 -make_cleanup 53,1721 -parse_escape 336,8051 -perror_with_name 147,3761 -print_spaces 279,6469 -print_sys_errmsg 173,4320 -printchar 403,9096 -query 293,6833 -quit 196,4760 -request_quit 214,5114 -savestring 256,6060 -xmalloc 120,3191 -xrealloc 132,3411 - -valarith.c,333 -binop_user_defined_p 120,3330 -initialize 536,13968 -int unop_user_defined_p 140,4066 -value_add 33,1153 -value_binop 283,8790 -value_equal 435,11202 -value_less 479,12413 -value_lognot 524,13697 -value_neg 506,13286 -value_sub 72,2127 -value_subscript 107,2996 -value_x_binop 157,4648 -value_x_unop 237,7399 -value_zerop 411,10851 - -valops.c,538 -call_function 406,11494 -check_field 799,21547 -destructor_name_p 772,20847 -initialize 1036,27337 -push_bytes 328,9807 -push_word 308,9441 -int typecmp(968,25919 -value_addr 249,7552 -value_arg_coerce 368,10600 -value_arg_push 391,11047 -value_assign 88,2873 -value_at 71,2465 -value_cast 34,1302 -value_coerce_array 221,6762 -value_ind 276,8307 -value_of_this 997,26533 -value_of_variable 211,6556 -value_push 347,10148 -value_repeat 188,5971 -value_string 534,14856 -value_struct_elt 609,16972 -value_struct_elt_for_address 872,23241 - -valprint.c,293 -initialize 922,23635 -is_nan 475,12348 -set_maximum_command 914,23489 -type_print 504,13250 -type_print_1 515,13476 -type_print_base 691,18041 -type_print_method_args 543,14320 -type_print_varspec_prefix 581,15207 -type_print_varspec_suffix 630,16398 -val_print 125,3755 -value_print 48,1661 - -values.c,852 -access_value_history 212,5551 -allocate_repeat_value 83,2505 -allocate_value 59,1948 -clear_internalvars 372,9256 -clear_value_history 251,6511 -convenience_info 387,9492 -free_all_values 108,3143 -history_info 270,6920 -initialize 884,23003 -internalvar_name 362,9065 -lookup_internalvar 308,7855 -modify_field 751,19493 -record_latest_value 178,4634 -release_value 125,3410 -set_internalvar 352,8896 -set_internalvar_component 337,8502 -set_return_value 858,22452 -unpack_double 495,12241 -unpack_field_as_long 727,18919 -unpack_long 436,10879 -value_as_double 419,10272 -value_as_long 412,10152 -value_being_returned 837,21874 -value_copy 151,3834 -value_field 559,13788 -value_fn_field 595,14830 -value_from_double 803,20832 -value_from_long 775,20072 -value_of_internalvar 327,8301 -value_static_field 665,17504 -value_virtual_fn_field 623,15815 - -vax-pinsn.c,44 -print_insn 42,1456 -print_insn_arg 86,2396 - -version.c,0 - -xgdb.c,679 -addbutton 420,9859 -breakpoint_button 288,7520 -breakpoint_button_1 265,7032 -cont_button 365,8944 -create_buttons 436,10258 -create_label 460,10963 -create_text_widget 475,11357 -deiconify_button 382,9170 -down_button 410,9706 -explicit_breakpoint_button 314,7948 -finish_button 373,9052 -garbage 301,7681 -iconify_button 389,9303 -initialize 660,16261 -next_button 349,8728 -print_1 222,6172 -print_button 249,6740 -print_prompt 209,5879 -print_star_button 255,6789 -step_button 357,8836 -until_button 294,7585 -up_button 402,9602 -xgdb_create_window 489,11713 -xgdb_dispatch 618,15369 -xgdb_display_exec_file 195,5595 -xgdb_display_source 93,2553 -xgdb_window_hook 650,16099 diff --git a/gdb/a.out.encap.h b/gdb/a.out.encap.h new file mode 100644 index 0000000..8885455 --- /dev/null +++ b/gdb/a.out.encap.h @@ -0,0 +1,112 @@ +/* + * another try at encapsulating bsd object files in coff + * by Pace Willisson 12/9/88 + * + * This time, we will only use the coff headers to tell the kernel + * how to exec the file. Therefore, the only fields that need to + * be filled in are the scnptr and vaddr for the text and data + * sections, and the vaddr for the bss. As far as coff is concerned, + * there is no symbol table, relocation, or line numbers. + * + * A normal bsd header (struct exec) is placed after the coff headers, + * and before the real text. I defined a the new fields 'a_machtype' + * and a_flags. If a_machtype is M_386, and a_flags & A_ENCAP is + * true, then the bsd header is preceeded by a coff header. Macros + * like N_TXTOFF and N_TXTADDR use this field to find the bsd header. + * + * The only problem is to track down the bsd exec header. The + * macros HEADER_OFFSET, etc do this. Look at nm.c, dis.c, etc + * for examples. + */ + +#include "a.out.gnu.h" + +#define N_FLAGS_COFF_ENCAPSULATE 0x20 /* coff header precedes bsd header */ + +/* Describe the COFF header used for encapsulation. */ + +struct coffheader +{ + /* filehdr */ + unsigned short f_magic; + unsigned short f_nscns; + long f_timdat; + long f_symptr; + long f_nsyms; + unsigned short f_opthdr; + unsigned short f_flags; + /* aouthdr */ + short magic; + short vstamp; + long tsize; + long dsize; + long bsize; + long entry; + long text_start; + long data_start; + struct coffscn + { + char s_name[8]; + long s_paddr; + long s_vaddr; + long s_size; + long s_scnptr; + long s_relptr; + long s_lnnoptr; + unsigned short s_nreloc; + unsigned short s_nlnno; + long s_flags; + } scns[3]; +}; + +/* Describe some of the parameters of the encapsulation, + including how to find the encapsulated BSD header. */ + +#ifdef i386 +#define COFF_MAGIC 0514 /* I386MAGIC */ +#endif + +#if defined(i386) +short __header_offset_temp; +#define HEADER_OFFSET(f) \ + (__header_offset_temp = 0, \ + fread ((char *)&__header_offset_temp, sizeof (short), 1, (f)), \ + fseek ((f), -sizeof (short), 1), \ + __header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0) + +#define HEADER_OFFSET_FD(fd) \ + (__header_offset_temp = 0, \ + read ((fd), (char *)&__header_offset_temp, sizeof (short)), \ + lseek ((fd), -sizeof (short), 1), \ + __header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0) + + +#else +#define HEADER_OFFSET(f) 0 +#define HEADER_OFFSET_FD(fd) 0 +#endif + +#define HEADER_SEEK(f) (fseek ((f), HEADER_OFFSET((f)), 1)) +#define HEADER_SEEK_FD(fd) (lseek ((fd), HEADER_OFFSET_FD((fd)), 1)) + + +/* Describe the characteristics of the BSD header + that appears inside the encapsulation. */ + +#undef _N_HDROFF +#undef N_TXTADDR +#undef N_DATADDR + +#define _N_HDROFF(x) ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + sizeof (struct coffheader) : 0) + +/* Address of text segment in memory after it is loaded. */ +#define N_TXTADDR(x) \ + ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + sizeof (struct coffheader) + sizeof (struct exec) : 0) + +#define SEGMENT_SIZE 0x400000 +#define N_DATADDR(x) \ + ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))) : \ + (N_TXTADDR(x)+(x).a_text)) diff --git a/gdb/a.out.gnu.h b/gdb/a.out.gnu.h new file mode 100644 index 0000000..2409bec --- /dev/null +++ b/gdb/a.out.gnu.h @@ -0,0 +1,182 @@ +#ifndef __A_OUT_GNU_H__ +#define __A_OUT_GNU_H__ + +#define __GNU_EXEC_MACROS__ + +#ifndef __STRUCT_EXEC_OVERRIDE__ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#endif /* __STRUCT_EXEC_OVERRIDE__ */ + +/* these go in the N_MACHTYPE field */ +enum machine_type { + M_OLDSUN2 = 0, + M_68010 = 1, + M_68020 = 2, + M_SPARC = 3, + /* skip a bunch so we don't run into any of sun's numbers */ + M_386 = 100, +}; + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#define N_SET_INFO(exec, magic, type, flags) \ + ((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#define N_SET_MAGIC(exec, magic) \ + ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) + +#define N_SET_MACHTYPE(exec, machtype) \ + ((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) + +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) + +/* Code indicating object file or impure executable. */ +#define OMAGIC 0407 +/* Code indicating pure executable. */ +#define NMAGIC 0410 +/* Code indicating demand-paged executable. */ +#define ZMAGIC 0413 + +#define N_BADMAG(x) \ + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) + +#define _N_HDROFF(x) (1024 - sizeof (struct exec)) + +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec)) + +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) + +#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) + +#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) + +#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) + +#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) + +/* Address of text segment in memory after it is loaded. */ +#define N_TXTADDR(x) 0 + +/* Address of data segment in memory after it is loaded. + Note that it is up to you to define SEGMENT_SIZE + on machines not listed here. */ +#ifdef vax +#define SEGMENT_SIZE page_size +#endif +#ifdef is68k +#define SEGMENT_SIZE 0x20000 +#endif + +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+(x).a_text) \ + : (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1)))) +#endif + +/* Address of bss segment in memory after it is loaded. */ +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) + +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; + } n_un; + char n_type; + char n_other; + short n_desc; + unsigned n_value; +}; + +#define N_UNDF 0 +#define N_ABS 2 +#define N_TEXT 4 +#define N_DATA 6 +#define N_BSS 8 +#define N_FN 15 + +#define N_EXT 1 +#define N_TYPE 036 +#define N_STAB 0340 + +/* 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. */ +#define N_INDR 0xa + +/* 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. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct relocation_info +{ + /* Address (within segment) to be relocated. */ + int r_address; + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in file's the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* Four bits that aren't used, but when writing an object file + it is desirable to clear them. */ + unsigned int r_pad:4; +}; + + +#endif /* __A_OUT_GNU_H__ */ diff --git a/gdb/alloca.c b/gdb/alloca.c new file mode 100644 index 0000000..cfe98f9 --- /dev/null +++ b/gdb/alloca.c @@ -0,0 +1,191 @@ +/* + alloca -- (mostly) portable public-domain implementation -- D A Gwyn + + last edit: 86/05/30 rms + include config.h, since on VMS it renames some symbols. + Use xmalloc instead of malloc. + + This implementation of the PWB library alloca() function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + + It should work under any C implementation that uses an + actual procedure stack (as opposed to a linked list of + frames). There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca()-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. +*/ +#ifndef lint +static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ +#endif + +#ifdef emacs +#include "config.h" +#ifdef static +/* actually, only want this if static is defined as "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif static +#endif emacs + +#ifdef X3J11 +typedef void *pointer; /* generic pointer type */ +#else +typedef char *pointer; /* generic pointer type */ +#endif + +#define NULL 0 /* null pointer constant */ + +extern void free(); +extern pointer xmalloc(); + +/* + Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown +*/ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* direction unknown */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* known at compile-time */ + +#else /* STACK_DIRECTION == 0; need run-time code */ + +static int stack_dir; /* 1 or -1 once known */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (/* void */) +{ + static char *addr = NULL; /* address of first + `dummy', once known */ + auto char dummy; /* to get stack address */ + + if (addr == NULL) + { /* initial entry */ + addr = &dummy; + + find_stack_direction (); /* recurse once */ + } + else /* second entry */ + if (&dummy > addr) + stack_dir = 1; /* stack grew upward */ + else + stack_dir = -1; /* stack grew downward */ +} + +#endif /* STACK_DIRECTION == 0 */ + +/* + An "alloca header" is used to: + (a) chain together all alloca()ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc() + alignment chunk size. The following default should work okay. +*/ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* to force sizeof(header) */ + struct + { + union hdr *next; /* for chaining headers */ + char *deep; /* for stack depth measure */ + } h; +} header; + +/* + alloca( size ) returns a pointer to at least `size' bytes of + storage which will be automatically reclaimed upon exit from + the procedure that called alloca(). Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. +*/ + +static header *last_alloca_header = NULL; /* -> last alloca header */ + +pointer +alloca (size) /* returns pointer to storage */ + unsigned size; /* # bytes to allocate */ +{ + auto char probe; /* probes stack depth: */ + register char *depth = &probe; + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* unknown growth direction */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca()ed storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* traverses linked list */ + + for (hp = last_alloca_header; hp != NULL;) + if (STACK_DIR > 0 && hp->h.deep > depth + || STACK_DIR < 0 && hp->h.deep < depth) + { + register header *np = hp->h.next; + + free ((pointer) hp); /* collect garbage */ + + hp = np; /* -> next header */ + } + else + break; /* rest are not deeper */ + + last_alloca_header = hp; /* -> last valid storage */ + } + + if (size == 0) + return NULL; /* no allocation required */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = xmalloc (sizeof (header) + size); + /* address of header */ + + ((header *)new)->h.next = last_alloca_header; + ((header *)new)->h.deep = depth; + + last_alloca_header = (header *)new; + + /* User storage begins just after header. */ + + return (pointer)((char *)new + sizeof(header)); + } +} + diff --git a/gdb/alloca.o b/gdb/alloca.o new file mode 100644 index 0000000..1d14b03 Binary files /dev/null and b/gdb/alloca.o differ diff --git a/gdb/blockframe.c b/gdb/blockframe.c index 86ff033..451af1a 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -20,7 +20,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "frame.h" @@ -39,7 +38,12 @@ static FRAME current_frame; struct block *block_for_pc (); CORE_ADDR get_pc_function_start (); -START_FILE +/* + * 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. */ @@ -59,6 +63,31 @@ set_current_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. */ @@ -66,98 +95,154 @@ FRAME get_prev_frame (frame) FRAME frame; { - CORE_ADDR pointer; - /* The caller of "no frame" is the innermost frame. */ - if (frame == 0) - return get_current_frame (); - - /* 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. */ - pointer = FRAME_CHAIN (frame); - if (!FRAME_CHAIN_VALID (pointer, frame)) - return 0; - /* If frame has a caller, combine the chain pointer and the frame's own - address to get the address of the caller. */ - return FRAME_CHAIN_COMBINE (pointer, frame); + /* We're allowed to know that FRAME and "struct frame_info *" are + the same */ + return get_prev_frame_info (frame); +} + +/* + * 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 +struct frame_info * get_frame_info (frame) FRAME frame; { - struct frame_info val; - FRAME current = get_current_frame (); - register FRAME frame1, frame2; + return frame; +} - val.frame = frame; +/* Return a structure containing various interesting information + about the frame that called NEXT_FRAME. */ - if (frame == current) +struct frame_info * +get_prev_frame_info (next_frame) + FRAME next_frame; +{ + FRAME_ADDR address; + struct frame_info *prev; + int fromleaf = 0; + + /* If we are within "start" right now, don't go any higher. */ + /* This truncates stack traces of things at sigtramp() though, + because sigtramp() doesn't have a normal return PC, it has + garbage or a small value (seen: 3) in the return PC slot. + It's VITAL to see where the signal occurred, so punt this. */ +#if 0 + if (next_frame && next_frame->pc < first_object_file_end) + return 0; +#endif + + /* 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) { - val.pc = read_pc (); - val.next_frame = 0; - val.next_next_frame = 0; + if (!current_frame) + error ("No frame is currently selected."); + + return current_frame; } - else + else { - for (frame1 = current, frame2 = 0; - frame1; - frame2 = frame1, frame1 = get_prev_frame (frame1)) + /* If we have the prev one, return it */ + if (next_frame->prev) + return next_frame->prev; + + /* There is a questionable, but probably always correct + assumption being made here. The assumption is that if + functions on a specific machine has a FUNCTION_START_OFFSET, + then this is used by the function call instruction for some + purpose. If the function call instruction has this much hair + in it, it probably also sets up the frame pointer + automatically (ie. we'll never have what I am calling a + "leaf node", one which shares a frame pointer with it's + calling function). This is true on a vax. The only other + way to find this out would be to setup a seperate macro + "FUNCTION_HAS_FRAME_POINTER", which would often be equivalent + to SKIP_PROLOGUE modifying a pc value. */ + +#if FUNCTION_START_OFFSET == 0 + if (!(next_frame->next)) { - QUIT; - if (frame1 == frame) - break; + /* Innermost */ + CORE_ADDR func_start, after_prologue; + + func_start = (get_pc_function_start (next_frame->pc) + + FUNCTION_START_OFFSET); + after_prologue = func_start; + SKIP_PROLOGUE (after_prologue); + if (after_prologue == func_start) + { + fromleaf = 1; + address = next_frame->frame; + } + } +#endif - val.pc = FRAME_SAVED_PC (frame1, frame2); - val.next_frame = frame1; - val.next_next_frame = frame2; + 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. */ + address = FRAME_CHAIN (next_frame); + if (!FRAME_CHAIN_VALID (address, next_frame)) + return 0; + + /* If frame has a caller, combine the chain pointer and + the frame's own address to get the address of the caller. */ + address = FRAME_CHAIN_COMBINE (address, next_frame); } } - return val; -} + prev = (struct frame_info *) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_info)); -/* Return a structure containing various interesting information - about the frame that called FRAME. + 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; - This is much faster than get_frame_info (get_prev_frame (FRAME)) - because it does not need to search the entire stack - to find the frame called by the one being described -- that is FRAME. */ +#ifdef INIT_EXTRA_FRAME_INFO + INIT_EXTRA_FRAME_INFO(prev); +#endif -struct frame_info -get_prev_frame_info (next_frame, next_next_frame) - FRAME next_frame, next_next_frame; -{ - struct frame_info val; - register FRAME frame = get_prev_frame (next_frame); + /* 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 ()); - val.frame = frame; - val.next_frame = next_frame; - val.next_next_frame = next_next_frame; - - if (next_frame == 0) - { - val.pc = read_pc (); - } - else - { - val.pc = FRAME_SAVED_PC (next_frame, next_next_frame); - } - - return val; + return prev; } CORE_ADDR get_frame_pc (frame) FRAME frame; { - struct frame_info fi; + struct frame_info *fi; fi = get_frame_info (frame); - return fi.pc; + return fi->pc; } /* Find the addresses in which registers are saved in FRAME. */ @@ -167,7 +252,102 @@ 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); +#if 1 + FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr); +#else + { + register int regnum; + register int regmask; + register CORE_ADDR next_addr; + register CORE_ADDR pc; + int nextinsn; + bzero (&*saved_regs_addr, sizeof *saved_regs_addr); + if ((frame_info_addr)->pc >= ((frame_info_addr)->frame + - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4) + && (frame_info_addr)->pc <= (frame_info_addr)->frame) + { + next_addr = (frame_info_addr)->frame; + pc = (frame_info_addr)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; + } + else + { + pc = get_pc_function_start ((frame_info_addr)->pc); + /* Verify we have a link a6 instruction next; + if not we lose. If we win, find the address above the saved + regs using the amount of storage from the link instruction. */ + if (044016 == read_memory_integer (pc, 2)) + { + next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 4); + pc += 4; + } + else if (047126 == read_memory_integer (pc, 2)) + { + next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 2); + pc+=2; + } + else goto lose; + + /* If have an addal #-n, sp next, adjust next_addr. */ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) + { + next_addr += read_memory_integer (pc += 2, 4); + pc += 4; + } + } + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ + regmask = read_memory_integer (pc + 2, 2); + + /* But before that can come an fmovem. Check for it. */ + nextinsn = 0xffff & read_memory_integer (pc, 2); + if (0xf227 == nextinsn + && (regmask & 0xff00) == 0xe000) + { + pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ + for (regnum = FP0_REGNUM + 7; + regnum >= FP0_REGNUM; + regnum--, regmask >>= 1) + if (regmask & 1) + (*saved_regs_addr).regs[regnum] = (next_addr -= 12); + regmask = read_memory_integer (pc + 2, 2); + } + if (0044327 == read_memory_integer (pc, 2)) + { + pc += 4; /* Regmask's low bit is for register 0, the first written */ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) + if (regmask & 1) + (*saved_regs_addr).regs[regnum] = (next_addr += 4) - 4; + } + else if (0044347 == read_memory_integer (pc, 2)) + { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) + if (regmask & 1) + (*saved_regs_addr).regs[regnum] = (next_addr -= 4); } + else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) + { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; + (*saved_regs_addr).regs[regnum] = (next_addr -= 4); } + /* fmovemx to index of sp may follow. */ + regmask = read_memory_integer (pc + 2, 2); + nextinsn = 0xffff & read_memory_integer (pc, 2); + if (0xf236 == nextinsn + && (regmask & 0xff00) == 0xf000) + { + pc += 10; /* Regmask's low bit is for register fp0, the first written */ + for (regnum = FP0_REGNUM + 7; + regnum >= FP0_REGNUM; + regnum--, regmask >>= 1) + if (regmask & 1) + (*saved_regs_addr).regs[regnum] = (next_addr += 12) - 12; + regmask = read_memory_integer (pc + 2, 2); + } + /* clrw -(sp); movw ccr,-(sp) may follow. */ + if (0x426742e7 == read_memory_integer (pc, 4)) + (*saved_regs_addr).regs[PS_REGNUM] = (next_addr -= 4); + lose: ; + (*saved_regs_addr).regs[SP_REGNUM] = (frame_info_addr)->frame + 8; + (*saved_regs_addr).regs[FP_REGNUM] = (frame_info_addr)->frame; + (*saved_regs_addr).regs[PC_REGNUM] = (frame_info_addr)->frame + 4; + } +#endif } /* Return the innermost lexical block in execution @@ -177,10 +357,10 @@ struct block * get_frame_block (frame) FRAME frame; { - struct frame_info fi; + struct frame_info *fi; fi = get_frame_info (frame); - return block_for_pc (fi.pc); + return block_for_pc (fi->pc); } struct block * @@ -195,17 +375,16 @@ get_pc_function_start (pc) { register struct block *bl = block_for_pc (pc); register struct symbol *symbol; - if (bl == 0) + 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; } - symbol = block_function (bl); bl = SYMBOL_BLOCK_VALUE (symbol); return BLOCK_START (bl); -} +} /* Return the symbol for the function executing in frame FRAME. */ @@ -222,6 +401,8 @@ get_frame_function (frame) /* 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; @@ -229,6 +410,7 @@ block_for_pc (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 */ @@ -243,6 +425,19 @@ block_for_pc (pc) } if (s == 0) + for (ps = partial_symtab_list; ps; ps = ps->next) + { + if (ps->textlow <= pc + && ps->texthigh > pc) + { + 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. */ @@ -307,7 +502,7 @@ find_pc_misc_function (pc) if (hi < 0) return -1; /* no misc functions recorded */ /* trivial reject range test */ - if (pc < misc_function_vector[0].address || + if (pc < misc_function_vector[0].address || pc > misc_function_vector[hi].address) return -1; @@ -333,7 +528,7 @@ FRAME block_innermost_frame (block) struct block *block; { - struct frame_info fi; + struct frame_info *fi; register FRAME frame; register CORE_ADDR start = BLOCK_START (block); register CORE_ADDR end = BLOCK_END (block); @@ -341,18 +536,17 @@ block_innermost_frame (block) frame = 0; while (1) { - fi = get_prev_frame_info (frame); - frame = fi.frame; + frame = get_prev_frame (frame); if (frame == 0) return 0; - if (fi.pc >= start && fi.pc < end) + fi = get_frame_info (frame); + if (fi->pc >= start && fi->pc < end) return frame; } } -static -initialize () +void +_initialize_blockframe () { + obstack_init (&frame_cache_obstack); } - -END_FILE diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index c5acf96..fd6a0ba 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -19,7 +19,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "frame.h" @@ -32,10 +31,16 @@ static char break_insn[] = BREAKPOINT; /* States of enablement of breakpoint. `temporary' means disable when hit. - `once' means delete 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; @@ -49,6 +54,9 @@ struct breakpoint 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; @@ -62,8 +70,9 @@ struct breakpoint char duplicate; /* Chain of command lines to execute when this breakpoint is hit. */ struct command_line *commands; - /* Stack depth (frame). If nonzero, break only if fp equals this. */ - FRAME frame; + /* 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; }; @@ -95,10 +104,6 @@ int default_breakpoint_line; struct command_line *breakpoint_commands; -START_FILE - -extern char *read_line (); - static void delete_breakpoint (); void clear_momentary_breakpoints (); void breakpoint_auto_delete (); @@ -161,9 +166,6 @@ commands_command (arg) register int bnum; struct command_line *l; - if (arg == 0) - error_no_arg ("breakpoint number"); - /* If we allowed this, we would have problems with when to free the storage, if we change the commands currently being read from. */ @@ -171,15 +173,21 @@ commands_command (arg) if (breakpoint_commands) error ("Can't use the \"commands\" command among a breakpoint's commands."); - 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); + /* 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) @@ -254,7 +262,10 @@ insert_breakpoints () register struct breakpoint *b; int val; -/* printf ("Inserting breakpoints.\n"); */ +#ifdef BREAKPOINT_DEBUG + printf ("Inserting breakpoints.\n"); +#endif /* BREAKPOINT_DEBUG */ + ALL_BREAKPOINTS (b) if (b->enable != disabled && ! b->inserted && ! b->duplicate) { @@ -262,8 +273,10 @@ insert_breakpoints () val = write_memory (b->address, break_insn, sizeof break_insn); if (val) return val; -/* printf ("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", - b->address, b->shadow_contents[0], b->shadow_contents[1]); */ +#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; @@ -275,7 +288,10 @@ remove_breakpoints () register struct breakpoint *b; int val; -/* printf ("Removing breakpoints.\n"); */ +#ifdef BREAKPOINT_DEBUG + printf ("Removing breakpoints.\n"); +#endif /* BREAKPOINT_DEBUG */ + ALL_BREAKPOINTS (b) if (b->inserted) { @@ -283,8 +299,10 @@ remove_breakpoints () if (val) return val; b->inserted = 0; -/* printf ("Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", - b->address, b->shadow_contents[0], b->shadow_contents[1]); */ +#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; @@ -293,7 +311,7 @@ remove_breakpoints () /* Clear the "inserted" flag in all breakpoints. This is done when the inferior is loaded. */ -int +void mark_breakpoints_out () { register struct breakpoint *b; @@ -334,12 +352,13 @@ breakpoint_cond_eval (exp) 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 for a silent breakpoint. */ + with 0x1000000 added (or subtracted, for a negative return value) for + a silent breakpoint. */ int -breakpoint_stop_status (pc, frame) +breakpoint_stop_status (pc, frame_address) CORE_ADDR pc; - FRAME frame; + FRAME_ADDR frame_address; { register struct breakpoint *b; register int cont = 0; @@ -350,7 +369,7 @@ breakpoint_stop_status (pc, frame) ALL_BREAKPOINTS (b) if (b->enable != disabled && b->address == pc) { - if (b->frame && b->frame != frame) + if (b->frame && b->frame != frame_address) cont = -1; else { @@ -376,11 +395,15 @@ breakpoint_stop_status (pc, frame) if (b->enable == temporary) b->enable = disabled; breakpoint_commands = b->commands; - if (breakpoint_commands - && !strcmp ("silent", breakpoint_commands->line)) + if (b->silent + || (breakpoint_commands + && !strcmp ("silent", breakpoint_commands->line))) { - breakpoint_commands = breakpoint_commands->next; - return 0x1000000 + b->number; + if (breakpoint_commands) + breakpoint_commands = breakpoint_commands->next; + return (b->number > 0 ? + 0x1000000 + b->number : + b->number - 0x1000000); } return b->number; } @@ -538,6 +561,7 @@ set_raw_breakpoint (sal) 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 @@ -571,7 +595,7 @@ set_momentary_breakpoint (sal, frame) b = set_raw_breakpoint (sal); b->number = -3; b->enable = delete; - b->frame = frame; + b->frame = (frame ? FRAME_FP (frame) : 0); } void @@ -622,14 +646,12 @@ set_breakpoint (s, line, tempflag) } /* Set a breakpoint according to ARG (function, linenum or *address) - and make it temporary if TEMPFLAG is nonzero. - - LINE_NUM is for C++. */ + and make it temporary if TEMPFLAG is nonzero. */ static void -break_command_1 (arg, tempflag, from_tty, line_num) +break_command_1 (arg, tempflag, from_tty) char *arg; - int tempflag, from_tty, line_num; + int tempflag, from_tty; { struct symtabs_and_lines sals; struct symtab_and_line sal; @@ -637,6 +659,7 @@ break_command_1 (arg, tempflag, from_tty, line_num) register struct breakpoint *b; char *save_arg; int i; + CORE_ADDR pc; sals.sals = NULL; sals.nelts = 0; @@ -644,58 +667,64 @@ break_command_1 (arg, tempflag, from_tty, line_num) sal.line = sal.pc = sal.end = 0; sal.symtab = 0; - if (arg) - { - CORE_ADDR pc; - sals = decode_line_1 (&arg, 1, 0, 0); + /* If no arg given, or if first arg is 'if ', use the default breakpoint. */ - if (! sals.nelts) return; - save_arg = arg; - for (i = 0; i < sals.nelts; i++) + if (!arg || (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t'))) + { + if (default_breakpoint_valid) { - 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) - { - 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; + 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 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 - error ("No default breakpoint address now."); + 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) + return; + save_arg = arg; for (i = 0; i < sals.nelts; i++) { sal = sals.sals[i]; - sal.line += line_num; /** C++ **/ - if (line_num != 0) - { /* get the pc for a particular line */ - sal.pc = find_line_pc (sal.symtab, sal.line); + 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); @@ -711,6 +740,12 @@ break_command_1 (arg, tempflag, from_tty, line_num) 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); } @@ -719,7 +754,7 @@ break_command (arg, from_tty) char *arg; int from_tty; { - break_command_1 (arg, 0, from_tty, 0); + break_command_1 (arg, 0, from_tty); } static void @@ -727,7 +762,62 @@ tbreak_command (arg, from_tty) char *arg; int from_tty; { - break_command_1 (arg, 1, from_tty, 0); + 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 frame = get_current_frame (); + FRAME prev_frame = get_prev_frame (frame); + + /* 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, 0); + + /* 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 @@ -742,7 +832,9 @@ clear_command (arg, from_tty) int i; if (arg) - sals = decode_line_spec (arg, 1); + { + sals = decode_line_spec (arg, 1); + } else { sals.sals = (struct symtab_and_line *) malloc (sizeof (struct symtab_and_line)); @@ -801,7 +893,7 @@ clear_command (arg, from_tty) } 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 @@ -851,7 +943,7 @@ delete_breakpoint (bpt) free (bpt); } -void map_breakpoint_numbers (); +static void map_breakpoint_numbers (); static void delete_command (arg, from_tty) @@ -1048,19 +1140,41 @@ enable_delete_command (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. */ -struct cmd_list_element *enablelist; +extern struct cmd_list_element + *enablelist, *disablelist, + *deletelist, *enablebreaklist; extern struct cmd_list_element *cmdlist; -static -initialize () +void +_initialize_breakpoint () { breakpoint_chain = 0; breakpoint_count = 0; - enablelist = 0; add_com ("ignore", class_breakpoint, ignore_command, "Set ignore-count of breakpoint number N to COUNT."); @@ -1068,6 +1182,7 @@ initialize () 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\ @@ -1085,35 +1200,80 @@ 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. Give breakpoint numbers as arguments.\n\ + "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.", +With a subcommand you can enable temporarily.\n\ +\n\ +The \"display\" subcommand applies to auto-displays instead of breakpoints.", &enablelist, "enable ", 1, &cmdlist); - add_cmd ("delete", 0, enable_delete_command, + 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", 0, enable_once_command, + 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_com ("disable", class_breakpoint, disable_command, - "Disable some breakpoints. Give breakpoint numbers as arguments.\n\ -With no arguments, disable all breakpoints.\n\ -A disabled breakpoint is not forgotten,\n\ -but it has no effect until enabled again."); + 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 ("delete", class_breakpoint, delete_command, - "Delete breakpoints, specifying breakpoint numbers; or all breakpoints.\n\ + 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."); +To delete all breakpoints, give no argument.\n\ +\n\ +The \"display\" subcommand applies to auto-displays instead of breakpoints.", + &deletelist, "delete ", 1, &cmdlist); add_com_alias ("d", "delete", class_breakpoint, 1); + add_com_alias ("unset", "delete", class_breakpoint, 1); + + add_abbrev_cmd ("breakpoints", 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\ +This command may be abbreviated \"delete\".", + &deletelist); add_com ("clear", class_breakpoint, clear_command, "Clear breakpoint at specified line or function.\n\ @@ -1152,4 +1312,3 @@ Convenience variable \"$_\" and default examine address for \"x\"\n\ are set to the address of the last breakpoint listed."); } -END_FILE diff --git a/gdb/c.h b/gdb/c.h deleted file mode 100644 index 1c60a34..0000000 --- a/gdb/c.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "b.h" - -inline c () -{ - Foo x = 1; - { - Foo y = 2; - { - b (); - } - Foo z = 3; - } - Foo w = 4; -} diff --git a/gdb/coffread.c b/gdb/coffread.c index 17b53bd..ae02d6f 100644 --- a/gdb/coffread.c +++ b/gdb/coffread.c @@ -2,7 +2,7 @@ Design and support routines derived from dbxread.c, and UMAX COFF specific routines written 9/1/87 by David D. Johnson, Brown University. Revised 11/27/87 ddj@cs.brown.edu - Copyright (C) 1987, 1988 Free Software Foundation, Inc. + Copyright (C) 1987, 1988, 1989 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 @@ -24,15 +24,22 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include "defs.h" #include "param.h" #ifdef COFF_FORMAT -#include "initialize.h" #include "symtab.h" +#ifdef USG +#include +#include +#endif + #include #include #include #include #include +/* Avoid problems with A/UX predefine */ +#undef aux + static void add_symbol_to_list (); static void read_coff_symtab (); static void patch_opaque_types (); @@ -52,8 +59,8 @@ static int init_lineno (); static void enter_linenos (); extern void free_all_symtabs (); +extern void free_all_psymtabs (); -START_FILE /* Name of source file whose symbol data we are now processing. This comes from a symbol named ".file". */ @@ -184,12 +191,17 @@ coff_lookup_type (index) { if (index >= type_vector_length) { + int old_vector_length = type_vector_length; + type_vector_length *= 2; + if (type_vector_length < index) { + type_vector_length = index * 2; + } type_vector = (struct typevector *) xrealloc (type_vector, sizeof (struct typevector) + type_vector_length * sizeof (struct type *)); - bzero (&type_vector->type[type_vector_length / 2], - type_vector_length * sizeof (struct type *) / 2); + bzero (&type_vector->type[ old_vector_length ], + (type_vector_length - old_vector_length) * sizeof(struct type *)); } return &type_vector->type[index]; } @@ -359,6 +371,7 @@ record_line (line, pc) int line; CORE_ADDR pc; { + struct linetable_entry *e; /* Make sure line vector is big enough. */ if (line_vector_index + 2 >= line_vector_length) @@ -366,21 +379,12 @@ record_line (line, pc) line_vector_length *= 2; line_vector = (struct linetable *) xrealloc (line_vector, sizeof (struct linetable) - + line_vector_length * sizeof (int)); + + (line_vector_length + * sizeof (struct linetable_entry))); } - /* If this line is not continguous with previous one recorded, - all lines between subsequent line and current one are same pc. - Add one item to line vector, and if more than one line skipped, - record a line-number entry for it. */ - if (prev_line_number > 0 && line != prev_line_number + 1) - line_vector->item[line_vector_index++] = pc; - if (prev_line_number < 0 || line > prev_line_number + 2) - line_vector->item[line_vector_index++] = - line; - prev_line_number = line; - - /* Record the core address of the line. */ - line_vector->item[line_vector_index++] = pc; + e = line_vector->item + line_vector_index++; + e->line = line; e->pc = pc; } /* Start a new symtab for a new source file. @@ -402,7 +406,8 @@ start_symtab () line_vector_length = 1000; prev_line_number = -2; /* Force first line number to be explicit */ line_vector = (struct linetable *) - xmalloc (sizeof (struct linetable) + line_vector_length * sizeof (int)); + xmalloc (sizeof (struct linetable) + + line_vector_length * sizeof (struct linetable_entry)); } /* Save the vital information for use when closing off the current file. @@ -438,18 +443,31 @@ end_symtab () if (context_stack) { cstk = context_stack; + context_stack = 0; /* Make a block for the local symbols within. */ finish_block (cstk->name, &local_symbols, cstk->old_blocks, cstk->start_addr, cur_src_end_addr); free (cstk); } + /* Ignore a file that has no functions with real debugging info. */ + if (pending_blocks == 0 && file_symbols == 0 && global_symbols == 0) + { + free (line_vector); + line_vector = 0; + line_vector_length = -1; + last_source_file = 0; + return; + } + + /* Create the two top-level blocks for this file. */ finish_block (0, &file_symbols, 0, cur_src_start_addr, cur_src_end_addr); finish_block (0, &global_symbols, 0, cur_src_start_addr, cur_src_end_addr); - blockvector = make_blockvector (); - /* Now create the symtab object this source file. */ + /* Create the blockvector that points to all the file's blocks. */ + blockvector = make_blockvector (); + /* Now create the symtab object for this source file. */ symtab = (struct symtab *) xmalloc (sizeof (struct symtab)); symtab->free_ptr = 0; @@ -460,7 +478,8 @@ end_symtab () lv = line_vector; lv->nitems = line_vector_index; symtab->linetable = (struct linetable *) - xrealloc (lv, sizeof (struct linetable) + lv->nitems * sizeof (int)); + xrealloc (lv, (sizeof (struct linetable) + + lv->nitems * sizeof (struct linetable_entry))); symtab->nlines = 0; symtab->line_charpos = 0; @@ -468,6 +487,7 @@ end_symtab () symtab->next = symtab_list; symtab_list = symtab; + /* Reinitialize for beginning of new file. */ line_vector = 0; line_vector_length = -1; last_source_file = 0; @@ -525,6 +545,21 @@ record_misc_function (name, address) misc_count++; } +/* if we see a function symbol, we do record_misc_function. + * however, if it turns out the next symbol is '.bf', then + * we call here to undo the misc definition + */ +static void +unrecord_misc_function () +{ + if (misc_bunch_index == 0) + error ("Internal error processing symbol table, at symbol %d.", + symnum); + misc_bunch_index--; + misc_count--; +} + + static int compare_misc_functions (fn1, fn2) struct misc_function *fn1, *fn2; @@ -621,8 +656,9 @@ sort_syms () for (i = 0; i < nbl; i++) { b = BLOCKVECTOR_BLOCK (bv, i); - qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), - sizeof (struct symbol *), compare_symbols); + if (BLOCK_SHOULD_SORT (b)) + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); } } } @@ -648,6 +684,9 @@ symbol_file_command (name) { if (symtab_list && !query ("Discard symbol table? ", 0)) error ("Not confirmed."); + if (symfile) + free (symfile); + symfile = 0; free_all_symtabs (); return; } @@ -689,6 +728,8 @@ symbol_file_command (name) /* Throw away the old symbol table. */ free_all_symtabs (); + free_all_psymtabs (); /* Make sure that partial_symtab_list */ + /* is 0 also. */ num_sections = file_hdr.f_nscns; symtab_offset = file_hdr.f_symptr; @@ -783,23 +824,35 @@ read_coff_symtab (desc, nsyms) int desc; int nsyms; { - FILE *stream = fdopen (desc, "r"); + int newfd; /* Avoid multiple closes on same desc */ + FILE *stream; register struct context_stack *new; struct coff_symbol coff_symbol; register struct coff_symbol *cs = &coff_symbol; static SYMENT main_sym; static AUXENT main_aux; + struct coff_symbol fcn_cs_saved; + static SYMENT fcn_sym_saved; + static AUXENT fcn_aux_saved; int num_object_files = 0; - int next_file_symnum; + int next_file_symnum = -1; char *filestring; int depth; int fcn_first_line; int fcn_last_line; + int fcn_start_addr; long fcn_line_ptr; struct cleanup *old_chain; + int fclose(); + + newfd = dup (desc); + if (newfd == -1) + fatal ("Too many open files"); + stream = fdopen (newfd, "r"); old_chain = make_cleanup (free_all_symtabs, 0); + make_cleanup (fclose, stream); nlist_stream_global = stream; nlist_nsyms_global = nsyms; last_source_file = 0; @@ -835,26 +888,19 @@ read_coff_symtab (desc, nsyms) if (!last_source_file && cs->c_type != T_NULL && cs->c_secnum == N_DEBUG) complete_symtab (filestring, 0, 0); - if (ISFCN (cs->c_type)) + /* Typedefs should not be treated as symbol definitions. */ + if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF) { - /* - * gdb expects all functions to also be in misc_function - * list -- why not... + /* record as misc function. if we get '.bf' next, + * then we undo this step */ record_misc_function (cs->c_name, cs->c_value); fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr; - within_function = 1; - - new = (struct context_stack *) - xmalloc (sizeof (struct context_stack)); - new->depth = depth = 0; - new->next = 0; - context_stack = new; - new->locals = 0; - new->old_blocks = pending_blocks; - new->start_addr = cs->c_value; - new->name = process_coff_symbol (cs, &main_aux); + fcn_start_addr = cs->c_value; + fcn_cs_saved = *cs; + fcn_sym_saved = main_sym; + fcn_aux_saved = main_aux; continue; } @@ -889,79 +935,84 @@ read_coff_symtab (desc, nsyms) num_object_files++; break; - case C_EXT: - if (cs->c_secnum == N_ABS && strcmp (cs->c_name, _ETEXT) == 0) - { - end_of_text_addr = cs->c_value; - } - if (cs->c_type == T_NULL) - { - if (cs->c_secnum <= 1) /* text or abs */ - { - record_misc_function (cs->c_name, cs->c_value); - break; - } - else - cs->c_type = T_INT; - } - (void) process_coff_symbol (cs, &main_aux); - break; - - case C_STAT: - if (cs->c_type == T_NULL && cs->c_secnum > N_UNDEF) - { - if (strcmp (cs->c_name, _TEXT) == 0) - { - if (num_object_files == 1) - { - /* Record end address of first file, crt0.s */ - first_object_file_end = - cs->c_value + main_aux.x_scn.x_scnlen; - } - /* - * Fill in missing information for debugged - * object file only if we have line number info. - */ - if (main_aux.x_scn.x_nlinno > 0) - { - complete_symtab (filestring, cs->c_value, - main_aux.x_scn.x_scnlen); - } + case C_STAT: + if (cs->c_name[0] == '.') { + if (strcmp (cs->c_name, _TEXT) == 0) { + if (num_object_files == 1) { + /* last address of startup file */ + first_object_file_end = cs->c_value + + main_aux.x_scn.x_scnlen; + } + /* for some reason the old code didn't do + * this if this section entry had + * main_aux.x_scn.x_nlinno equal to 0 + */ + complete_symtab (filestring, cs->c_value, + main_aux.x_scn.x_scnlen); + } + /* flush rest of '.' symbols */ break; - } - else if (strcmp (cs->c_name, _DATA) == 0) - break; - else if (strcmp (cs->c_name, _BSS) == 0) - break; - - /* get rid of assembly labels here */ - /* record_misc_function (cs->c_name, cs->c_value); */ - break; - } + } + /* fall in for static symbols that don't start with '.' */ + case C_EXT: + if (cs->c_sclass == C_EXT && + cs->c_secnum == N_ABS && + strcmp (cs->c_name, _ETEXT) == 0) + end_of_text_addr = cs->c_value; + if (cs->c_type == T_NULL) { + if (cs->c_secnum <= 1) { /* text or abs */ + record_misc_function (cs->c_name, cs->c_value); + break; + } else { + cs->c_type = T_INT; + } + } (void) process_coff_symbol (cs, &main_aux); break; case C_FCN: if (strcmp (cs->c_name, ".bf") == 0) { + unrecord_misc_function (); + + within_function = 1; + /* value contains address of first non-init type code */ /* main_aux.x_sym.x_misc.x_lnsz.x_lnno contains line number of '{' } */ fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + + new = (struct context_stack *) + xmalloc (sizeof (struct context_stack)); + new->depth = depth = 0; + new->next = 0; + context_stack = new; + new->locals = 0; + new->old_blocks = pending_blocks; + new->start_addr = fcn_start_addr; + fcn_cs_saved.c_name = getsymname (&fcn_sym_saved); + new->name = process_coff_symbol (&fcn_cs_saved, + &fcn_aux_saved); } else if (strcmp (cs->c_name, ".ef") == 0) { - /* value contains address of exit/return from function */ - /* round it up to next multiple of 16 */ - cs->c_value = (cs->c_value + 15) & -16; + /* the value of .ef is the address of epilogue code; + * not useful for gdb + */ /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno contains number of lines to '}' */ fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line); - new = context_stack; + + if (new == 0) + error ("Invalid symbol data; .bf/.ef/.bb/.eb symbol mismatch, at symbol %d.", + symnum); + finish_block (new->name, &local_symbols, new->old_blocks, - new->start_addr, cs->c_value); + new->start_addr, + fcn_cs_saved.c_value + + fcn_aux_saved.x_sym.x_misc.x_fsize); context_stack = 0; within_function = 0; free (new); @@ -987,7 +1038,8 @@ read_coff_symtab (desc, nsyms) { new = context_stack; if (new == 0 || depth != new->depth) - error ("Invalid symbol data: .bb/.eb symbol mismatch."); + error ("Invalid symbol data: .bb/.eb symbol mismatch at symbol %d.", + symnum); if (local_symbols && context_stack->next) { /* Make a block for the local symbols within. */ @@ -1027,12 +1079,25 @@ read_file_hdr (chan, file_hdr) switch (file_hdr->f_magic) { +#ifdef NS32GMAGIC case NS32GMAGIC: case NS32SMAGIC: +#endif +#ifdef I386MAGIC + case I386MAGIC: +#endif return file_hdr->f_nsyms; + default: +#ifdef BADMAG + if (BADMAG(file_hdr)) + return -1; + else + return file_hdr->f_nsyms; +#else return -1; +#endif } } @@ -1107,15 +1172,22 @@ init_stringtab (chan, offset) long buffer; int val; + if (stringtab) + { + free (stringtab); + stringtab = NULL; + } + if (lseek (chan, offset, 0) < 0) return -1; val = myread (chan, (char *)&buffer, sizeof buffer); - if (val != sizeof buffer) - return -1; - if (stringtab) - free (stringtab); + /* If no string table is needed, then the file may end immediately + after the symbols. Just return with `stringtab' set to null. */ + if (val != sizeof buffer || buffer == 0) + return 0; + stringtab = (char *) xmalloc (buffer); if (stringtab == NULL) return -1; @@ -1166,9 +1238,11 @@ getfilename (aux_entry) char *result; extern char *rindex (); +#ifndef COFF_NO_LONG_FILE_NAMES if (aux_entry->x_file.x_foff != 0) strcpy (buffer, stringtab + aux_entry->x_file.x_foff); else +#endif { strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN); buffer[FILNMLEN] = '\0'; @@ -1365,8 +1439,8 @@ process_coff_symbol (cs, aux) if (ISFCN (cs->c_type)) { - SYMBOL_TYPE (sym) - = lookup_function_type (decode_function_type (cs, cs->c_type, aux)); + SYMBOL_TYPE (sym) = + lookup_function_type (decode_function_type (cs, cs->c_type, aux)); SYMBOL_CLASS (sym) = LOC_BLOCK; if (cs->c_sclass == C_STAT) add_symbol_to_list (sym, &file_symbols); @@ -1571,8 +1645,8 @@ decode_base_type (cs, c_type, aux) switch (c_type) { case T_NULL: - /* shouldn't show up here */ - break; + /* shows up with "void (*foo)();" structure members */ + return builtin_type_void; case T_ARG: /* shouldn't show up here */ @@ -1691,12 +1765,13 @@ read_struct_type (index, length, lastsym) register struct coff_symbol *ms = &member_sym; SYMENT sub_sym; AUXENT sub_aux; + int done = 0; type = coff_alloc_type (index); TYPE_CODE (type) = TYPE_CODE_STRUCT; TYPE_LENGTH (type) = length; - while (symnum < lastsym && symnum < nlist_nsyms_global) + while (!done && symnum < lastsym && symnum < nlist_nsyms_global) { read_one_sym (ms, &sub_sym, &sub_aux); name = ms->c_name; @@ -1736,6 +1811,7 @@ read_struct_type (index, length, lastsym) break; case C_EOS: + done = 1; break; } } @@ -1829,23 +1905,48 @@ read_enum_type (index, length, lastsym) { SYMBOL_TYPE (syms->symbol) = type; TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (syms->symbol); - TYPE_FIELD_VALUE (type, n) = SYMBOL_VALUE (syms->symbol); - TYPE_FIELD_BITPOS (type, n) = 0; + TYPE_FIELD_VALUE (type, n) = 0; + TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (syms->symbol); TYPE_FIELD_BITSIZE (type, n) = 0; } return type; } -static -initialize () +/* This function is really horrible, but to avoid it, there would need + to be more filling in of forward references. THIS SHOULD BE MOVED + OUT OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED. */ +int +fill_in_vptr_fieldno (type) + struct type *type; +{ + if (TYPE_VPTR_FIELDNO (type) < 0) + TYPE_VPTR_FIELDNO (type) = + fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1)); + return TYPE_VPTR_FIELDNO (type); +} + +/* partial symbol tables are not implemented in coff, therefore + block_for_pc() (and others) will never decide to call this. */ + +extern struct symtab * +psymtab_to_symtab () +{ + fatal ("error: Someone called psymtab_to_symtab\n"); +} + +/* These will stay zero all the time */ +struct partial_symbol *global_psymbols, *static_psymbols; + +_initialize_coff () { symfile = 0; + static_psymbols = global_psymbols = (struct partial_symbol *) 0; + add_com ("symbol-file", class_files, symbol_file_command, "Load symbol table (in coff format) from executable file FILE."); } -END_FILE #endif /* COFF_FORMAT */ diff --git a/gdb/command.c b/gdb/command.c index acde0e3..000b273 100644 --- a/gdb/command.c +++ b/gdb/command.c @@ -104,6 +104,7 @@ what you give them. Help stamp out software-hoarding! */ #include "command.h" +#include "defs.h" #include #ifdef sparc @@ -112,8 +113,6 @@ what you give them. Help stamp out software-hoarding! */ extern char *xmalloc (); -static char *savestring (); - /* 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 @@ -149,6 +148,33 @@ add_cmd (name, class, fun, doc, list) 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; @@ -180,7 +206,7 @@ add_alias_cmd (name, oldname, class, abbrev_flag, list) return c; } -/* Like add_prefix_cmd but adds an element for a command prefix: +/* 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. */ @@ -204,6 +230,28 @@ add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, 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 @@ -228,65 +276,86 @@ delete_cmd (name, list) } } -/* Implement a help command on command list LIST. - COMMAND is the argument given (a command from the list to document) - or zero for no arg (describe briefly all the commands in the list). - CMDTYPE is a string to use in the error message if command COMMAND - is not found in the list. */ +void help_cmd (), help_list (), help_cmd_list (); -/* CLASS should be -1 to list all commands in LIST, - or a nonnegative class number value to list just commands in that class, - or -2 to list the classes themselves. */ +/* 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, list, cmdtype, class, stream) +help_cmd (command, stream) char *command; - struct cmd_list_element *list; - char *cmdtype; - int class; FILE *stream; { - register struct cmd_list_element *c; - register char *p; - register int ncmds; - struct cmdvec { struct cmd_list_element *cmd; int class; }; - register struct cmdvec *cmdvec; - char *cmdtype1, *cmdtype2; - int len; + struct cmd_list_element *c; + extern struct cmd_list_element *cmdlist; - if (command) + if (!command) { - c = lookup_cmd (&command, list, cmdtype, 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. */ - - p = c->doc; - fprintf (stream, "%s\n", p); - if (c->function != 0 && c->prefixlist == 0) - return; - fputc ('\n', stream); - if (c->prefixlist) - { - list = *c->prefixlist; - class = 0; - cmdtype = c->prefixname; - } - else - class = c->class; + help_list (cmdlist, "", -2, stream); + return; } + c = lookup_cmd (&command, cmdlist, "", 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. */ + + fprintf (stream, "%s\n", c->doc); + if (c->prefixlist == 0 && c->function != 0) + return; + fputc ('\n', stream); + + /* 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); @@ -307,21 +376,7 @@ help_cmd (command, list, cmdtype, class, stream) else fprintf (stream, "List of %scommands:\n\n", cmdtype2); - for (c = list; c; c = c->next) - { - if (c->abbrev_flag == 0 - && (class == -1 /* Listing all */ - || (c->class == class && c->function != 0) /* Listing one class */ - || (class == -2 && c->function == 0))) /* Listing the classes */ - { - fprintf (stream, "%s -- ", c->name); - /* Print just first line of documentation. */ - p = c->doc; - while (*p && *p != '\n') p++; - fwrite (c->doc, 1, p - c->doc, stream); - fputc ('\n', stream); - } - } + help_cmd_list (list, class, cmdtype, (class >= 0), stream); if (class == -2) fprintf (stream, "\n\ @@ -333,6 +388,55 @@ 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; + + 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 (stream, "%s%s -- ", prefix, c->name); + /* Print just the first line */ + p = c->doc; + while (*p && *p != '\n') p++; + fwrite (c->doc, 1, p - c->doc, stream); + fputc('\n', stream); + } + if (recurse + && c->prefixlist != 0 + && c->abbrev_flag == 0) + help_cmd_list (*c->prefixlist, class, c->prefixname, 1, stream); + } +} /* Look up the contents of *LINE as a command in the command list LIST. LIST is a chain of struct cmd_list_element's. @@ -355,6 +459,8 @@ lookup_cmd (line, list, cmdtype, allow_unknown) register struct cmd_list_element *c, *found; int nfound; char ambbuf[100]; + char *processed_cmd; + int i, cmd_len; /* Skip leading whitespace. */ @@ -371,29 +477,53 @@ lookup_cmd (line, list, cmdtype, allow_unknown) /* Find end of command name. */ p = *line; - while (*p == '-' - || (*p >= 'a' && *p <= 'z') - || (*p >= 'A' && *p <= 'Z') - || (*p >= '0' && *p <= '9')) - { - if (*p >= 'A' && *p <= 'Z') - *p += 'a' - 'A'; - p++; - } + if (*p == '!') + p++; + else 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. */ + 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 (*line, c->name, p - *line)) + if (!strncmp (processed_cmd, c->name, cmd_len)) { found = c; nfound++; - if (c->name[p - *line] == 0) + if (c->name[cmd_len] == 0) { nfound = 1; break; @@ -407,10 +537,9 @@ lookup_cmd (line, list, cmdtype, allow_unknown) { if (nfound > 1 && allow_unknown >= 0) { - *p = 0; ambbuf[0] = 0; for (c = list; c; c = c->next) - if (!strncmp (*line, c->name, p - *line)) + if (!strncmp (processed_cmd, c->name, cmd_len)) { if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf) { @@ -424,13 +553,11 @@ lookup_cmd (line, list, cmdtype, allow_unknown) break; } } - error ("Ambiguous %scommand \"%s\": %s.", cmdtype, *line, ambbuf); + error ("Ambiguous %scommand \"%s\": %s.", cmdtype, + processed_cmd, ambbuf); } else if (!allow_unknown) - { - *p = 0; - error ("Undefined %scommand: \"%s\".", cmdtype, *line); - } + error ("Undefined %scommand: \"%s\".", cmdtype, processed_cmd); return 0; } @@ -450,17 +577,48 @@ lookup_cmd (line, list, cmdtype, allow_unknown) return found; } -/* 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. */ +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); -static char * -savestring (ptr, size) - char *ptr; - int size; + 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 () { - register char *p = (char *) xmalloc (size + 1); - bcopy (ptr, p, size); - p[size] = 0; - return p; + 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."); + + add_com_alias ("!", "shell", class_support, 1); } diff --git a/gdb/config.gdb b/gdb/config.gdb index 62848f8..2578462 100755 --- a/gdb/config.gdb +++ b/gdb/config.gdb @@ -4,7 +4,7 @@ # Shell script to create proper links to machine-dependent files in # preparation for compiling gdb. # -# Usage: config.gdb machine +# Usage: config.gdb machine [operating-system] # # If config.gdb succeeds, it leaves its status in config.status. # If config.gdb fails after disturbing the status quo, @@ -13,79 +13,159 @@ progname=$0 -case $# in +case $# in 1) machine=$1 - paramfile=m-${machine}.h - initfile=m-${machine}init.h - pinsnfile=${machine}-pinsn.c - opcodefile=${machine}-opcode.h + os="none" + ;; +2) + machine=$1 + os=$2 + ;; +*) + echo "Usage: $progname machine [operating-system]" + echo "Available machine types:" + echo m-*.h | sed 's/m-//g' | sed 's/\.h//g' + if [ -r config.status ] + then + cat config.status + fi + exit 1 + ;; +esac - case $machine in - hp9k320) - initfile=m-sun3init.h - pinsnfile=m68k-pinsn.c - opcodefile=m68k-opcode.h - ;; - hp9k320bsd) - initfile=m-sun3init.h - pinsnfile=m68k-pinsn.c - opcodefile=m68k-opcode.h - ;; - isi) - # some version of m68k-pinsn.c should work here - pinsnfile=m68k-pinsn.c - opcodefile=m68k-opcode.h - ;; - merlin) - # m-umaxinit.h? - initfile=unknown-or-unavailable - pinsnfile=ns32k-pinsn.c - opcodefile=ns32k-opcode.h - ;; - news) - pinsnfile=m68k-pinsn.c - opcodefile=m68k-opcode.h - ;; - npl) - pinsnfile=gld-pinsn.c - ;; - pn) - pinsnfile=gld-pinsn.c - ;; - sun2) - pinsnfile=m68k-pinsn.c - opcodefile=m68k-opcode.h - ;; - sun3) - pinsnfile=m68k-pinsn.c - opcodefile=m68k-opcode.h - ;; - sun4) - pinsnfile=sparc-pinsn.c - opcodefile=sparc-opcode.h - ;; - umax) - pinsnfile=ns32k-pinsn.c - opcodefile=ns32k-opcode.h - ;; - test) - paramfile=one - initfile=two - pinsnfile=three - opcodefile=four +paramfile=m-${machine}.h +pinsnfile=${machine}-pinsn.c +opcodefile=${machine}-opcode.h +if [ -r ${machine}-dep.c ] +then + depfile=${machine}-dep.c +else + depfile=default-dep.c +fi + +# +# Special cases. +# If a file is not needed, set the filename to 'skip' and it will be +# ignored. +# +case $machine in +aux) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +vax) + pinsnfile=vax-pinsn.c + opcodefile=vax-opcode.h + ;; +hp9k320) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +isi) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +i386) + echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile" + opcodefile=skip + ;; +i386gas) + echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile" + echo "Use of the coff encapsulation features also requires the GNU binutils utilities" + echo "to be ahead of their System V counterparts in your path." + pinsnfile=i386-pinsn.c + depfile=i386-dep.c + opcodefile=skip + ;; +merlin) + pinsnfile=ns32k-pinsn.c + opcodefile=ns32k-opcode.h + ;; +news) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +npl) + pinsnfile=gld-pinsn.c + ;; +pn) + pinsnfile=gld-pinsn.c + ;; +sun2) + case $os in + os4|sunos4) + paramfile=m-sun2os4.h ;; + os2|sunos2) + paramfile=m-sun2os2.h esac + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +sun2os2) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +sun2os4) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +sun3) + case $os in + os4|sunos4) + paramfile=m-sun3os4.h + esac + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + ;; +sun3os4) + pinsnfile=m68k-pinsn.c + opcodefile=m68k-opcode.h + depfile=sun3-dep.c + ;; +sun4os4) + pinsnfile=sparc-pinsn.c + opcodefile=sparc-opcode.h + depfile=sparc-dep.c + ;; +umax) + pinsnfile=ns32k-pinsn.c + opcodefile=ns32k-opcode.h + ;; +sparc|sun4) + case $os in + os4|sunos4) + paramfile=m-sun4os4.h + esac + pinsnfile=sparc-pinsn.c + opcodefile=sparc-opcode.h + depfile=sparc-dep.c + paramfile=m-sparc.h + ;; +test) + paramfile=one + pinsnfile=three + opcodefile=four + ;; +*) + echo "Unknown machine type: \`$machine'" + echo "Available types:" + echo m-*.h | sed 's/m-//g' | sed 's/\.h//g' + exit 1 +esac - files="$paramfile $initfile $pinsnfile $opcodefile" - links="param.h m-init.h pinsn.c opcode.h" +files="$paramfile $pinsnfile $opcodefile $depfile" +links="param.h pinsn.c opcode.h dep.c" - while [ -n "$files" ] - do - # set file to car of files, files to cdr of files - set $files; file=$1; shift; files=$* - set $links; link=$1; shift; links=$* +while [ -n "$files" ] +do + # set file to car of files, files to cdr of files + set $files; file=$1; shift; files=$* + set $links; link=$1; shift; links=$* + if [ "$file" != skip ] + then if [ ! -r $file ] then echo "$progname: cannot create a link \`$link'," @@ -103,21 +183,10 @@ case $# in exit 1 fi echo "Linked \`$link' to \`$file'." - done - - echo "Links are now set up for use with a $machine." \ - | tee config.status - exit 0 - ;; -*) - echo "Usage: $progname machine" - echo -n "Where \`machine' is something like " - echo "\`vax', \`sun3', \`umax', etc." - if [ -r config.status ] - then - cat config.status fi - exit 1 - ;; -esac +done + +echo "Links are now set up for use with a $machine." \ + | tee config.status +exit 0 diff --git a/gdb/convex-dep.c b/gdb/convex-dep.c new file mode 100644 index 0000000..509012b --- /dev/null +++ b/gdb/convex-dep.c @@ -0,0 +1,524 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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; + /* Convex ptrace needs an extra 0 arg */ + ptrace (8, inferior_pid, 0, 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 + { + extern char registers[]; + + /* Blam the trace bits in the stack's saved psws to match the + desired step mode. This is required so that single-stepping a + return doesn't restore a psw with a clear trace bit and fly away, + and conversely, proceeding through a return in a routine that was + stepped into doesn't cause a phantom break by restoring a psw + with the trace bit set. */ + scan_stack (PSW_T_BIT, step); + + /* Write the registers back now */ + ptrace (11, inferior_pid, 0, registers, REGISTER_BYTES); + if (errno != 0) perror_with_name ("writing registers"); + + errno = 0; + ptrace (step ? 9 : 7, inferior_pid, 1, &signal, sizeof signal); + if (errno) + perror_with_name ("ptrace"); + } +} + +void +fetch_inferior_registers () +{ + extern char registers[]; + ptrace (10, inferior_pid, 0, registers, REGISTER_BYTES); +} + +/* 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; +{ + /* do this only once, right before resuming inferior. */ + return; +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes 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; +{ + errno = 0; + ptrace (1, inferior_pid, memaddr, myaddr, len); + if (errno) + bzero (myaddr, len); + return errno; +} + +/* Copy LEN bytes of data from debugger memnory at MYADDR + to inferior's memory at MEMADDR. + Returns errno on failure (cannot write the inferior) */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + errno = 0; + ptrace (4, inferior_pid, memaddr, myaddr, len); + return errno; +} + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +/* Required by convex's SOFF format + It may be desirable to remove the conditionals for SOFF_FORMAT, if + Convex is the only machine which will ever make use of them. */ +#ifdef SOFF_FORMAT +#include +#include +#include +#include +#endif /* SOFF_FORMAT */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#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; + +#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) + { + 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 SOFF_FORMAT + { + extern char *sys_errlist[], *sys_siglist[]; + extern int sys_nerr; + int stop_signal; + struct core_hdr corehdr; + struct user u; + + if (myread (corechan, &corehdr, sizeof corehdr) < 0) + perror_with_name (filename); + if (corehdr.c_magic != CH_MAGIC) + error ("%s: not a core file.", filename); + + lseek (corechan, corehdr.c_user, 0); + if (myread (corechan, &u, sizeof u) < 0) + perror_with_name (filename); + + lseek (corechan, corehdr.c_syscall_context, 0); + if (myread (corechan, registers, REGISTER_BYTES) < 0) + perror_with_name (filename); + + if (corehdr.c_vecst) + { + lseek (corechan, corehdr.c_vecst, 0); + if (myread (corechan, vecst, sizeof vecst) < 0) + perror_with_name (filename); + } + + data_offset = corehdr.c_data; + data_start = exec_data_start; + data_end = data_start + ctob (u.u_dsize); + + stack_offset = corehdr.c_stack; + stack_start = stack_end - ctob (u.u_ssize); + + printf ("Program %s", u.u_comm ); + if (u.u_error >= sys_nerr) + printf (", last error: %d (undocumented),\n", u.u_error); + else if (u.u_error != 0) + printf (", last error: %s,", sys_errlist[u.u_error]); + + stop_signal = u.u_arg[0]; + printf (" received signal %d, %s\n", stop_signal, + stop_signal < NSIG ? sys_siglist[stop_signal] : "(undocumented)"); + + core_aouthdr.a_magic = 0; + } +#ifdef SOFF_FORMAT + + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + /* Convex-specific code: remove the frame stored by a + user-mode trap, if present */ + + if (read_register (PC_REGNUM) > STACK_END_ADDR) + { + POP_FRAME; + } + + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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; + + val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); + + if (val < 0) + perror_with_name (filename); + + /* Convex-specific SOFF-FORMAT */ +#ifdef SOFF_FORMAT + if (IS_SOFF_MAGIC (exec_aouthdr.a_magic)) + { + FILEHDR filhdr; + OPTHDR opthdr; + SCNHDR scnhdr; + int n, gotem; + + lseek (execchan, 0L, 0); + if (myread (execchan, &filhdr, sizeof filhdr) < 0) + perror_with_name (filename); + if (myread (execchan, &opthdr, filhdr.h_opthdr) <= 0) + perror_with_name (filename); + + lseek (execchan, (long) filhdr.h_scnptr, 0); + n = -1; + gotem = 0; + while (++n < filhdr.h_nscns && gotem < 2) + { + if (myread (execchan, &scnhdr, SCNHSZ) < 0) + perror_with_name (filename); + if ((scnhdr.s_flags & S_TYPMASK) == S_TEXT) + { + text_start = scnhdr.s_vaddr; + text_end = text_start + scnhdr.s_size; + text_offset = scnhdr.s_scnptr; + ++gotem; + } + else if ((scnhdr.s_flags & S_TYPMASK) == S_DATA) + { + exec_data_start = scnhdr.s_vaddr; + exec_data_end = exec_data_start + scnhdr.s_size; + exec_data_offset = scnhdr.s_scnptr; + data_start = exec_data_start; + data_end += exec_data_start; + ++gotem; + } + } + } + else +#endif SOFF_FORMAT + { + text_start = N_TXTADDR (exec_aouthdr); + text_end = text_start + exec_aouthdr.a_text; + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_start = N_DATADDR (exec_aouthdr); + exec_data_end = exec_data_start + exec_aouthdr.a_data; + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + 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); +} + diff --git a/gdb/core.c b/gdb/core.c index 85a8d24..03f4a68 100644 --- a/gdb/core.c +++ b/gdb/core.c @@ -1,5 +1,5 @@ /* Work with core dump and executable files, for GDB. - Copyright (C) 1986, 1987 Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1989 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 @@ -18,11 +18,29 @@ 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! */ -#include "initialize.h" #include "defs.h" #include "param.h" +#include "gdbcore.h" +#ifdef USG +#include +#include +#endif + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else #include +#endif + +#ifndef N_MAGIC +#ifdef COFF_FORMAT +#define N_MAGIC(exec) ((exec).magic) +#else +#define N_MAGIC(exec) ((exec).a_magic) +#endif +#endif + #include #include #include @@ -30,28 +48,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include #include -/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ -#ifdef AOUTHDR -#define COFF_FORMAT +#ifdef UNISOFT_ASSHOLES +#define PMMU +#define NEW_PMMU +#include /* Required for user.ps */ +#include /* '' */ +#include /* '' */ +#include +#define mc68881 /* Required to get float in user.ps */ #endif -#ifdef NEW_SUN_CORE -#include -#else /* not NEW_SUN_CORE */ #ifdef UMAX_CORE #include -#else /* not UMAX_CORE */ +#else #include -#ifdef HP9K320 -#include -#include -#ifdef HPUX_VERSION_5 -#define e_PS e_regs[PS] -#define e_PC e_regs[PC] -#endif /* HPUX_VERSION_5 */ -#endif /* HP9K320 */ -#endif /* not UMAX_CORE */ -#endif /* not NEW_SUN_CORE */ +#endif #ifndef N_TXTADDR #define N_TXTADDR(hdr) 0 @@ -61,20 +72,13 @@ anyone else from sharing it farther. Help stamp out software hoarding! #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 -#define AOUTHDR struct exec +#define AOUTHDR struct exec #endif extern char *sys_siglist[]; -START_FILE +extern core_file_command (), exec_file_command (); /* Hook for `exec_file_command' command to call. */ @@ -82,15 +86,15 @@ void (*exec_file_display_hook) (); /* File names of core file and executable file. */ -static char *corefile; -static char *execfile; +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. */ -static int corechan; -static int execchan; +int corechan; +int execchan; /* Last modification time of executable file. Also used in source.c to compare against mtime of a source file. */ @@ -99,10 +103,10 @@ int exec_mtime; /* Virtual addresses of bounds of the two areas of memory in the core file. */ -static CORE_ADDR data_start; -static CORE_ADDR data_end; -static CORE_ADDR stack_start; -static CORE_ADDR stack_end; +CORE_ADDR data_start; +CORE_ADDR data_end; +CORE_ADDR stack_start; +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. */ @@ -110,361 +114,49 @@ static CORE_ADDR stack_end; CORE_ADDR text_start; CORE_ADDR text_end; -static CORE_ADDR exec_data_start; -static CORE_ADDR exec_data_end; +CORE_ADDR exec_data_start; +CORE_ADDR exec_data_end; /* Address in executable file of start of text area data. */ -static int text_offset; +int text_offset; /* Address in executable file of start of data area data. */ -static int exec_data_offset; +int exec_data_offset; /* Address in core file of start of data area data. */ -static int data_offset; +int data_offset; /* Address in core file of start of stack area data. */ -static int stack_offset; +int stack_offset; #ifdef COFF_FORMAT /* various coff data structures */ -static FILHDR file_hdr; -static SCNHDR text_hdr; -static SCNHDR data_hdr; +FILHDR file_hdr; +SCNHDR text_hdr; +SCNHDR data_hdr; #endif /* not COFF_FORMAT */ /* a.out header saved in core file. */ -static AOUTHDR core_aouthdr; +AOUTHDR core_aouthdr; /* a.out header of exec file. */ -static AOUTHDR exec_aouthdr; +AOUTHDR exec_aouthdr; -static void validate_files (); +void validate_files (); unsigned int register_addr (); -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) - { - 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 NEW_SUN_CORE - { - struct core corestr; - - val = myread (corechan, &corestr, sizeof corestr); - if (val < 0) - perror_with_name (filename); - if (corestr.c_magic != CORE_MAGIC) - error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", - filename, corestr.c_magic, (int) CORE_MAGIC); - else if (sizeof (struct core) != corestr.c_len) - error ("\"%s\" has an invalid struct core length (%d, expected %d)", - filename, corestr.c_len, (int) sizeof (struct core)); - - data_start = exec_data_start; - data_end = data_start + corestr.c_dsize; - stack_start = stack_end - corestr.c_ssize; - data_offset = sizeof corestr; - stack_offset = sizeof corestr + corestr.c_dsize; - -#if defined(sun2) || defined(sun3) - bcopy (&corestr.c_regs, registers, 16 * 4); - *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; - *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; - bcopy (corestr.c_fpstatus.fps_regs, - ®isters[REGISTER_BYTE (FP0_REGNUM)], - sizeof corestr.c_fpstatus.fps_regs); - bcopy (&corestr.c_fpstatus.fps_control, - ®isters[REGISTER_BYTE (FPC_REGNUM)], - sizeof corestr.c_fpstatus - sizeof corestr.c_fpstatus.fps_regs); -#endif -#if defined(sun4) - /* G0 *always* holds 0. */ - *(int *)®isters[REGISTER_BYTE (0)] = 0; - /* The globals and output registers. I don't know where - to get the locals and input registers from the core file. */ - bcopy (&corestr.c_regs.r_g1, registers, 15 * 4); - *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; - *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; - *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = corestr.c_regs.r_npc; - *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = corestr.c_regs.r_y; - bcopy (corestr.c_fpu.fpu_regs, - ®isters[REGISTER_BYTE (FP0_REGNUM)], - sizeof corestr.c_fpu.fpu_regs); -#ifdef FPU - bcopy (&corestr.c_fpu.fpu_fsr, - ®isters[REGISTER_BYTE (FPS_REGNUM)], - sizeof (FPU_FSR_TYPE)); -#endif -#endif - - bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); - - printf ("Core file is from \"%s\".\n", corestr.c_cmdname); - if (corestr.c_signo > 0) - printf ("Program terminated with signal %d, %s.\n", - corestr.c_signo, - corestr.c_signo < NSIG - ? sys_siglist[corestr.c_signo] - : "(undocumented)"); - } -#else /* not NEW_SUN_CORE */ - /* 4.2-style (and perhaps also sysV-style) core dump file. */ - { -#ifdef UMAX_CORE - struct ptrace_user u; -#else - struct user u; -#endif - int reg_offset; - - val = myread (corechan, &u, sizeof u); - if (val < 0) - perror_with_name (filename); - data_start = exec_data_start; - -#ifdef UMAX_CORE - data_end = data_start + u.pt_dsize; - stack_start = stack_end - u.pt_ssize; - data_offset = sizeof u; - stack_offset = data_offset + u.pt_dsize; - reg_offset = 0; - - bcopy (&u.pt_aouthdr, &core_aouthdr, sizeof (AOUTHDR)); - printf ("Core file is from \"%s\".\n", u.pt_comm); - if (u.pt_signal > 0) - printf ("Program terminated with signal %d, %s.\n", - u.pt_signal, - u.pt_signal < NSIG - ? sys_siglist[u.pt_signal] - : "(undocumented)"); -#else /* not UMAX_CORE */ - 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. */ - core_aouthdr.a_magic = 0; -#endif /* not UMAX_CORE */ - - /* Read the register values out of the core file and store - them where `read_register' will find them. */ - -#ifdef HP9K320 - { - register int regno; - struct exception_stack es; - int val; - - val = lseek (corechan, (REGISTER_ADDR (reg_offset, 0)), 0); - if (val < 0) - perror_with_name (filename); - val = myread (corechan, es, - ((char *) &es.e_regs[R0] - (char *) &es.e_offset)); - if (val < 0) - perror_with_name (filename); - for (regno = 0; (regno < PS_REGNUM); regno++) - supply_register (regno, &es.e_regs[regno + R0]); - val = es.e_PS; - supply_register (regno++, &val); - supply_register (regno++, &es.e_PC); - for (; (regno < NUM_REGS); regno++) - { - char buf[MAX_REGISTER_RAW_SIZE]; - - val = lseek (corechan, (FP_REGISTER_ADDR (u, regno)), 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); - } - } -#else /* not HP9K320 */ - { - 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); - } - } -#endif /* not HP9K320 */ - } -#endif /* not NEW_SUN_CORE */ - if (filename[0] == '/') - corefile = savestring (filename, strlen (filename)); - else - { - corefile = concat (current_directory, "/", filename); - } - - set_current_frame (read_register (FP_REGNUM)); - 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) - { - 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) < 0) - error ("\"%s\": can't read text section header", execfile); - - if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) - error ("\"%s\": can't read data section header", execfile); - - text_start = exec_aouthdr.text_start; - text_end = text_start + exec_aouthdr.tsize; - text_offset = 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 gould - FILHDR exec_coffhdr; - - val = myread (execchan, &exec_coffhdr, sizeof exec_coffhdr); - if (val < 0) - perror_with_name (filename); -#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); -#ifdef gould - text_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr); - exec_data_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr) - + exec_aouthdr.a_text; -#else - text_offset = N_TXTOFF (exec_aouthdr); - exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; -#endif - 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); -} - /* 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) (); { @@ -475,6 +167,7 @@ specify_exec_file_hook (hook) If it is needed again after the inferior dies, it must be reopened. */ +void close_exec_file () { if (execchan >= 0) @@ -482,6 +175,7 @@ close_exec_file () execchan = -1; } +void reopen_exec_file () { if (execchan < 0 && execfile != 0) @@ -497,7 +191,7 @@ reopen_exec_file () This should really check that the core file came from that exec file, but I don't know how to do it. */ -static void +void validate_files () { if (execfile != 0 && corefile != 0) @@ -506,7 +200,7 @@ validate_files () fstat (corechan, &st_core); - if (core_aouthdr.a_magic != 0 + 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) @@ -544,49 +238,54 @@ files_info () printf ("Executable file \"%s\".\n", execfile); else printf ("No executable file\n"); - if (corefile == 0) - printf ("No core dump file\n"); + + if (corefile) + printf ("Core dump file \"%s\".\n", corefile); else - printf ("Core dump file \"%s\".\n", corefile); + printf ("No core dump file\n"); 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 loaded from \"%s\".\n", symfile); + printf ("Symbols from \"%s\".\n", symfile); if (! have_inferior_p ()) { if (execfile) { - printf ("Text segment from 0x%x to 0x%x.\n", + 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 from 0x%x to 0x%x.\nStack segment from 0x%x to 0x%x.\n", - data_start, data_end, stack_start, stack_end); - } - else - { - printf ("Data segment in executable from 0x%x to 0x%x.\n", - exec_data_start, exec_data_end); + 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 */ +/* 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 (have_inferior_p ()) - read_inferior_memory (memaddr, myaddr, len); + return read_inferior_memory (memaddr, myaddr, len); else - xfer_core_file (memaddr, myaddr, len, 0); + return xfer_core_file (memaddr, myaddr, len); } /* Write LEN bytes of data starting at address MYADDR @@ -605,6 +304,15 @@ write_memory (memaddr, myaddr, len) error ("Can write memory only when program being debugged is running."); } +/* 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; @@ -615,6 +323,7 @@ xfer_core_file (memaddr, myaddr, len) int xferchan; char **xferfile; int fileptr; + int returnval = 0; while (len > 0) { @@ -625,30 +334,17 @@ xfer_core_file (memaddr, myaddr, len) 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. */ + along with the next address. + + We put the most likely tests first for efficiency. */ - if (memaddr < text_start) - { - i = min (len, text_start - memaddr); - } - else if (memaddr >= text_end && memaddr < data_start) - { - i = min (len, data_start - memaddr); - } - else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end) - && memaddr < stack_start) - { - i = min (len, stack_start - memaddr); - } - else if (memaddr >= stack_end && stack_end != 0) - { - i = min (len, - memaddr); - } /* Note that if there is no core file data_start and data_end are equal. */ - else if (memaddr >= data_start && memaddr < data_end) + if (memaddr >= data_start && memaddr < data_end) { i = min (len, data_end - memaddr); fileptr = memaddr - data_start + data_offset; @@ -679,6 +375,31 @@ xfer_core_file (memaddr, myaddr, len) 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 (memaddr >= (corechan >= 0 ? data_end : exec_data_end) + && memaddr < stack_start) + { + i = min (len, stack_start - memaddr); + } + else if (memaddr >= stack_end && stack_end != 0) + { + i = min (len, - memaddr); + } + else + { + /* Address did not classify into one of the known ranges. + This could be because data_start != exec_data_start + or data_end similarly. */ + abort(); + } /* Now we know which file to use. Set up its pointer and transfer the data. */ @@ -697,19 +418,25 @@ xfer_core_file (memaddr, myaddr, len) perror_with_name (*xferfile); } /* If this address is for nonexistent memory, - read zeros if reading, or do nothing if writing. */ + read zeros if reading, or do nothing if writing. + (FIXME we never write.) */ else - bzero (myaddr, i); + { + bzero (myaddr, i); + returnval = 1; + } memaddr += i; myaddr += i; len -= i; } + return returnval; } /* 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; @@ -753,8 +480,8 @@ register_addr (regno, blockend) #endif /* REGISTER_U_ADDR */ -static -initialize () +void +_initialize_core() { corechan = -1; execchan = -1; @@ -782,4 +509,3 @@ No arg means have no executable file."); add_info ("files", files_info, "Names of files being debugged."); } -END_FILE diff --git a/gdb/createtags b/gdb/createtags new file mode 100755 index 0000000..491694c --- /dev/null +++ b/gdb/createtags @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Here we check to see if we are compiling in a directory that contains +# symlinks to the source files instead of the actual files. If this is so, +# we setup the TAGS entries to point to the actual source directory. +# +filelist="" +if test -h main.c ; then + prefix=`ls -l main.c | awk '{print $11}' | sed 's;main.c$;;'` + echo path 1 +else + prefix="" +fi +for i in $@ ; do + filelist="$prefix$i $filelist" +done +# +# Here we simply make sure that the actual machine dependent files being used +# (if any) are ahead of all of the other machine dependent files in the list. +# This means that M-. will (almost) always give you exactly the routine +# you want. +# +if test -f param.h ; then + if `grep '^#define[ ]*COFF_FORMAT' param.h > /dev/null 2>&1`; then + frmatfile=${prefix}coffread.c + else + frmatfile=${prefix}dbxread.c + fi + hfile=$prefix`ls -l param.h | awk '{print $11}'` + dfile=$prefix`ls -l dep.c | awk '{print $11}'` + ofile=$prefix`ls -l opcode.h | awk '{print $11}'` + pfile=$prefix`ls -l pinsn.c | awk '{print $11}'` + etags $hfile $dfile $ofile $pfile $frmatfile $filelist +else + etags $filelist +fi diff --git a/gdb/dbxread.c b/gdb/dbxread.c index 27ffcc1..9908aa1 100644 --- a/gdb/dbxread.c +++ b/gdb/dbxread.c @@ -1,6 +1,5 @@ /* Read dbx symbol tables and convert to internal format, for GDB. - Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc. - Hacked by Michael Tiemann (tiemann@mcc.com) + Copyright (C) 1986, 1987, 1988, 1989 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 @@ -23,24 +22,113 @@ anyone else from sharing it farther. Help stamp out software hoarding! #ifdef READ_DBX_FORMAT +#ifdef USG +#include +#include +#define L_SET 0 +#define L_INCR 1 +#endif + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#include "stab.gnu.h" +#else #include #include +#endif + +/* + * 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__ */ + #include #include #include #include #include #include "defs.h" -#include "initialize.h" #include "symtab.h" +#ifndef COFF_FORMAT +#define AOUTHDR struct exec +#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 (); @@ -51,15 +139,37 @@ static void hash_symsegs (); 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 (); +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 @@ -80,21 +190,38 @@ static struct type **read_args (); /* Macro to declare variables to hold the file's header data. */ #ifndef DECLARE_FILE_HEADERS -#define DECLARE_FILE_HEADERS struct exec hdr +#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 - -START_FILE +#endif +/* Macro for size of text segment */ +#ifndef SIZE_OF_TEXT_SEGMENT +#define SIZE_OF_TEXT_SEGMENT hdr.a_text +#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 + /* 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 @@ -247,6 +374,26 @@ extern CORE_ADDR first_object_file_end; /* From blockframe.c */ 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; + +/* Partial symbol list for all of the global and static symbols found + in a file */ + +struct partial_symbol *global_psymbols, *static_psymbols; +int global_psymbols_allocated, static_psymbols_allocated; + +/* Position for next psymbol to be added */ + +struct partial_symbol *next_ps_global, *next_ps_static; + +/* Global variable which, when set, indicates that we are processing a + .o file compiled with gcc */ + +static unsigned char processing_gcc_compilation; + static int xxmalloc (n) { @@ -331,6 +478,23 @@ 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 @@ -375,8 +539,9 @@ free_header_files () register int i; for (i = 0; i < n_header_files; i++) free (header_files[i].name); - free (header_files); - free (this_object_header_files); + 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. @@ -476,14 +641,16 @@ add_new_header_file (name, instance) 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)); + 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 = name; + header_files[i].name = savestring (name, strlen(name)); header_files[i].instance = instance; header_files[i].length = 10; header_files[i].vector @@ -518,7 +685,9 @@ dbx_lookup_type (typenums) { type_vector_length *= 2; type_vector = (struct typevector *) - xrealloc (type_vector, sizeof (struct typevector) + type_vector_length * sizeof (struct type *)); + 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); } @@ -566,7 +735,6 @@ dbx_alloc_type (typenums) sizeof (struct type)); bzero (type, sizeof (struct type)); TYPE_VPTR_FIELDNO (type) = -1; - TYPE_MAIN_VARIANT (type) = type; *type_addr = type; } return type; @@ -677,7 +845,9 @@ finish_block (symbol, listhead, old_blocks, start, end) 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 *)); + (sizeof (struct block) + + ((i - 1) + * sizeof (struct symbol *)))); /* Copy the symbols into the block. */ @@ -692,6 +862,7 @@ finish_block (symbol, listhead, old_blocks, start, end) 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. */ @@ -731,8 +902,9 @@ finish_block (symbol, listhead, old_blocks, start, end) /* 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 = (struct pending_block *) + obstack_alloc (symbol_obstack, + sizeof (struct pending_block)); pblock->block = block; if (opblock) { @@ -757,7 +929,10 @@ make_blockvector () 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 *)); + 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 @@ -785,11 +960,12 @@ make_blockvector () /* Manage the vector of line numbers. */ -static +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) @@ -802,18 +978,13 @@ record_line (line, pc) line_vector_length *= 2; line_vector = (struct linetable *) xrealloc (line_vector, - sizeof (struct linetable) + line_vector_length * sizeof (int)); + (sizeof (struct linetable) + + line_vector_length * sizeof (struct linetable_entry))); current_subfile->line_vector = line_vector; } - /* If this line is not continguous with previous one recorded, - record a line-number entry for it. */ - if (line != prev_line_number + 1) - line_vector->item[line_vector_index++] = - line; - prev_line_number = line; - - /* Record the core address of the line. */ - line_vector->item[line_vector_index++] = pc; + e = line_vector->item + line_vector_index++; + e->line = line; e->pc = pc; } /* Start a new symtab for a new source file. @@ -849,7 +1020,9 @@ start_symtab (name, start_addr) return; type_vector_length = 160; - type_vector = (struct typevector *) xxmalloc (sizeof (struct typevector) + type_vector_length * sizeof (struct type *)); + 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 @@ -858,6 +1031,11 @@ start_symtab (name, start_addr) subfiles = 0; current_subfile = 0; start_subfile (name); + + /* Set default for compiler to pcc; assume that we aren't processing + a gcc compiled file until proved otherwise. */ + + processing_gcc_compilation = 0; } /* Handle an N_SOL symbol, which indicates the start of @@ -901,7 +1079,8 @@ start_subfile (name) 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 (int)); + 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. */ @@ -978,7 +1157,8 @@ end_symtab (end_addr) lv = subfile->line_vector; lv->nitems = subfile->line_vector_index; symtab->linetable = (struct linetable *) - xrealloc (lv, sizeof (struct linetable) + lv->nitems * sizeof (int)); + xrealloc (lv, (sizeof (struct linetable) + + lv->nitems * sizeof (struct linetable_entry))); symtab->nlines = 0; symtab->line_charpos = 0; @@ -1123,8 +1303,12 @@ discard_misc_bunches () } } +/* 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 () +condense_misc_bunches (inclink) + int inclink; { register int i, j; register struct misc_bunch *bunch; @@ -1134,11 +1318,22 @@ condense_misc_bunches () int offset = 0; #endif - misc_function_vector - = (struct misc_function *) - xxmalloc (misc_count * sizeof (struct misc_function)); - - j = 0; + 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) { @@ -1155,11 +1350,15 @@ condense_misc_bunches () misc_bunch_index = MISC_BUNCH_SIZE; } - misc_function_count = j; + if (inclink) + misc_function_count += misc_count; + else + misc_function_count = j; /* Sort the misc functions by address. */ - qsort (misc_function_vector, j, sizeof (struct misc_function), + qsort (misc_function_vector, misc_function_count, + sizeof (struct misc_function), compare_misc_functions); } @@ -1185,42 +1384,51 @@ compare_symbols (s1, s2) - (SYMBOL_CLASS (*s1) == LOC_REGISTER)); } +static void sort_symtab_syms (); + static void sort_syms () { register struct symtab *s; - int i, nbl; - register struct blockvector *bv; - register struct block *b; 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++) { - bv = BLOCKVECTOR (s); - nbl = BLOCKVECTOR_NBLOCKS (bv); - for (i = 0; i < nbl; i++) - { - b = BLOCKVECTOR_BLOCK (bv, i); - if (BLOCK_SHOULD_SORT (b)) - qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), - sizeof (struct symbol *), compare_symbols); -#if 0 - else - { - int lastindex = BLOCK_NSYMS (b) - 1; - register int j; - for (j = (lastindex - 1) / 2; j >= 0; j--) - { - register struct symbol *sym; - sym = BLOCK_SYM (b, j); - BLOCK_SYM (b, j) = BLOCK_SYM (b, lastindex - j); - BLOCK_SYM (b, lastindex - j) = sym; - } - } -#endif - } + 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 (); + /* This is the symbol-file command. Read the file, analyze its symbols, and add a struct symtab to symtab_list. */ @@ -1243,13 +1451,19 @@ symbol_file_command (name) if (name == 0) { - if (symtab_list && !query ("Discard symbol table? ", 0)) + if ((symtab_list || partial_symtab_list) + && !query ("Discard symbol table? ", 0)) error ("Not confirmed."); + if (symfile) + free (symfile); + symfile = 0; free_all_symtabs (); + free_all_psymtabs (); return; } - if (symtab_list && !query ("Load new symbol table from \"%s\"? ", name)) + if ((symtab_list || partial_symtab_list) + && !query ("Load new symbol table from \"%s\"? ", name)) error ("Not confirmed."); { @@ -1272,8 +1486,10 @@ symbol_file_command (name) 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; } @@ -1304,6 +1520,7 @@ symbol_file_command (name) 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); @@ -1349,10 +1566,15 @@ symbol_file_command (name) 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); - init_header_files (); - make_cleanup (free_header_files, 0); + free_pendings = 0; pending_blocks = 0; file_symbols = 0; @@ -1362,16 +1584,11 @@ symbol_file_command (name) /* 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, NUMBER_OF_SYMBOLS); - close (desc); - - /* Sort symbols alphabetically within each block. */ - - sort_syms (); + read_dbx_symtab (desc, stringtab, NUMBER_OF_SYMBOLS, 0, 0, 0); /* Go over the misc functions and install them in vector. */ - condense_misc_bunches (); + condense_misc_bunches (0); /* Don't allow char * to have a typename (else would get caddr_t.) */ @@ -1379,11 +1596,13 @@ symbol_file_command (name) /* Make a default for file to list. */ - select_source_symtab (symtab_list); - symfile = savestring (name, strlen (name)); - do_cleanups (old_chain); + /* 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. */ @@ -1394,6 +1613,9 @@ symbol_file_command (name) symseg_chain = s; } + if (!partial_symtab_list) + printf ("\n(no debugging symbols found)..."); + printf ("done.\n"); fflush (stdout); } @@ -1407,7 +1629,7 @@ get_sym_file () } /* Buffer for reading the symbol table entries. */ -static struct nlist symbuf[2048]; +static struct nlist symbuf[4096]; static int symbuf_idx; static int symbuf_end; @@ -1449,152 +1671,1038 @@ next_symbol_text () return symbuf[symbuf_idx++].n_un.n_strx + stringtab_global; } -/* Given pointers to a a.out symbol table in core containing dbx style data, - analyze them and create struct symtab's describing the symbols. - NLISTLEN is the number of symbols in the symbol table. - We read them one at a time using stdio. - All symbol names are given as offsets relative to STRINGTAB. */ +/* + * 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_allocated = total_symbols / 10; + static_psymbols_allocated = total_symbols / 10; + next_ps_global = global_psymbols = (struct partial_symbol *) + xmalloc (global_psymbols_allocated * sizeof (struct partial_symbol)); + next_ps_static = static_psymbols = (struct partial_symbol *) + xmalloc (static_psymbols_allocated * 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(); + +/* 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. + + 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 process_symbol_for_psymtab (); static void -read_dbx_symtab (desc, stringtab, nlistlen) +read_dbx_symtab (desc, stringtab, nlistlen, inclink, text_addr, text_size) int desc; register char *stringtab; register int nlistlen; + int inclink; + unsigned text_addr; + int text_size; { register char *namestring; register struct symbol *sym, *prev; int hash; int num_object_files = 0; + int past_first_source_file = 0; struct cleanup *old_chain; + int current_text_start, current_file_symbol_start; + struct pending *global_symbols, *static_symbols; + int nsl; /* Length of namestring, when needed */ -#ifdef N_BINCL - subfile_stack = 0; + /* 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; + + /* Setup a define to deal cleanly with the underscore problem */ + +#ifdef NAMES_HAVE_UNDERSCORE +#define HASH_OFFSET 1 +#else +#define HASH_OFFSET 0 #endif - old_chain = make_cleanup (free_all_symtabs, 0); - stringtab_global = stringtab; - last_source_file = 0; + global_symbols = static_symbols = + (struct pending *) 0; + 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; #endif - - symtab_input_desc = desc; + + symtab_input_desc = desc; /* This is needed for fill_symbuf below */ symbuf_end = symbuf_idx = 0; - + for (symnum = 0; symnum < nlistlen; symnum++) { struct nlist *bufp; - int type; - + unsigned char type; + + /* 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++]; type = bufp->n_type; + + /* + * Special cases to speed up readin. + */ + if (type == N_SLINE) continue; + namestring = bufp->n_un.n_strx ? bufp->n_un.n_strx + stringtab : ""; - if (type & N_STAB) - process_one_symbol (type, bufp->n_desc, - bufp->n_value, namestring); - /* A static text symbol whose name ends in ".o" - or begins with "-l" means 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 ( -#ifdef N_NBTEXT - (type == N_NBTEXT) -#else - (type == N_TEXT) -#endif - && (!strcmp (namestring + strlen (namestring) - 2, ".o") - || !strncmp (namestring, "-l", 2))) + switch (type) { - if (num_object_files++ == 1) - first_object_file_end = bufp->n_value; - if (last_source_file) - end_symtab (bufp->n_value); - } - else if (type & N_EXT || type == N_TEXT + /* + * Standard, non-debugger, symbols + */ + + case N_TEXT | N_EXT: + /* Catch etext */ + + if (!strcmp (namestring, "_etext")) + end_of_text_addr = bufp->n_value; + /* Fall through */ + #ifdef N_NBTEXT - || type == N_NBTEXT + case N_NBTEXT | N_EXT: #endif - ) - { - int used_up = 0; +#ifdef N_NBDATA + case N_NBDATA | N_EXT: +#endif +#ifdef N_NBBSS + case N_NBBSS | 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 */ + + last_global_sym = symnum; + if (!first_global_sym) first_global_sym = symnum; + + record_misc_function (namestring, bufp->n_value); /* Always */ - /* Record the location of _etext. */ - if (type == (N_TEXT | N_EXT) - && !strcmp (namestring, "_etext")) - end_of_text_addr = bufp->n_value; + continue; - /* 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) +#ifdef N_NBTEXT + case N_NBTEXT: +#endif + case N_TEXT: + if (!strcmp (namestring + strlen (namestring) - 2, ".o") + || !strncmp (namestring, "-l", 2)) { - 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 (num_object_files++ == 1) + first_object_file_end = bufp->n_value; + if (past_first_source_file && pst) { - 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); - 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); - } + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * sizeof (struct nlist), bufp->n_value, + dependency_list, dependencies_used, + next_ps_global, next_ps_static); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; } + else + past_first_source_file = 1; } + continue; + + case N_UNDF: + case N_UNDF | N_EXT: + case N_ABS: + case N_DATA: + case N_BSS: +#ifdef N_NBDATA + case N_NBDATA: +#endif +#ifdef N_NBBSS + case N_NBBSS: +#endif + case N_FN: + /* 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: + case N_SETV | N_EXT: +#endif + continue; + + /* + * Debugger symbols + */ - /* 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); + case N_SO: + /* End the current partial symtab and start a new one */ + + 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, + next_ps_global, next_ps_static); + 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), + next_ps_global, next_ps_static); + + 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 */ + add_bincl_to_list (pst, namestring, bufp->n_value); + + /* Fall through */ +#endif + + case N_SOL: + /* 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 *)); +#ifdef DEBUG_INFO + fprintf (stderr, "Had to realloc includes. New size: %d\n", + includes_allocated); +#endif + } + continue; + + case N_FUN: + case N_SSYM: + case N_GSYM: + case N_LSYM: + case N_STSYM: + case N_LCSYM: + case N_ENTRY: +#ifdef N_MAIN + case N_MAIN: +#endif +#ifdef N_BSLINE + case N_BSLINE: +#endif + case N_PC: +#ifdef N_M2C + case N_M2C: + case N_SCOPE: +#endif + /* Process a symbol as appropriate for the type (this + information is contained in the name of the symbol) */ + + if (namestring[0] != '\0') +#if 1 + process_symbol_for_psymtab (namestring); +#else + process_symbol_for_psymtab (namestring, tmp_symchain); +#endif + continue; + +#ifdef N_BINCL + case N_EXCL: + /* 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 + 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 (type)) + continue; + + fatal ("Bad symbol type 0x%x encountered in gdb scan", type); } } - + if (last_source_file) - end_symtab (end_of_text_addr); - + { + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * sizeof (struct nlist), end_of_text_addr, + dependency_list, dependencies_used, + next_ps_global, next_ps_static); + includes_used = 0; + dependencies_used = 0; + pst = (struct partial_symtab *) 0; + } + + free_bincl_list (); discard_cleanups (old_chain); } +/* + * Take a single symbol (name: NAME) and process it (add it to the + * app psymbol list or not). + */ +static void +process_symbol_for_psymtab (name) + char *name; +{ + char *p = (char *) index(name, ':') + 1; + int deftype; + struct partial_symbol *sym; + enum { T_IGNORE, T_STATIC, T_GLOBAL } symbol_type; + enum namespace ns = UNDEF_NAMESPACE; + enum address_class class; + int hash; + + if (p == (char *) 0x1) + /* No ":" ; I guess it's not a debuggging symbol */ + return; + + if ((*p >= '0' && *p <= '9') || *p == '(') + deftype = 'l'; + else + deftype = *p; + + /* Figure out how to handle this symbol */ + switch (deftype) + { + /* T is a struct/union/enum, t is a typedef */ + case 'T': + symbol_type = T_STATIC; + ns = STRUCT_NAMESPACE; + class = LOC_TYPEDEF; + break; + case 't': + symbol_type = T_STATIC; + ns = VAR_NAMESPACE; + class = LOC_TYPEDEF; + break; + case 'c': + symbol_type = T_STATIC; + ns = VAR_NAMESPACE; + class = LOC_CONST; + break; + case 'S': + symbol_type = T_STATIC; + ns = VAR_NAMESPACE; + class = LOC_STATIC; + break; + case 'f': + symbol_type = T_STATIC; + ns = VAR_NAMESPACE; + class = LOC_BLOCK; + break; + case 'F': + symbol_type = T_GLOBAL; + ns = VAR_NAMESPACE; + class = LOC_BLOCK; + break; + case 'G': + symbol_type = T_GLOBAL; + ns = VAR_NAMESPACE; + class = LOC_STATIC; + break; + default: + return; + } + + /* Create the symbol and store it on the list */ + /* There's a better algorithm possible for the allocation; figure + out how far through the symbol table we are and do a reestimate */ + if (symbol_type == T_STATIC) + { + if (next_ps_static >= static_psymbols + static_psymbols_allocated) + { + static_psymbols = (struct partial_symbol *) + xrealloc (static_psymbols, + (static_psymbols_allocated * 2 + * sizeof (struct partial_symbol))); + /* Next assumes we only went one over. Should be good if + program works correctly */ + next_ps_static = static_psymbols + static_psymbols_allocated; + static_psymbols_allocated *= 2; +#ifdef DEBUGINFO + fprintf(stderr, "debuginfo: Had to realloc statics\n"); +#endif + } + sym = next_ps_static++; + } + else + { + if (next_ps_global >= global_psymbols + global_psymbols_allocated) + { + global_psymbols = (struct partial_symbol *) + xrealloc (global_psymbols, + (global_psymbols_allocated * 2 + * sizeof (struct partial_symbol))); + next_ps_global = global_psymbols + global_psymbols_allocated; + global_psymbols_allocated *= 2; +#ifdef DEBUGINFO + fprintf(stderr, "debuginfo: Had to realloc globals\n"); +#endif + } + sym = next_ps_global++; + } + + SYMBOL_NAME(sym) = (char *) obstack_alloc (psymbol_obstack, + p - name); + strncpy(SYMBOL_NAME(sym), name, p - name - 1); + SYMBOL_NAME(sym)[p - name - 1] = '\0'; + SYMBOL_NAMESPACE(sym) = ns; + SYMBOL_CLASS(sym) = class; +} +#undef HASH_OFFSET + +/* + * 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; + result->statics_offset = static_syms - static_psymbols; + + result->n_global_syms = 0; + result->n_static_syms = 0; + + return result; +} + +static int +compare_psymbols (s1, s2) + register struct partial_symbol *s1, *s2; +{ + register char + *st1 = SYMBOL_NAME (s1), + *st2 = SYMBOL_NAME (s2); + + return (st1[0] - st2[0] ? st1[0] - st2[0] : + strcmp (st1 + 1, st2 + 1)); +} + + +/* Close off the current usage of a partial_symbol table entry. This + involves setting the correct number of includes (with a realloc), + setting the high text mark, setting the symbol length in the + executable, and setting the length of the global and static lists + of psymbols. + + The global symbols and static symbols are then seperately sorted. + + Then the partial symtab is put on the global list. + *** List variables and peculiarities of same. *** + */ +static void +end_psymtab (pst, include_list, num_includes, capping_symbol_offset, + capping_text, dependency_list, number_dependencies, + capping_global, capping_static) + struct partial_symtab *pst; + char **include_list; + int num_includes; + int capping_symbol_offset; + int capping_text; + struct partial_symtab **dependency_list; + int number_dependencies; + struct partial_symbol *capping_global, *capping_static; +{ + int i; + + pst->ldsymlen = capping_symbol_offset - pst->ldsymoff; + pst->texthigh = capping_text; + + pst->n_global_syms = + capping_global - (global_psymbols + pst->globals_offset); + pst->n_static_syms = + capping_static - (static_psymbols + 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; + } + + /* Sort the global list; don't sort the static list */ + qsort (global_psymbols + pst->globals_offset, pst->n_global_syms, + sizeof (struct partial_symbol), compare_psymbols); + + /* Put the psymtab on the psymtab list */ + pst->next = partial_symtab_list; + partial_symtab_list = pst; +} + +/* + * 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. + */ +static void scan_file_globals (); +static void read_ofile_symtab (); + +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"); + + /* 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) + psymtab_to_symtab (pst->dependencies[i]); + + if (pst->ldsymlen) /* Otherwise it's a dummy */ + { + /* Open symbol file and read in string table */ + stat (name, &statbuf); + 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); + + /* Read in the string table */ + lseek (desc, STRING_TABLE_OFFSET, L_SET); + READ_STRING_TABLE_SIZE (stsize); + if (stsize >= 0 && stsize < statbuf.st_size) + stringtab = (char *) alloca (stsize); + else + stringtab = NULL; + if (stringtab == NULL) + error ("ridiculous string table size: %d bytes", name, stsize); + + bcopy (&stsize, stringtab, sizeof stsize); + val = myread (desc, stringtab + sizeof stsize, stsize - sizeof stsize); + if (val < 0) + perror_with_name (name); + + /* Init stuff necessary for reading in symbols */ + free_pendings = 0; + pending_blocks = 0; + file_symbols = 0; + global_symbols = 0; + make_cleanup (really_free_pendings, 0); + + /* Read in this files symbols */ + lseek (desc, SYMBOL_TABLE_OFFSET, L_SET); + read_ofile_symtab (desc, stringtab, pst->ldsymoff, + pst->ldsymlen, pst->textlow, + pst->texthigh - pst->textlow, 0); + sort_symtab_syms (symtab_list); /* At beginning since just added */ + + /* Match with global symbols */ + lseek (desc, SYMBOL_TABLE_OFFSET, L_SET); + scan_file_globals (desc, stringtab, + first_global_sym * sizeof(struct nlist), + last_global_sym - first_global_sym + 1); + + do_cleanups (old_chain); + } + + /* Find pst in list, prune it, and free it's storage */ + for (list_patch = &partial_symtab_list; + *list_patch && *list_patch != pst; + list_patch = &((*list_patch)->next)) + ; + + if (!(*list_patch)) /* pst not in list. Don't worry about it? */ + fatal ("internal: psymtab_to_symtab called with non-listed pst"); + + *list_patch = (*list_patch)->next; /* Prune */ + + pst->readin = 1; /* Mark as read in */ + + /* It's the last one if we actually read something in */ + if (pst->ldsymlen) + return symtab_list; + else + /* 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. + * + * DESC is the file descriptor of the symbol file, with the seek + * pointer pointing at the beginning of the symbol table. + * STRINGTAB is the file's string table, already read in. + * OFFSET is the offset (in bytes) of the beginning of the global + * symbols from the beginning of the symbol table. + * NUMSYMS is the number of symbols that have to be checked. + */ +static void +scan_file_globals (desc, stringtab, offset, numsyms) + int desc; + char *stringtab; + int offset; + int numsyms; +{ + int hash; + + lseek(desc, offset, L_INCR); + symtab_input_desc = desc; + symbuf_end = symbuf_idx = 0; + + for (symnum = 0; symnum < numsyms; symnum++) + { + struct nlist *bufp; + unsigned char type; + char *namestring; + + QUIT; + if (symbuf_idx == symbuf_end) + fill_symbuf (); + + bufp = &symbuf[symbuf_idx++]; + type = bufp->n_type; + + if (type & N_EXT && type != N_EXT) + { + struct symbol *sym, *prev; + + namestring = bufp->n_un.n_strx ? + bufp->n_un.n_strx + stringtab : ""; + prev = (struct symbol *) 0; + + /* Get the hash index and check all the symbols + under that hash index. */ + +#ifdef NAMES_HAVE_UNDERSCORE + hash = hashname (namestring + 1); +#else /* ! NAMES_HAVE_UNDERSCORE */ + hash = hashname (namestring); +#endif /* ! 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 */ + ) + { + /* 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); + SYMBOL_VALUE (sym) = bufp->n_value; + if (prev) + sym = (struct symbol *) SYMBOL_VALUE (prev); + else + sym = global_sym_chain[hash]; + break; /* Only one reference per file */ + } + else + { + prev = sym; + sym = (struct symbol *) SYMBOL_VALUE (sym); + } + } + } + } + /* There shouldn't be anything left on the hash list at this point. + If there is, we have done something wrong. For right now it's + worth checking, until I get the bugs out. */ + /* Sigh. Unfortunately, the above is not true. If an extern + variable is mentioned in an include file (or a program) and the + variable is never either referenced or defined, there will be a + debugger symbol with no "real" symbol. Oh well. */ +} + +/* + * 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, 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; + lseek(desc, sym_offset, L_INCR); + + 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; + + namestring = bufp->n_un.n_strx ? 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)) + 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; @@ -1666,23 +2774,12 @@ process_one_symbol (type, desc, value, name) if (last_source_file == 0 && type != N_SO) { -#ifdef N_NSYMS - /* This code is used on Ultrix; ignore this sym. */ - if (type == N_NSYMS) - return; -#endif - - if (type == N_ENTRY) - /* This code appears in libraries on Gould machines. */ + /* Currently this ignores N_ENTRY on Gould machines, N_NSYM on machines + where that code is defined, and all symbols on the Convex. */ + if (IGNORE_SYMBOL (type)) return; - if (type == N_SLINE && desc == -1) - /* This code is used by the Sun4 coimpiler; ignore it. */ - return; - - /* This should give an aborting error. */ - printf ("Invalid symbol data: does not start by identifying a source file.\ntype == %d\n\n", type); - return; + error ("Invalid symbol data: does not start by identifying a source file."); } switch (type) @@ -1693,7 +2790,7 @@ process_one_symbol (type, desc, value, name) 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. */ - + within_function = 1; if (context_stack_depth > 0) { @@ -1721,10 +2818,10 @@ process_one_symbol (type, desc, value, name) 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)); + context_stack = (struct context_stack *) + xrealloc (context_stack, + (context_stack_size + * sizeof (struct context_stack))); } new = &context_stack[context_stack_depth++]; @@ -1821,9 +2918,54 @@ process_one_symbol (type, desc, value, name) } } -/************************ READ_ADDL_SYM() ***********************************/ +/* 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; @@ -1850,7 +2992,7 @@ read_addl_syms (desc, stringtab, nlistlen, text_addr, text_size) for (symnum = 0; symnum < nlistlen; symnum++) { struct nlist *bufp; - int type; + unsigned char type; QUIT; /* allow this to be interruptable */ if (symbuf_idx == symbuf_end) @@ -1943,91 +3085,54 @@ read_addl_syms (desc, stringtab, nlistlen, text_addr, text_size) 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); - } - } - - if (last_source_file) - end_symtab (text_addr + text_size); - - fclose (stream); -} - -/***************************** CONDENSE_ADDL_MISC_BUNCHES *******************/ - -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++; + 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); } - bunch = bunch->next; - misc_bunch_index = MISC_BUNCH_SIZE; } - misc_function_count += misc_count; - - /* Sort the misc functions by address. */ + if (last_source_file) + end_symtab (text_addr + text_size); - qsort (misc_function_vector, misc_function_count, - sizeof (struct misc_function), compare_misc_functions); + fclose (stream); } - -/**************************** ADD_FILE_COMMAND() ****************************/ -/* This function allows the addition of incrementally linked object files. */ + +/* 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; - struct exec hdr; + DECLARE_FILE_HEADERS; struct nlist *nlist; char *stringtab; long buffer; register int val; extern void close (); struct cleanup *old_chain; - char* name; + 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"); @@ -2043,92 +3148,132 @@ add_file_command (arg_string) dont_repeat (); - if (query ("add symbol table from filename \"%s\" at text_addr = 0x%x\n", name, text_addr)) - { - desc = open (name, O_RDONLY); - if (desc < 0) - perror_with_name (name); - - old_chain = make_cleanup (close, desc); - make_cleanup (free_current_contents, &name); - - val = myread (desc, &hdr, sizeof hdr); - if (val < 0) - perror_with_name (name); - - if (N_BADMAG (hdr)) - error ("File \"%s\" has a bad header.", name); - - if (hdr.a_syms == 0) - { - printf ("%s does not have a symbol-table.\n", name); - fflush (stdout); - return; - } - - /* Now read the string table, all at once. */ - val = lseek (desc, N_SYMOFF (hdr) + hdr.a_syms, 0); - if (val < 0) - perror_with_name (name); - val = myread (desc, &buffer, sizeof buffer); - if (val < 0) - perror_with_name (name); - stringtab = (char *) alloca (buffer); - bcopy (&buffer, stringtab, sizeof buffer); - val = myread (desc, stringtab + sizeof buffer, buffer - sizeof buffer); - if (val < 0) - perror_with_name (name); - - /* That puts us at the symsegs. Read them. ########## Also need other - changes if they exist. */ - - /* Position to read the symbol table. Do not read it all at once. */ - val = lseek (desc, N_SYMOFF (hdr), 0); - if (val < 0) - perror_with_name (name); + if (!query ("add symbol table from filename \"%s\" at text_addr = 0x%x\n", + name, text_addr)) + error ("Not confirmed."); - printf ("Reading symbol data from %s...", name); + desc = open (name, O_RDONLY); + if (desc < 0) + perror_with_name (name); + + old_chain = make_cleanup (close, desc); + make_cleanup (free_current_contents, &name); + + 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); + stat (name, &statbuf); + READ_STRING_TABLE_SIZE (buffer); + if (buffer >= 0 && buffer < statbuf.st_size) + stringtab = (char *) alloca (buffer); + else + stringtab = NULL; + if (stringtab == NULL) + error ("ridiculous string table size: %d bytes", name, buffer); + + bcopy (&buffer, stringtab, sizeof buffer); + val = myread (desc, stringtab + sizeof buffer, buffer - sizeof buffer); + if (val < 0) + perror_with_name (name); + +#ifdef READ_GDB_SYMSEGS + /* That puts us at the symsegs. Read them. */ + symseg_chain = read_symsegs (desc, name); + hash_symsegs (); - init_misc_functions (); - make_cleanup (discard_misc_bunches, 0); - init_header_files (); - make_cleanup (free_header_files, 0); - - read_addl_syms (desc, stringtab, hdr.a_syms / sizeof(struct nlist), - text_addr, hdr.a_text) ; - - /* Sort symbols alphabetically within each block. */ - - sort_syms (); - - /* Go over the all misc functions and install them in vector. */ - - condense_addl_misc_bunches (); - - /* 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. */ + /* Free the symtabs made by read_symsegs, but not their contents, + which have been copied into symtabs on symtab_list. */ + for (symseg = symseg_chain; symseg; symseg = symseg->next) + { + int i; + struct sourcevector *sv = (struct sourcevector *) symseg->linetable; - select_source_symtab (symtab_list); + for (i = 0; i < sv->length; i++) + { + int j; + struct source *source = sv->source[i]; + struct symtab *sp1 + = (struct symtab *) xxmalloc (sizeof (struct symtab)); - do_cleanups (old_chain); + bcopy (symseg, sp1, sizeof (struct symtab)); + sp1->filename = savestring (source->name, strlen (source->name)); + sp1->linetable = &source->contents; + sp1->free_code = free_nothing; + sp1->free_ptr = (i == 0) ? (char *) symseg : 0; - /* 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; + sp1->next = symtab_list; + symtab_list = sp1; } + } +#else + /* Where people are using the 4.2 ld program, must not check for + symsegs, because that ld puts randonm garbage at the end of + the output file and that would trigger an error message. */ + symseg_chain = 0; +#endif + + /* 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); - printf ("done.\n"); - fflush (stdout); + 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; + + /* Make a default for file to list. */ + /* Hmmm. I'd say we don't want this in add_file_command, but . . . */ + + select_source_symtab (symtab_list); + + 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; } - else error ("Not confirmed."); + + printf ("done.\n"); + fflush (stdout); } static struct symbol * @@ -2213,11 +3358,11 @@ define_symbol (value, string, desc) SYMBOL_TYPE (sym) = lookup_pointer_type (lookup_function_type (read_type (&p))); } - else + else { struct type *type = read_type (&p); - - if ((deftype == 'F' || deftype == 'f') + + if ((deftype == 'F' || deftype == 'f') && TYPE_CODE (type) != TYPE_CODE_FUNC) SYMBOL_TYPE (sym) = lookup_function_type (type); else @@ -2311,20 +3456,21 @@ define_symbol (value, string, desc) 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)); - } - + /* 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; @@ -2432,7 +3578,7 @@ read_type (pp) 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.) */ - *pp = (char *) index (*pp, ':') + 1; + *pp = (char *) index (*pp, ','); /* Just allocate the type and leave it zero if nothing known */ return dbx_alloc_type (typenums); @@ -2456,8 +3602,17 @@ read_type (pp) break; case '*': - type = dbx_alloc_type (typenums); - smash_to_pointer_type (type, read_type (pp)); + type1 = read_type (pp); + if (TYPE_POINTER_TYPE (type1)) + { + type = TYPE_POINTER_TYPE (type1); + *dbx_lookup_type (typenums) = type; + } + else + { + type = dbx_alloc_type (typenums); + smash_to_pointer_type (type, type1); + } break; case '@': @@ -2477,13 +3632,31 @@ read_type (pp) break; case '&': - type = dbx_alloc_type (typenums); - smash_to_reference_type (type, read_type (pp)); + type1 = read_type (pp); + if (TYPE_REFERENCE_TYPE (type1)) + { + type = TYPE_REFERENCE_TYPE (type1); + *dbx_lookup_type (typenums) = type; + } + else + { + type = dbx_alloc_type (typenums); + smash_to_reference_type (type, type1); + } break; case 'f': - type = dbx_alloc_type (typenums); - smash_to_function_type (type, read_type (pp)); + type1 = read_type (pp); + if (TYPE_FUNCTION_TYPE (type1)) + { + type = TYPE_FUNCTION_TYPE (type1); + *dbx_lookup_type (typenums) = type; + } + else + { + type = dbx_alloc_type (typenums); + smash_to_function_type (type, type1); + } break; case 'r': @@ -2509,8 +3682,18 @@ read_type (pp) break; case 'a': - /* Define an array type. */ + 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; + +#if 0 + /* Format of an array type: + "ar;lower;upper;". Put code + in to handle this. */ /* dbx expresses array types in terms of a range type for the index, and that range type is specified right inside the array type spec @@ -2537,6 +3720,7 @@ read_type (pp) TYPE_TARGET_TYPE (type) = read_type (pp); TYPE_LENGTH (type) = TYPE_LENGTH (TYPE_TARGET_TYPE (type)) * n; break; +#endif default: error ("Invalid symbol data: unrecognized type-code `%c' at symtab pos %d.", @@ -2614,22 +3798,26 @@ read_struct_type (pp, type) 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. */ + and then the base type. */ if (**pp == '!') { int i, n_baseclasses, offset; struct type **baseclass_vec; struct type *baseclass; int via_public, 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 (); + if (**pp == '\\') + *pp = next_symbol_text (); + switch (*(*pp)++) { case '0': @@ -2639,9 +3827,10 @@ read_struct_type (pp, type) via_virtual = 1; break; default: - error ("Invalid symbol data: bad visibility format at symtab pos %d.", + error ("Invalid symbol data: bad visibility format at symtab pos %d", symnum); } + switch (*(*pp)++) { case '0': @@ -2699,13 +3888,13 @@ read_struct_type (pp, type) while (*p != ':') p++; list->field.name = obsavestring (*pp, p - *pp); - /* C++: Check to see if we have hit the methods yet. */ + /* 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. */ + /* This means we have a visibility for a field coming. */ if (**pp == '/') { switch (*++*pp) @@ -2715,33 +3904,32 @@ read_struct_type (pp, type) *pp += 1; break; - case '1': - visibility = 1; - *pp += 1; - break; - - case '2': - visibility = 2; - *pp += 1; - break; - } - } - /* else normal dbx-style format. */ + 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 == ':') - { - /* read a static member. */ - list->field.bitpos = (long)-1; - p = ++(*pp); - while (*p != ';') p++; - list->field.bitsize = (long) savestring (*pp, p - *pp); - *pp = p + 1; - nfields++; - continue; - } - else if (**pp != ',') - error ("Invalid symbol data: bad structure-type format at symtab pos %d.", + { + 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, ','); @@ -2872,6 +4060,7 @@ read_struct_type (pp, type) } while (**pp != ';'); } + *pp += 1; /* Now create the vector of fields, and record how big it is. */ @@ -2976,6 +4165,60 @@ read_struct_type (pp, type) return type; } +/* Read a definition of an enumberation 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; + + /* Format of an array type: + "ar;lower;upper;". Put code in + to handle this. */ + + index_type = read_type (pp); + if (*(*pp)++ != ';') + error ("Invalid symbol data; improper format of array type decl."); + lower = read_number (pp, ';'); + upper = read_number (pp, ';'); + element_type = read_type (pp); + + { + /* 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. */ @@ -3007,7 +4250,7 @@ read_enum_type (pp, type) while (**pp && **pp != ';') { /* Check for and handle cretinous dbx symbol name continuation! */ - if (**pp == '\\') *pp = next_symbol_text (); + if (**pp == '\\') *pp = next_symbol_text (); p = *pp; while (*p != ':') p++; @@ -3049,8 +4292,8 @@ read_enum_type (pp, type) struct symbol *sym = syms->symbol[j]; SYMBOL_TYPE (sym) = type; TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (sym); - TYPE_FIELD_VALUE (type, n) = SYMBOL_VALUE (sym); - TYPE_FIELD_BITPOS (type, n) = 0; + TYPE_FIELD_VALUE (type, n) = 0; + TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (sym); TYPE_FIELD_BITSIZE (type, n) = 0; } if (syms == osyms) @@ -3060,6 +4303,9 @@ read_enum_type (pp, type) 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; @@ -3067,12 +4313,15 @@ read_range_type (pp, typenums) { char *errp = *pp; int rangenums[2]; - int n1, n2, n3; + int n2, n3; + int self_subrange; + struct type *result_type; /* First comes a type we are a subrange of. - In practice it is usually 0, 1 or the type being defined. */ + In C it is usually 0, 1 or the type being defined. */ read_type_number (pp, rangenums); - n1 = rangenums[1]; + self_subrange = (rangenums[0] == typenums[0] && + rangenums[1] == typenums[1]); /* A semicolon should now follow; skip it. */ if (**pp == ';') @@ -3084,8 +4333,7 @@ read_range_type (pp, typenums) n3 = read_number (pp, ';'); /* A type defined as a subrange of itself, with bounds both 0, is void. */ - if (rangenums[0] == typenums[0] && rangenums[1] == typenums[1] - && n2 == 0 && n3 == 0) + if (self_subrange && n2 == 0 && n3 == 0) return builtin_type_void; /* If n3 is zero and n2 is not, we want a floating type, @@ -3114,12 +4362,16 @@ read_range_type (pp, typenums) return builtin_type_unsigned_long; } - /* Detect unsigned subranges of int. Int is normally 1. - Note that `char' is usually given bounds of 0 to 127, - and would therefore appear unsigned; but it is described - as a subrange of itself, so we reject it here. */ + /* 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; - else if (n2 == 0 && n1 == 1) + /* 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 */ if (n3 == (1 << (8 * sizeof (int))) - 1) @@ -3129,7 +4381,7 @@ read_range_type (pp, typenums) if (n3 == (1 << (8 * sizeof (char))) - 1) return builtin_type_unsigned_char; } - else + else if (n2 == -n3 -1) { /* a signed type */ if (n3 == (1 << (8 * sizeof (int) - 1)) - 1) @@ -3141,8 +4393,49 @@ read_range_type (pp, typenums) if (n3 == (1 << (8 * sizeof (char) - 1)) - 1) return builtin_type_char; } - error ("Invalid symbol data: range type spec %s at symtab pos %d.", - errp - 1, symnum); + + /* 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. @@ -3179,7 +4472,7 @@ read_number (pp, end) } if (end) { - if (c != end) + if (c && c != end) error ("Invalid symbol data: invalid character \\%03o at symbol pos %d.", c, symnum); } else @@ -3204,7 +4497,8 @@ read_args (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! */ + + /* Check for and handle cretinous dbx symbol name continuation! */ if (**pp == '\\') *pp = next_symbol_text (); @@ -3230,28 +4524,30 @@ read_args (pp, end) } /* This function is really horrible, but to avoid it, there would need - to be more filling in of forward references. */ + 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)); + TYPE_VPTR_FIELDNO (type) = + fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1)); return TYPE_VPTR_FIELDNO (type); } -static -initialize () +void +_initialize_dbxread () { symfile = 0; + header_files = (struct header_file *) 0; + this_object_header_files = (int *) 0; 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 codes is at TEXT_START.") ; + "Load the symbols from FILE, assuming its code is at TEXT_START.") ; } -END_FILE - #endif /* READ_DBX_FORMAT */ diff --git a/gdb/default-dep.c b/gdb/default-dep.c new file mode 100644 index 0000000..59bd739 --- /dev/null +++ b/gdb/default-dep.c @@ -0,0 +1,601 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include +#endif + +#ifdef UNISOFT_ASSHOLES +#define PMMU +#define NEW_PMMU +#define mc68881 /* Needed to get float in user.h!!! */ +#include /* For user.h */ +#include +#include +/* Things Unisoft defined differently from every other Unix system */ +#define NBPG PAGESIZE +#define UPAGES USIZE +#define KERNEL_U_ADDR UDOT +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include +#endif +#ifndef N_SET_MAGIC +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif + +#include /* After a.out.h */ +#include +#include + +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. + + If you are having trouble debugging ptrace calls, turn on DEBUG + and every call to ptrace, in this module or elsewhere, will be + logged to stderr. */ +int +call_ptrace (request, pid, arg3, arg4) + int request, pid, arg3, arg4; +{ +#ifdef DEBUG + int result; + + fprintf(stderr, "ptrace(%x,,%x, %x) = ", request, arg3, arg4); + result=ptrace (request, pid, arg3, arg4); + fprintf(stderr, "%x\n", result); + return result; + +#define ptrace call_ptrace + +#else + return ptrace (request, pid, arg3, arg4); +#endif +} + +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; +#ifdef UNISOFT_ASSHOLES + /* You can't write the PC with ptrace 6, only with ptrace 11! */ + if (regno == PC_REGNUM) + ptrace(11, inferior_pid, 16, read_register(regno)); + else +#endif + 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; +#ifdef UNISOFT_ASSHOLES + if (regno == PC_REGNUM) + ptrace(11, inferior_pid, 16, read_register(regno)); + else +#endif + 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 (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. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#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; + +#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) + { + 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 ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* Some machines put an absolute address in here; Unisoft + seems to put the offset in the upage of the regs. Sigh. */ + 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) + perror_with_name (reg_names[regno]); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (reg_names[regno]); + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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); +} diff --git a/gdb/defs.h b/gdb/defs.h index d5653ec..cbc4f5e 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -26,6 +26,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! extern char *savestring (); extern char *concat (); extern char *xmalloc (), *xrealloc (); +extern char *alloca (); extern int parse_escape (); extern char *reg_names[]; @@ -37,8 +38,9 @@ extern int immediate_quit; enum command_class { - class_run, class_vars, class_stack, class_files, class_support, class_info, - class_breakpoint, class_alias, class_obscure, class_user, + 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 @@ -61,6 +63,8 @@ struct cleanup 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 (); /* Structure for saved commands lines @@ -81,3 +85,4 @@ char *current_directory; #ifdef sparc #include #endif + diff --git a/gdb/dep.c b/gdb/dep.c new file mode 120000 index 0000000..26ce829 --- /dev/null +++ b/gdb/dep.c @@ -0,0 +1 @@ +sparc-dep.c \ No newline at end of file diff --git a/gdb/eval.c b/gdb/eval.c index 5dcd993..ae9720b 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -19,12 +19,11 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" -#include "initialize.h" +#include "param.h" #include "symtab.h" #include "value.h" #include "expression.h" -START_FILE /* Parse the string EXP as a C expression, evaluate it, and return the result as a number. */ @@ -38,7 +37,7 @@ parse_and_eval_address (exp) register struct cleanup *old_chain = make_cleanup (free_current_contents, &expr); - addr = value_as_long (evaluate_expression (expr)); + addr = (CORE_ADDR) value_as_long (evaluate_expression (expr)); do_cleanups (old_chain); return addr; } @@ -104,9 +103,11 @@ static value evaluate_subexp_with_coercion (); /* Values of NOSIDE argument to eval_subexp. */ enum noside -{ EVAL_NORMAL, - EVAL_SKIP, - EVAL_AVOID_SIDE_EFFECTS, +{ EVAL_NORMAL, + EVAL_SKIP, /* Only effect is to increment pos. */ + EVAL_AVOID_SIDE_EFFECTS, /* Don't modify any variables or + call any functions. Correct type + is returned. */ }; value @@ -137,7 +138,7 @@ evaluate_subexp (expect_type, exp, pos, noside) { enum exp_opcode op; int tem; - register int pc, pc2, *oldpos; + register int pc, pc2, oldpos; register value arg1, arg2, arg3; int nargs; value *argvec; @@ -171,16 +172,38 @@ evaluate_subexp (expect_type, exp, pos, noside) case OP_LAST: (*pos) += 2; - return access_value_history (exp->elts[pc + 1].longconst); + return access_value_history ((int) exp->elts[pc + 1].longconst); case OP_REGISTER: (*pos) += 2; - return value_of_register (exp->elts[pc + 1].longconst); + 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; @@ -189,7 +212,7 @@ evaluate_subexp (expect_type, exp, pos, noside) int fnptr; int tem2; - nargs = exp->elts[pc + 1].longconst + 1; + nargs = (int) exp->elts[pc + 1].longconst + 1; /* First, evaluate the structure into arg2 */ pc2 = (*pos)++; @@ -213,7 +236,7 @@ evaluate_subexp (expect_type, exp, pos, noside) arg1 = evaluate_subexp (0, exp, pos, noside); - fnptr = value_as_long (arg1); + fnptr = (int) value_as_long (arg1); if (fnptr < 128) { struct type *basetype; @@ -262,7 +285,7 @@ evaluate_subexp (expect_type, exp, pos, noside) /* Hair for method invocations */ int tem2; - nargs = exp->elts[pc + 1].longconst + 1; + nargs = (int) exp->elts[pc + 1].longconst + 1; /* First, evaluate the structure into arg2 */ pc2 = (*pos)++; tem2 = strlen (&exp->elts[pc2 + 1].string); @@ -283,7 +306,7 @@ evaluate_subexp (expect_type, exp, pos, noside) } else { - nargs = exp->elts[pc + 1].longconst; + nargs = (int) exp->elts[pc + 1].longconst; tem = 0; } argvec = (value *) alloca (sizeof (value) * (nargs + 2)); @@ -311,30 +334,23 @@ evaluate_subexp (expect_type, exp, pos, noside) if (noside == EVAL_SKIP) goto nosideret; if (noside == EVAL_AVOID_SIDE_EFFECTS) - return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]))); - return call_function (argvec[0], nargs, argvec + 1); + { + /* 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. */ - 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); + struct type *ftype = + TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])); - 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; + 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); @@ -452,6 +468,16 @@ evaluate_subexp (expect_type, exp, pos, noside) 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); @@ -463,11 +489,21 @@ evaluate_subexp (expect_type, exp, pos, noside) arg2 = evaluate_subexp (0, exp, pos, (tem ? EVAL_SKIP : noside)); return value_from_long (builtin_type_int, - !tem && !value_zerop (arg2)); + (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); @@ -479,7 +515,7 @@ evaluate_subexp (expect_type, exp, pos, noside) arg2 = evaluate_subexp (0, exp, pos, (!tem ? EVAL_SKIP : noside)); return value_from_long (builtin_type_int, - !tem || !value_zerop (arg2)); + (LONGEST) (!tem || !value_zerop (arg2))); } case BINOP_EQUAL: @@ -494,7 +530,7 @@ evaluate_subexp (expect_type, exp, pos, noside) else { tem = value_equal (arg1, arg2); - return value_from_long (builtin_type_int, tem); + return value_from_long (builtin_type_int, (LONGEST) tem); } case BINOP_NOTEQUAL: @@ -509,7 +545,7 @@ evaluate_subexp (expect_type, exp, pos, noside) else { tem = value_equal (arg1, arg2); - return value_from_long (builtin_type_int, ! tem); + return value_from_long (builtin_type_int, (LONGEST) ! tem); } case BINOP_LESS: @@ -524,7 +560,7 @@ evaluate_subexp (expect_type, exp, pos, noside) else { tem = value_less (arg1, arg2); - return value_from_long (builtin_type_int, tem); + return value_from_long (builtin_type_int, (LONGEST) tem); } case BINOP_GTR: @@ -539,7 +575,7 @@ evaluate_subexp (expect_type, exp, pos, noside) else { tem = value_less (arg2, arg1); - return value_from_long (builtin_type_int, tem); + return value_from_long (builtin_type_int, (LONGEST) tem); } case BINOP_GEQ: @@ -554,7 +590,7 @@ evaluate_subexp (expect_type, exp, pos, noside) else { tem = value_less (arg1, arg2); - return value_from_long (builtin_type_int, ! tem); + return value_from_long (builtin_type_int, (LONGEST) ! tem); } case BINOP_LEQ: @@ -569,7 +605,7 @@ evaluate_subexp (expect_type, exp, pos, noside) else { tem = value_less (arg2, arg1); - return value_from_long (builtin_type_int, ! tem); + return value_from_long (builtin_type_int, (LONGEST) ! tem); } case BINOP_REPEAT: @@ -577,7 +613,7 @@ evaluate_subexp (expect_type, exp, pos, noside) arg2 = evaluate_subexp (0, exp, pos, noside); if (noside == EVAL_SKIP) goto nosideret; - return value_repeat (arg1, value_as_long (arg2)); + return value_repeat (arg1, (int) value_as_long (arg2)); case BINOP_COMMA: evaluate_subexp (0, exp, pos, noside); @@ -608,7 +644,8 @@ evaluate_subexp (expect_type, exp, pos, noside) if (unop_user_defined_p (op, arg1)) return value_x_unop (arg1, op, 0); else - return value_from_long (builtin_type_int, value_zerop (arg1)); + return value_from_long (builtin_type_int, + (LONGEST) value_zerop (arg1)); case UNOP_IND: if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR) @@ -670,7 +707,8 @@ evaluate_subexp (expect_type, exp, pos, noside) arg1 = evaluate_subexp (expect_type, exp, pos, noside); if (noside == EVAL_SKIP) goto nosideret; - return value_at (exp->elts[pc + 1].type, value_as_long (arg1)); + 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); @@ -682,7 +720,8 @@ evaluate_subexp (expect_type, exp, pos, noside) } else { - arg2 = value_add (arg1, value_from_long (builtin_type_char, 1)); + arg2 = value_add (arg1, value_from_long (builtin_type_char, + (LONGEST) 1)); return value_assign (arg1, arg2); } @@ -696,7 +735,8 @@ evaluate_subexp (expect_type, exp, pos, noside) } else { - arg2 = value_sub (arg1, value_from_long (builtin_type_char, 1)); + arg2 = value_sub (arg1, value_from_long (builtin_type_char, + (LONGEST) 1)); return value_assign (arg1, arg2); } @@ -710,7 +750,8 @@ evaluate_subexp (expect_type, exp, pos, noside) } else { - arg2 = value_add (arg1, value_from_long (builtin_type_char, 1)); + arg2 = value_add (arg1, value_from_long (builtin_type_char, + (LONGEST) 1)); value_assign (arg1, arg2); return arg1; } @@ -725,7 +766,8 @@ evaluate_subexp (expect_type, exp, pos, noside) } else { - arg2 = value_sub (arg1, value_from_long (builtin_type_char, 1)); + arg2 = value_sub (arg1, value_from_long (builtin_type_char, + (LONGEST) 1)); value_assign (arg1, arg2); return arg1; } @@ -735,11 +777,11 @@ evaluate_subexp (expect_type, exp, pos, noside) return value_of_this (1); default: - error ("internal error: I dont know how to evaluation what you gave me"); + error ("internal error: I do not know how to evaluate what you gave me"); } nosideret: - return value_from_long (builtin_type_long, 1); + return value_from_long (builtin_type_long, (LONGEST) 1); } /* Evaluate a subexpression of EXP, at index *POS, @@ -839,28 +881,22 @@ evaluate_subexp_for_sizeof (exp, pos) case UNOP_IND: (*pos)++; val = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS); - return value_from_long (builtin_type_int, - TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val)))); + 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, - TYPE_LENGTH (exp->elts[pc + 1].type)); + 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, - TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 1].symbol))); + (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, - TYPE_LENGTH (VALUE_TYPE (val))); + (LONGEST) TYPE_LENGTH (VALUE_TYPE (val))); } } - -static -initialize () -{ } - -END_FILE diff --git a/gdb/expprint.c b/gdb/expprint.c index b7adc29..966f770 100644 --- a/gdb/expprint.c +++ b/gdb/expprint.c @@ -20,6 +20,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include "defs.h" #include "symtab.h" +#include "param.h" #include "expression.h" #include @@ -79,7 +80,9 @@ static struct op_print op_print_tab[] = {"&", UNOP_ADDR, PREC_PREFIX, 0}, {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0}, {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0}, - {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0} + {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0}, + /* C++ */ + {"::", BINOP_SCOPE, PREC_PREFIX, 0}, }; static void print_subexp (); @@ -119,6 +122,18 @@ print_subexp (exp, pos, stream, prec) 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, diff --git a/gdb/expread.tab.c b/gdb/expread.tab.c index 5d6ff11..99a855e 100644 --- a/gdb/expread.tab.c +++ b/gdb/expread.tab.c @@ -13,9 +13,8 @@ static int expout_size; static int expout_ptr; static int yylex (); -static yyerror (); +static void yyerror (); static void write_exp_elt (); -static void write_exp_elt2 (); static void write_exp_string (); static void start_arglist (); static int end_arglist (); @@ -27,6 +26,13 @@ static char *copy_name (); 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; @@ -50,7 +56,7 @@ struct stoken int length; }; -# line 86 "expread.y" +# line 92 "expread.y" typedef union { long lval; @@ -106,7 +112,7 @@ extern short yyerrflag; YYSTYPE yylval, yyval; # define YYERRCODE 256 -# line 625 "expread.y" +# line 630 "expread.y" /* Begin counting arguments for a function call, @@ -157,16 +163,13 @@ free_funcalls () /* Add one element to the end of the expression. */ -/* To avoid a bug in the Sun 4 compiler, we pass only things that - can fit into a single register through here. */ +/* 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; */ - long expelt; + union exp_element expelt; { - union exp_element temp; - temp.longconst = expelt; - if (expout_ptr >= expout_size) { expout_size *= 2; @@ -174,25 +177,73 @@ write_exp_elt (expelt) sizeof (struct expression) + expout_size * sizeof (union exp_element)); } - expout->elts[expout_ptr++] = /* expelt */ temp; + 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); } -/* Things that take more space must come through here. */ static void -write_exp_elt2 (expelt) +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 temp; - temp.doubleconst = expelt; + union exp_element tmp; - 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++] = temp; + 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. @@ -211,13 +262,13 @@ write_exp_string (str) 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)); + 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 (len); + write_exp_elt_longcst (len); } /* During parsing of a C expression, the pointer to the next character @@ -284,12 +335,13 @@ parse_number (olen) while (len-- > 0) { c = *p++; - n *= base; + if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + if (c != 'l') + n *= base; if (c >= '0' && c <= '9') n += c - '0'; else { - if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; if (base == 16 && c >= 'a' && c <= 'f') n += c - 'a' + 10; else if (len == 0 && c == 'l') @@ -346,6 +398,29 @@ static struct token tokentab2[] = {">=", 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 @@ -529,7 +604,7 @@ yylex () /* Handle tokens that refer to machine registers: $ followed by a register name. */ - if (*tokstart == '$') + if (*tokstart == '$') { for (c = 0; c < NUM_REGS; c++) if (namelen - 1 == strlen (reg_names[c]) && !strncmp (tokstart + 1, reg_names[c], namelen - 1)) @@ -537,7 +612,14 @@ yylex () 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; + } + } if (namelen == 6 && !strncmp (tokstart, "struct", 6)) { return STRUCT; @@ -555,10 +637,10 @@ yylex () { return ENUM; } - if (!strncmp (tokstart, "this", 4)) - { - return THIS; - } + if (!strncmp (tokstart, "this", 4) + && lookup_symbol ("$this", expression_context_block, + VAR_NAMESPACE, 0)) + return THIS; } if (namelen == 6 && !strncmp (tokstart, "sizeof", 6)) { @@ -587,7 +669,7 @@ yylex () return NAME; } -static +static void yyerror () { error ("Invalid syntax in expression."); @@ -846,6 +928,8 @@ parse_c_1 (stringptr, block, comma) lexptr = *stringptr; + paren_depth = 0; + comma_terminates = comma; if (lexptr == 0 || *lexptr == 0) @@ -859,8 +943,9 @@ parse_c_1 (stringptr, block, comma) 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)); + expout = (struct expression *) + xmalloc (sizeof (struct expression) + + expout_size * sizeof (union exp_element)); make_cleanup (free_current_contents, &expout); if (yyparse ()) yyerror (); @@ -1054,7 +1139,7 @@ short yydef[]={ 0, 23, 0, 69, 0, 70, 0, 77, 71, 0, 78 }; #ifndef lint -static char yaccpar_sccsid[] = "@(#)yaccpar 1.6 88/02/08 SMI"; /* from UCB 4.1 83/02/11 */ +static char yaccpar_sccsid[] = "@(#)yaccpar 1.5 86/08/27 SMI"; /* from UCB 4.1 83/02/11 */ #endif # @@ -1203,202 +1288,202 @@ yyparse() { switch(yym){ case 3: -# line 159 "expread.y" -{ write_exp_elt (BINOP_COMMA); } break; +# line 165 "expread.y" +{ write_exp_elt_opcode (BINOP_COMMA); } break; case 4: -# line 164 "expread.y" -{ write_exp_elt (UNOP_IND); } break; +# line 170 "expread.y" +{ write_exp_elt_opcode (UNOP_IND); } break; case 5: -# line 167 "expread.y" -{ write_exp_elt (UNOP_ADDR); } break; +# line 173 "expread.y" +{ write_exp_elt_opcode (UNOP_ADDR); } break; case 6: -# line 170 "expread.y" -{ write_exp_elt (UNOP_NEG); } break; +# line 176 "expread.y" +{ write_exp_elt_opcode (UNOP_NEG); } break; case 7: -# line 174 "expread.y" -{ write_exp_elt (UNOP_ZEROP); } break; +# line 180 "expread.y" +{ write_exp_elt_opcode (UNOP_ZEROP); } break; case 8: -# line 178 "expread.y" -{ write_exp_elt (UNOP_LOGNOT); } break; +# line 184 "expread.y" +{ write_exp_elt_opcode (UNOP_LOGNOT); } break; case 9: -# line 182 "expread.y" -{ write_exp_elt (UNOP_PREINCREMENT); } break; +# line 188 "expread.y" +{ write_exp_elt_opcode (UNOP_PREINCREMENT); } break; case 10: -# line 186 "expread.y" -{ write_exp_elt (UNOP_PREDECREMENT); } break; +# line 192 "expread.y" +{ write_exp_elt_opcode (UNOP_PREDECREMENT); } break; case 11: -# line 190 "expread.y" -{ write_exp_elt (UNOP_POSTINCREMENT); } break; +# line 196 "expread.y" +{ write_exp_elt_opcode (UNOP_POSTINCREMENT); } break; case 12: -# line 194 "expread.y" -{ write_exp_elt (UNOP_POSTDECREMENT); } break; +# line 200 "expread.y" +{ write_exp_elt_opcode (UNOP_POSTDECREMENT); } break; case 13: -# line 198 "expread.y" -{ write_exp_elt (UNOP_SIZEOF); } break; +# line 204 "expread.y" +{ write_exp_elt_opcode (UNOP_SIZEOF); } break; case 14: -# line 202 "expread.y" -{ write_exp_elt (STRUCTOP_PTR); +# line 208 "expread.y" +{ write_exp_elt_opcode (STRUCTOP_PTR); write_exp_string (yypvt[-0].sval); - write_exp_elt (STRUCTOP_PTR); } break; + write_exp_elt_opcode (STRUCTOP_PTR); } break; case 15: -# line 208 "expread.y" -{ write_exp_elt (STRUCTOP_MPTR); } break; +# line 214 "expread.y" +{ write_exp_elt_opcode (STRUCTOP_MPTR); } break; case 16: -# line 212 "expread.y" -{ write_exp_elt (STRUCTOP_STRUCT); +# line 218 "expread.y" +{ write_exp_elt_opcode (STRUCTOP_STRUCT); write_exp_string (yypvt[-0].sval); - write_exp_elt (STRUCTOP_STRUCT); } break; + write_exp_elt_opcode (STRUCTOP_STRUCT); } break; case 17: -# line 218 "expread.y" -{ write_exp_elt (STRUCTOP_MEMBER); } break; +# line 224 "expread.y" +{ write_exp_elt_opcode (STRUCTOP_MEMBER); } break; case 18: -# line 222 "expread.y" -{ write_exp_elt (BINOP_SUBSCRIPT); } break; -case 19: # line 228 "expread.y" +{ write_exp_elt_opcode (BINOP_SUBSCRIPT); } break; +case 19: +# line 234 "expread.y" { start_arglist (); } break; case 20: -# line 230 "expread.y" -{ write_exp_elt (OP_FUNCALL); - write_exp_elt (end_arglist ()); - write_exp_elt (OP_FUNCALL); } break; +# line 236 "expread.y" +{ write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst (end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } break; case 22: -# line 239 "expread.y" +# line 245 "expread.y" { arglist_len = 1; } break; case 23: -# line 243 "expread.y" +# line 249 "expread.y" { arglist_len++; } break; case 24: -# line 247 "expread.y" -{ write_exp_elt (UNOP_MEMVAL); - write_exp_elt (yypvt[-2].tval); - write_exp_elt (UNOP_MEMVAL); } break; -case 25: # line 253 "expread.y" -{ write_exp_elt (UNOP_CAST); - write_exp_elt (yypvt[-2].tval); - write_exp_elt (UNOP_CAST); } break; -case 26: +{ write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (yypvt[-2].tval); + write_exp_elt_opcode (UNOP_MEMVAL); } break; +case 25: # line 259 "expread.y" +{ write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yypvt[-2].tval); + write_exp_elt_opcode (UNOP_CAST); } break; +case 26: +# line 265 "expread.y" { } break; case 27: -# line 265 "expread.y" -{ write_exp_elt (BINOP_REPEAT); } break; +# line 271 "expread.y" +{ write_exp_elt_opcode (BINOP_REPEAT); } break; case 28: -# line 269 "expread.y" -{ write_exp_elt (BINOP_MUL); } break; +# line 275 "expread.y" +{ write_exp_elt_opcode (BINOP_MUL); } break; case 29: -# line 273 "expread.y" -{ write_exp_elt (BINOP_DIV); } break; +# line 279 "expread.y" +{ write_exp_elt_opcode (BINOP_DIV); } break; case 30: -# line 277 "expread.y" -{ write_exp_elt (BINOP_REM); } break; +# line 283 "expread.y" +{ write_exp_elt_opcode (BINOP_REM); } break; case 31: -# line 281 "expread.y" -{ write_exp_elt (BINOP_ADD); } break; +# line 287 "expread.y" +{ write_exp_elt_opcode (BINOP_ADD); } break; case 32: -# line 285 "expread.y" -{ write_exp_elt (BINOP_SUB); } break; +# line 291 "expread.y" +{ write_exp_elt_opcode (BINOP_SUB); } break; case 33: -# line 289 "expread.y" -{ write_exp_elt (BINOP_LSH); } break; +# line 295 "expread.y" +{ write_exp_elt_opcode (BINOP_LSH); } break; case 34: -# line 293 "expread.y" -{ write_exp_elt (BINOP_RSH); } break; +# line 299 "expread.y" +{ write_exp_elt_opcode (BINOP_RSH); } break; case 35: -# line 297 "expread.y" -{ write_exp_elt (BINOP_EQUAL); } break; +# line 303 "expread.y" +{ write_exp_elt_opcode (BINOP_EQUAL); } break; case 36: -# line 301 "expread.y" -{ write_exp_elt (BINOP_NOTEQUAL); } break; +# line 307 "expread.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); } break; case 37: -# line 305 "expread.y" -{ write_exp_elt (BINOP_LEQ); } break; +# line 311 "expread.y" +{ write_exp_elt_opcode (BINOP_LEQ); } break; case 38: -# line 309 "expread.y" -{ write_exp_elt (BINOP_GEQ); } break; +# line 315 "expread.y" +{ write_exp_elt_opcode (BINOP_GEQ); } break; case 39: -# line 313 "expread.y" -{ write_exp_elt (BINOP_LESS); } break; +# line 319 "expread.y" +{ write_exp_elt_opcode (BINOP_LESS); } break; case 40: -# line 317 "expread.y" -{ write_exp_elt (BINOP_GTR); } break; +# line 323 "expread.y" +{ write_exp_elt_opcode (BINOP_GTR); } break; case 41: -# line 321 "expread.y" -{ write_exp_elt (BINOP_LOGAND); } break; +# line 327 "expread.y" +{ write_exp_elt_opcode (BINOP_LOGAND); } break; case 42: -# line 325 "expread.y" -{ write_exp_elt (BINOP_LOGXOR); } break; +# line 331 "expread.y" +{ write_exp_elt_opcode (BINOP_LOGXOR); } break; case 43: -# line 329 "expread.y" -{ write_exp_elt (BINOP_LOGIOR); } break; +# line 335 "expread.y" +{ write_exp_elt_opcode (BINOP_LOGIOR); } break; case 44: -# line 333 "expread.y" -{ write_exp_elt (BINOP_AND); } break; +# line 339 "expread.y" +{ write_exp_elt_opcode (BINOP_AND); } break; case 45: -# line 337 "expread.y" -{ write_exp_elt (BINOP_OR); } break; +# line 343 "expread.y" +{ write_exp_elt_opcode (BINOP_OR); } break; case 46: -# line 341 "expread.y" -{ write_exp_elt (TERNOP_COND); } break; +# line 347 "expread.y" +{ write_exp_elt_opcode (TERNOP_COND); } break; case 47: -# line 345 "expread.y" -{ write_exp_elt (BINOP_ASSIGN); } break; +# line 351 "expread.y" +{ write_exp_elt_opcode (BINOP_ASSIGN); } break; case 48: -# line 349 "expread.y" -{ write_exp_elt (BINOP_ASSIGN_MODIFY); - write_exp_elt (yypvt[-1].opcode); - write_exp_elt (BINOP_ASSIGN_MODIFY); } break; -case 49: # line 355 "expread.y" -{ write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_long); - write_exp_elt (yypvt[-0].lval); - write_exp_elt (OP_LONG); } break; +{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode (yypvt[-1].opcode); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); } break; +case 49: +# line 361 "expread.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_long); + write_exp_elt_longcst (yypvt[-0].lval); + write_exp_elt_opcode (OP_LONG); } break; case 50: -# line 362 "expread.y" -{ write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_char); - write_exp_elt (yypvt[-0].lval); - write_exp_elt (OP_LONG); } break; +# line 368 "expread.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst (yypvt[-0].lval); + write_exp_elt_opcode (OP_LONG); } break; case 51: -# line 369 "expread.y" -{ write_exp_elt (OP_DOUBLE); - write_exp_elt (builtin_type_double); - write_exp_elt2 (yypvt[-0].dval); - write_exp_elt (OP_DOUBLE); } break; +# line 375 "expread.y" +{ write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst (yypvt[-0].dval); + write_exp_elt_opcode (OP_DOUBLE); } break; case 53: -# line 379 "expread.y" -{ write_exp_elt (OP_LAST); - write_exp_elt (yypvt[-0].lval); - write_exp_elt (OP_LAST); } break; -case 54: # line 385 "expread.y" -{ write_exp_elt (OP_REGISTER); - write_exp_elt (yypvt[-0].lval); - write_exp_elt (OP_REGISTER); } break; -case 55: +{ write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst (yypvt[-0].lval); + write_exp_elt_opcode (OP_LAST); } break; +case 54: # line 391 "expread.y" -{ write_exp_elt (OP_INTERNALVAR); - write_exp_elt (yypvt[-0].ivar); - write_exp_elt (OP_INTERNALVAR); } break; -case 56: +{ write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst (yypvt[-0].lval); + write_exp_elt_opcode (OP_REGISTER); } break; +case 55: # line 397 "expread.y" -{ write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_int); - write_exp_elt ((long) TYPE_LENGTH (yypvt[-1].tval)); - write_exp_elt (OP_LONG); } break; +{ write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern (yypvt[-0].ivar); + write_exp_elt_opcode (OP_INTERNALVAR); } break; +case 56: +# line 403 "expread.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((long) TYPE_LENGTH (yypvt[-1].tval)); + write_exp_elt_opcode (OP_LONG); } break; case 57: -# line 404 "expread.y" -{ write_exp_elt (OP_STRING); +# line 410 "expread.y" +{ write_exp_elt_opcode (OP_STRING); write_exp_string (yypvt[-0].sval); - write_exp_elt (OP_STRING); } break; + write_exp_elt_opcode (OP_STRING); } break; case 58: -# line 411 "expread.y" -{ write_exp_elt (OP_THIS); - write_exp_elt (OP_THIS); } break; +# line 417 "expread.y" +{ write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); } break; case 59: -# line 418 "expread.y" +# line 424 "expread.y" { struct symtab *tem = lookup_symtab (copy_name (yypvt[-0].sval)); struct symbol *sym; @@ -1409,7 +1494,7 @@ case 59: { sym = lookup_symbol (copy_name (yypvt[-0].sval), expression_context_block, - VAR_NAMESPACE); + VAR_NAMESPACE, 0); if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) yyval.bval = SYMBOL_BLOCK_VALUE (sym); else @@ -1418,29 +1503,25 @@ case 59: } } break; case 60: -# line 439 "expread.y" -{ - struct symbol *tem - = lookup_symbol (copy_name (yypvt[-0].sval), yypvt[-2].bval, VAR_NAMESPACE); +# line 445 "expread.y" +{ struct symbol *tem + = lookup_symbol (copy_name (yypvt[-0].sval), yypvt[-2].bval, VAR_NAMESPACE, 0); if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) error ("No function \"%s\" in specified context.", copy_name (yypvt[-0].sval)); - yyval.bval = SYMBOL_BLOCK_VALUE (tem); - } break; + yyval.bval = SYMBOL_BLOCK_VALUE (tem); } break; case 61: -# line 450 "expread.y" -{ - struct symbol *sym; - sym = lookup_symbol (copy_name (yypvt[-0].sval), yypvt[-2].bval, VAR_NAMESPACE); +# line 454 "expread.y" +{ struct symbol *sym; + sym = lookup_symbol (copy_name (yypvt[-0].sval), yypvt[-2].bval, VAR_NAMESPACE, 0); if (sym == 0) error ("No symbol \"%s\" in specified context.", copy_name (yypvt[-0].sval)); - write_exp_elt (OP_VAR_VALUE); - write_exp_elt (sym); - write_exp_elt (OP_VAR_VALUE); - } break; + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } break; case 62: -# line 463 "expread.y" +# line 465 "expread.y" { struct type *type = yypvt[-2].tval; if (TYPE_CODE (type) != TYPE_CODE_STRUCT @@ -1448,24 +1529,24 @@ case 62: error ("`%s' is not defined as an aggregate type.", TYPE_NAME (type)); - write_exp_elt (OP_SCOPE); - write_exp_elt (type); + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); write_exp_string (yypvt[-0].sval); - write_exp_elt (OP_SCOPE); + write_exp_elt_opcode (OP_SCOPE); } break; case 63: -# line 476 "expread.y" +# line 478 "expread.y" { char *name = copy_name (yypvt[-0].sval); struct symbol *sym; int i; - sym = lookup_symbol_2 (name, 0, VAR_NAMESPACE); + sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0); if (sym) { - write_exp_elt (OP_VAR_VALUE); - write_exp_elt (sym); - write_exp_elt (OP_VAR_VALUE); + 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++) @@ -1474,130 +1555,133 @@ case 63: if (i < misc_function_count) { - write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_int); - write_exp_elt (misc_function_vector[i].address); - write_exp_elt (OP_LONG); - write_exp_elt (UNOP_MEMVAL); - write_exp_elt (builtin_type_char); - write_exp_elt (UNOP_MEMVAL); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst (misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); } else - if (symtab_list == 0) + 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); } break; case 64: -# line 512 "expread.y" +# line 515 "expread.y" { struct symbol *sym; - sym = lookup_symbol_1 (copy_name (yypvt[-0].sval), - expression_context_block, - VAR_NAMESPACE); + int is_a_field_of_this; + + sym = lookup_symbol (copy_name (yypvt[-0].sval), + expression_context_block, + VAR_NAMESPACE, + &is_a_field_of_this); if (sym) { - write_exp_elt (OP_VAR_VALUE); - write_exp_elt (sym); - write_exp_elt (OP_VAR_VALUE); + 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 + else if (is_a_field_of_this) { - register char *arg = copy_name (yypvt[-0].sval); - register int i; - int v, val; - /* C++: see if it hangs off of `this'. Must + /* C++: it hangs off of `this'. Must not inadvertently convert from a method call to data ref. */ - v = (int)value_of_this (0); - if (v) - { - val = check_field (v, arg); - if (val) - { - write_exp_elt (OP_THIS); - write_exp_elt (OP_THIS); - write_exp_elt (STRUCTOP_PTR); - write_exp_string (yypvt[-0].sval); - write_exp_elt (STRUCTOP_PTR); - break; - } - } - sym = lookup_symbol_2 (arg, 0, VAR_NAMESPACE); - if (sym) - { - write_exp_elt (OP_VAR_VALUE); - write_exp_elt (sym); - write_exp_elt (OP_VAR_VALUE); - break; /* YACC-dependent */ - } + 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 (yypvt[-0].sval); + write_exp_elt_opcode (STRUCTOP_PTR); + } + else + { + register int i; + register char *arg = copy_name (yypvt[-0].sval); + for (i = 0; i < misc_function_count; i++) if (!strcmp (misc_function_vector[i].name, arg)) break; if (i < misc_function_count) { - write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_int); - write_exp_elt (misc_function_vector[i].address); - write_exp_elt (OP_LONG); - write_exp_elt (UNOP_MEMVAL); - write_exp_elt (builtin_type_char); - write_exp_elt (UNOP_MEMVAL); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst (misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + 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 - if (symtab_list == 0) - error ("No symbol table is loaded. Use the \"symbol-file\" command."); - else - error ("No symbol \"%s\" in current context.", - copy_name (yypvt[-0].sval)); + error ("No symbol \"%s\" in current context.", + copy_name (yypvt[-0].sval)); } } break; case 66: -# line 578 "expread.y" +# line 583 "expread.y" { yyval.tval = lookup_pointer_type (yypvt[-1].tval); } break; case 67: -# line 580 "expread.y" +# line 585 "expread.y" { yyval.tval = lookup_reference_type (yypvt[-1].tval); } break; case 68: -# line 582 "expread.y" +# line 587 "expread.y" { yyval.tval = lookup_member_type (builtin_type_int, yypvt[-2].tval); } break; case 69: -# line 584 "expread.y" +# line 589 "expread.y" { yyval.tval = lookup_member_type (yypvt[-5].tval, yypvt[-3].tval); } break; case 70: -# line 586 "expread.y" -{ yyval.tval = lookup_member_type (lookup_function_type (yypvt[-7].tval, 0), yypvt[-5].tval); } break; +# line 591 "expread.y" +{ yyval.tval = lookup_member_type (lookup_function_type (yypvt[-7].tval)); } break; case 71: -# line 588 "expread.y" -{ yyval.tval = lookup_member_type (lookup_function_type (yypvt[-8].tval, yypvt[-1].tvec), yypvt[-6].tval); +# line 593 "expread.y" +{ yyval.tval = lookup_member_type (lookup_function_type (yypvt[-8].tval)); free (yypvt[-1].tvec); } break; case 72: -# line 594 "expread.y" +# line 599 "expread.y" { yyval.tval = lookup_typename (copy_name (yypvt[-0].sval), expression_context_block, 0); } break; case 73: -# line 597 "expread.y" +# line 602 "expread.y" { yyval.tval = lookup_struct (copy_name (yypvt[-0].sval), expression_context_block); } break; case 74: -# line 600 "expread.y" +# line 605 "expread.y" { yyval.tval = lookup_union (copy_name (yypvt[-0].sval), expression_context_block); } break; case 75: -# line 603 "expread.y" +# line 608 "expread.y" { yyval.tval = lookup_enum (copy_name (yypvt[-0].sval), expression_context_block); } break; case 76: -# line 606 "expread.y" +# line 611 "expread.y" { yyval.tval = lookup_unsigned_typename (copy_name (yypvt[-0].sval)); } break; case 77: -# line 611 "expread.y" +# line 616 "expread.y" { yyval.tvec = (struct type **)xmalloc (sizeof (struct type *) * 2); yyval.tvec[0] = (struct type *)0; yyval.tvec[1] = yypvt[-0].tval; } break; case 78: -# line 616 "expread.y" +# line 621 "expread.y" { int len = sizeof (struct type *) * ++(yypvt[-2].ivec[0]); yyval.tvec = (struct type **)xrealloc (yypvt[-2].tvec, len); yyval.tvec[yyval.ivec[0]] = yypvt[-0].tval; diff --git a/gdb/expread.y b/gdb/expread.y index 97628ef..fd6caa9 100644 --- a/gdb/expread.y +++ b/gdb/expread.y @@ -41,9 +41,8 @@ static int expout_size; static int expout_ptr; static int yylex (); -static yyerror (); +static void yyerror (); static void write_exp_elt (); -static void write_exp_elt2 (); static void write_exp_string (); static void start_arglist (); static int end_arglist (); @@ -55,6 +54,13 @@ static char *copy_name (); 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; @@ -156,70 +162,70 @@ start : exp1 /* Expressions, including the comma operator. */ exp1 : exp | exp1 ',' exp - { write_exp_elt (BINOP_COMMA); } + { write_exp_elt_opcode (BINOP_COMMA); } ; /* Expressions, not including the comma operator. */ exp : '*' exp %prec UNARY - { write_exp_elt (UNOP_IND); } + { write_exp_elt_opcode (UNOP_IND); } exp : '&' exp %prec UNARY - { write_exp_elt (UNOP_ADDR); } + { write_exp_elt_opcode (UNOP_ADDR); } exp : '-' exp %prec UNARY - { write_exp_elt (UNOP_NEG); } + { write_exp_elt_opcode (UNOP_NEG); } ; exp : '!' exp %prec UNARY - { write_exp_elt (UNOP_ZEROP); } + { write_exp_elt_opcode (UNOP_ZEROP); } ; exp : '~' exp %prec UNARY - { write_exp_elt (UNOP_LOGNOT); } + { write_exp_elt_opcode (UNOP_LOGNOT); } ; exp : INCREMENT exp %prec UNARY - { write_exp_elt (UNOP_PREINCREMENT); } + { write_exp_elt_opcode (UNOP_PREINCREMENT); } ; exp : DECREMENT exp %prec UNARY - { write_exp_elt (UNOP_PREDECREMENT); } + { write_exp_elt_opcode (UNOP_PREDECREMENT); } ; exp : exp INCREMENT %prec UNARY - { write_exp_elt (UNOP_POSTINCREMENT); } + { write_exp_elt_opcode (UNOP_POSTINCREMENT); } ; exp : exp DECREMENT %prec UNARY - { write_exp_elt (UNOP_POSTDECREMENT); } + { write_exp_elt_opcode (UNOP_POSTDECREMENT); } ; exp : SIZEOF exp %prec UNARY - { write_exp_elt (UNOP_SIZEOF); } + { write_exp_elt_opcode (UNOP_SIZEOF); } ; exp : exp ARROW name - { write_exp_elt (STRUCTOP_PTR); + { write_exp_elt_opcode (STRUCTOP_PTR); write_exp_string ($3); - write_exp_elt (STRUCTOP_PTR); } + write_exp_elt_opcode (STRUCTOP_PTR); } ; exp : exp ARROW '*' exp - { write_exp_elt (STRUCTOP_MPTR); } + { write_exp_elt_opcode (STRUCTOP_MPTR); } ; exp : exp '.' name - { write_exp_elt (STRUCTOP_STRUCT); + { write_exp_elt_opcode (STRUCTOP_STRUCT); write_exp_string ($3); - write_exp_elt (STRUCTOP_STRUCT); } + write_exp_elt_opcode (STRUCTOP_STRUCT); } ; exp : exp '.' '*' exp - { write_exp_elt (STRUCTOP_MEMBER); } + { write_exp_elt_opcode (STRUCTOP_MEMBER); } ; exp : exp '[' exp1 ']' - { write_exp_elt (BINOP_SUBSCRIPT); } + { write_exp_elt_opcode (BINOP_SUBSCRIPT); } ; exp : exp '(' @@ -227,9 +233,9 @@ exp : exp '(' being accumulated by an outer function call. */ { start_arglist (); } arglist ')' - { write_exp_elt (OP_FUNCALL); - write_exp_elt (end_arglist ()); - write_exp_elt (OP_FUNCALL); } + { write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst (end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } ; arglist : @@ -244,15 +250,15 @@ arglist : arglist ',' exp %prec ABOVE_COMMA ; exp : '{' type '}' exp %prec UNARY - { write_exp_elt (UNOP_MEMVAL); - write_exp_elt ($2); - write_exp_elt (UNOP_MEMVAL); } + { 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 (UNOP_CAST); - write_exp_elt ($2); - write_exp_elt (UNOP_CAST); } + { write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_CAST); } ; exp : '(' exp1 ')' @@ -262,154 +268,154 @@ exp : '(' exp1 ')' /* Binary operators in order of decreasing precedence. */ exp : exp '@' exp - { write_exp_elt (BINOP_REPEAT); } + { write_exp_elt_opcode (BINOP_REPEAT); } ; exp : exp '*' exp - { write_exp_elt (BINOP_MUL); } + { write_exp_elt_opcode (BINOP_MUL); } ; exp : exp '/' exp - { write_exp_elt (BINOP_DIV); } + { write_exp_elt_opcode (BINOP_DIV); } ; exp : exp '%' exp - { write_exp_elt (BINOP_REM); } + { write_exp_elt_opcode (BINOP_REM); } ; exp : exp '+' exp - { write_exp_elt (BINOP_ADD); } + { write_exp_elt_opcode (BINOP_ADD); } ; exp : exp '-' exp - { write_exp_elt (BINOP_SUB); } + { write_exp_elt_opcode (BINOP_SUB); } ; exp : exp LSH exp - { write_exp_elt (BINOP_LSH); } + { write_exp_elt_opcode (BINOP_LSH); } ; exp : exp RSH exp - { write_exp_elt (BINOP_RSH); } + { write_exp_elt_opcode (BINOP_RSH); } ; exp : exp EQUAL exp - { write_exp_elt (BINOP_EQUAL); } + { write_exp_elt_opcode (BINOP_EQUAL); } ; exp : exp NOTEQUAL exp - { write_exp_elt (BINOP_NOTEQUAL); } + { write_exp_elt_opcode (BINOP_NOTEQUAL); } ; exp : exp LEQ exp - { write_exp_elt (BINOP_LEQ); } + { write_exp_elt_opcode (BINOP_LEQ); } ; exp : exp GEQ exp - { write_exp_elt (BINOP_GEQ); } + { write_exp_elt_opcode (BINOP_GEQ); } ; exp : exp '<' exp - { write_exp_elt (BINOP_LESS); } + { write_exp_elt_opcode (BINOP_LESS); } ; exp : exp '>' exp - { write_exp_elt (BINOP_GTR); } + { write_exp_elt_opcode (BINOP_GTR); } ; exp : exp '&' exp - { write_exp_elt (BINOP_LOGAND); } + { write_exp_elt_opcode (BINOP_LOGAND); } ; exp : exp '^' exp - { write_exp_elt (BINOP_LOGXOR); } + { write_exp_elt_opcode (BINOP_LOGXOR); } ; exp : exp '|' exp - { write_exp_elt (BINOP_LOGIOR); } + { write_exp_elt_opcode (BINOP_LOGIOR); } ; exp : exp AND exp - { write_exp_elt (BINOP_AND); } + { write_exp_elt_opcode (BINOP_AND); } ; exp : exp OR exp - { write_exp_elt (BINOP_OR); } + { write_exp_elt_opcode (BINOP_OR); } ; exp : exp '?' exp ':' exp - { write_exp_elt (TERNOP_COND); } + { write_exp_elt_opcode (TERNOP_COND); } ; exp : exp '=' exp - { write_exp_elt (BINOP_ASSIGN); } + { write_exp_elt_opcode (BINOP_ASSIGN); } ; exp : exp ASSIGN_MODIFY exp - { write_exp_elt (BINOP_ASSIGN_MODIFY); - write_exp_elt ($2); - write_exp_elt (BINOP_ASSIGN_MODIFY); } + { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode ($2); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); } ; exp : INT - { write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_long); - write_exp_elt ($1); - write_exp_elt (OP_LONG); } + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_long); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_LONG); } ; exp : CHAR - { write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_char); - write_exp_elt ($1); - write_exp_elt (OP_LONG); } + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_LONG); } ; exp : FLOAT - { write_exp_elt (OP_DOUBLE); - write_exp_elt (builtin_type_double); - write_exp_elt2 ($1); - write_exp_elt (OP_DOUBLE); } + { 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 (OP_LAST); - write_exp_elt ($1); - write_exp_elt (OP_LAST); } + { write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_LAST); } ; exp : REGNAME - { write_exp_elt (OP_REGISTER); - write_exp_elt ($1); - write_exp_elt (OP_REGISTER); } + { write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_REGISTER); } ; exp : VARIABLE - { write_exp_elt (OP_INTERNALVAR); - write_exp_elt ($1); - write_exp_elt (OP_INTERNALVAR); } + { write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern ($1); + write_exp_elt_opcode (OP_INTERNALVAR); } ; exp : SIZEOF '(' type ')' - { write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_int); - write_exp_elt ((long) TYPE_LENGTH ($3)); - write_exp_elt (OP_LONG); } + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((long) TYPE_LENGTH ($3)); + write_exp_elt_opcode (OP_LONG); } ; exp : STRING - { write_exp_elt (OP_STRING); + { write_exp_elt_opcode (OP_STRING); write_exp_string ($1); - write_exp_elt (OP_STRING); } + write_exp_elt_opcode (OP_STRING); } ; /* C++. */ exp : THIS - { write_exp_elt (OP_THIS); - write_exp_elt (OP_THIS); } + { write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); } ; /* end of C++. */ @@ -425,7 +431,7 @@ block : name { sym = lookup_symbol (copy_name ($1), expression_context_block, - VAR_NAMESPACE); + VAR_NAMESPACE, 0); if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) $$ = SYMBOL_BLOCK_VALUE (sym); else @@ -436,27 +442,23 @@ block : name ; block : block COLONCOLON name - { - struct symbol *tem - = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE); + { 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); - } + $$ = SYMBOL_BLOCK_VALUE (tem); } ; variable: block COLONCOLON name - { - struct symbol *sym; - sym = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE); + { 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 (OP_VAR_VALUE); - write_exp_elt (sym); - write_exp_elt (OP_VAR_VALUE); - } + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } ; variable: typebase COLONCOLON name @@ -467,10 +469,10 @@ variable: typebase COLONCOLON name error ("`%s' is not defined as an aggregate type.", TYPE_NAME (type)); - write_exp_elt (OP_SCOPE); - write_exp_elt (type); + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); write_exp_string ($3); - write_exp_elt (OP_SCOPE); + write_exp_elt_opcode (OP_SCOPE); } | COLONCOLON name { @@ -478,12 +480,12 @@ variable: typebase COLONCOLON name struct symbol *sym; int i; - sym = lookup_symbol_2 (name, 0, VAR_NAMESPACE); + sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0); if (sym) { - write_exp_elt (OP_VAR_VALUE); - write_exp_elt (sym); - write_exp_elt (OP_VAR_VALUE); + 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++) @@ -492,16 +494,17 @@ variable: typebase COLONCOLON name if (i < misc_function_count) { - write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_int); - write_exp_elt (misc_function_vector[i].address); - write_exp_elt (OP_LONG); - write_exp_elt (UNOP_MEMVAL); - write_exp_elt (builtin_type_char); - write_exp_elt (UNOP_MEMVAL); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst (misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); } else - if (symtab_list == 0) + 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); @@ -510,65 +513,67 @@ variable: typebase COLONCOLON name variable: NAME { struct symbol *sym; - sym = lookup_symbol_1 (copy_name ($1), - expression_context_block, - VAR_NAMESPACE); + int is_a_field_of_this; + + sym = lookup_symbol (copy_name ($1), + expression_context_block, + VAR_NAMESPACE, + &is_a_field_of_this); if (sym) { - write_exp_elt (OP_VAR_VALUE); - write_exp_elt (sym); - write_exp_elt (OP_VAR_VALUE); + 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 + else if (is_a_field_of_this) { - register char *arg = copy_name ($1); - register int i; - int v, val; - /* C++: see if it hangs off of `this'. Must + /* C++: it hangs off of `this'. Must not inadvertently convert from a method call to data ref. */ - v = (int)value_of_this (0); - if (v) - { - val = check_field (v, arg); - if (val) - { - write_exp_elt (OP_THIS); - write_exp_elt (OP_THIS); - write_exp_elt (STRUCTOP_PTR); - write_exp_string ($1); - write_exp_elt (STRUCTOP_PTR); - break; - } - } - sym = lookup_symbol_2 (arg, 0, VAR_NAMESPACE); - if (sym) - { - write_exp_elt (OP_VAR_VALUE); - write_exp_elt (sym); - write_exp_elt (OP_VAR_VALUE); - break; /* YACC-dependent */ - } + 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) { - write_exp_elt (OP_LONG); - write_exp_elt (builtin_type_int); - write_exp_elt (misc_function_vector[i].address); - write_exp_elt (OP_LONG); - write_exp_elt (UNOP_MEMVAL); - write_exp_elt (builtin_type_char); - write_exp_elt (UNOP_MEMVAL); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst (misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + 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 - if (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)); + error ("No symbol \"%s\" in current context.", + copy_name ($1)); } } ; @@ -583,9 +588,9 @@ type : typebase | type '(' typebase COLONCOLON '*' ')' { $$ = lookup_member_type ($1, $3); } | type '(' typebase COLONCOLON '*' ')' '(' ')' - { $$ = lookup_member_type (lookup_function_type ($1, 0), $3); } + { $$ = lookup_member_type (lookup_function_type ($1)); } | type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')' - { $$ = lookup_member_type (lookup_function_type ($1, $8), $3); + { $$ = lookup_member_type (lookup_function_type ($1)); free ($8); } ; @@ -672,16 +677,13 @@ free_funcalls () /* Add one element to the end of the expression. */ -/* To avoid a bug in the Sun 4 compiler, we pass only things that - can fit into a single register through here. */ +/* 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; */ - long expelt; + union exp_element expelt; { - union exp_element temp; - temp.longconst = expelt; - if (expout_ptr >= expout_size) { expout_size *= 2; @@ -689,25 +691,73 @@ write_exp_elt (expelt) sizeof (struct expression) + expout_size * sizeof (union exp_element)); } - expout->elts[expout_ptr++] = /* expelt */ temp; + 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); } -/* Things that take more space must come through here. */ static void -write_exp_elt2 (expelt) +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 temp; - temp.doubleconst = expelt; + union exp_element tmp; - 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++] = temp; + 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. @@ -726,13 +776,13 @@ write_exp_string (str) 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)); + 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 (len); + write_exp_elt_longcst (len); } /* During parsing of a C expression, the pointer to the next character @@ -799,12 +849,13 @@ parse_number (olen) while (len-- > 0) { c = *p++; - n *= base; + if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + if (c != 'l') + n *= base; if (c >= '0' && c <= '9') n += c - '0'; else { - if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; if (base == 16 && c >= 'a' && c <= 'f') n += c - 'a' + 10; else if (len == 0 && c == 'l') @@ -861,6 +912,29 @@ static struct token tokentab2[] = {">=", 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 @@ -1044,7 +1118,7 @@ yylex () /* Handle tokens that refer to machine registers: $ followed by a register name. */ - if (*tokstart == '$') + if (*tokstart == '$') { for (c = 0; c < NUM_REGS; c++) if (namelen - 1 == strlen (reg_names[c]) && !strncmp (tokstart + 1, reg_names[c], namelen - 1)) @@ -1052,7 +1126,14 @@ yylex () 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; + } + } if (namelen == 6 && !strncmp (tokstart, "struct", 6)) { return STRUCT; @@ -1070,10 +1151,10 @@ yylex () { return ENUM; } - if (!strncmp (tokstart, "this", 4)) - { - return THIS; - } + if (!strncmp (tokstart, "this", 4) + && lookup_symbol ("$this", expression_context_block, + VAR_NAMESPACE, 0)) + return THIS; } if (namelen == 6 && !strncmp (tokstart, "sizeof", 6)) { @@ -1102,7 +1183,7 @@ yylex () return NAME; } -static +static void yyerror () { error ("Invalid syntax in expression."); @@ -1361,6 +1442,8 @@ parse_c_1 (stringptr, block, comma) lexptr = *stringptr; + paren_depth = 0; + comma_terminates = comma; if (lexptr == 0 || *lexptr == 0) @@ -1374,8 +1457,9 @@ parse_c_1 (stringptr, block, comma) 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)); + expout = (struct expression *) + xmalloc (sizeof (struct expression) + + expout_size * sizeof (union exp_element)); make_cleanup (free_current_contents, &expout); if (yyparse ()) yyerror (); diff --git a/gdb/expression.h b/gdb/expression.h index 0fac7be..ade7adb 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -175,7 +175,7 @@ union exp_element { enum exp_opcode opcode; struct symbol *symbol; - long longconst; + LONGEST longconst; double doubleconst; char string; struct type *type; diff --git a/gdb/findvar.c b/gdb/findvar.c index d7ccdc4..0bfd1d8 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -19,7 +19,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "frame.h" @@ -27,34 +26,56 @@ anyone else from sharing it farther. Help stamp out software hoarding! CORE_ADDR read_register (); -START_FILE - /* 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. */ -static CORE_ADDR +CORE_ADDR find_saved_register (frame, regnum) FRAME frame; int regnum; { - struct frame_info fi; + 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 dissapears 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. */ + + if (REGISTER_IN_WINDOW_P(regnum)) + { + fi = get_frame_info (frame); + 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; - fi = get_prev_frame_info (frame1); - if (fi.frame == 0 || fi.frame == frame) + frame1 = get_prev_frame (frame1); + if (frame1 == 0 || frame1 == frame) break; - get_frame_saved_regs (&fi, &saved_regs); + fi = get_frame_info (frame1); + get_frame_saved_regs (fi, &saved_regs); if (saved_regs.regs[regnum]) addr = saved_regs.regs[regnum]; - frame1 = fi.frame; } return addr; @@ -73,7 +94,7 @@ read_relative_register_raw_bytes (regnum, myaddr) if (regnum == FP_REGNUM) { - bcopy (&selected_frame, myaddr, sizeof (CORE_ADDR)); + bcopy (&FRAME_FP(selected_frame), myaddr, sizeof (CORE_ADDR)); return; } @@ -102,15 +123,19 @@ value value_of_register (regnum) int regnum; { - register CORE_ADDR addr = find_saved_register (selected_frame, 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, addr); + return value_from_long (builtin_type_int, (LONGEST) addr); read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum)); } else @@ -137,6 +162,7 @@ char registers[REGISTER_BYTES]; starting with the REGBYTE'th byte of register data into memory at MYADDR. */ +void read_register_bytes (regbyte, myaddr, len) int regbyte; char *myaddr; @@ -148,6 +174,7 @@ read_register_bytes (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; @@ -211,7 +238,7 @@ read_var_value (var, frame) { register value v; - struct frame_info fi; + struct frame_info *fi; struct type *type = SYMBOL_TYPE (var); register CORE_ADDR addr = 0; @@ -260,84 +287,178 @@ read_var_value (var, frame) case LOC_REGISTER: case LOC_REGPARM: - { - char raw_buffer[MAX_REGISTER_RAW_SIZE]; - char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; - - VALUE_REGNO (v) = val; - - /* Locate the register's contents in a real register or in core; - read the data in raw format. */ - - addr = find_saved_register (frame, val); - if (addr == 0) - { - /* Value is really in a register. */ - - VALUE_LVAL (v) = lval_register; - VALUE_ADDRESS (v) = REGISTER_BYTE (val); - - read_register_bytes (REGISTER_BYTE (val), - raw_buffer, REGISTER_RAW_SIZE (val)); - } - else - { - /* Value was in a register that has been saved in memory. */ - - read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (val)); - VALUE_ADDRESS (v) = addr; - } - - /* Convert the raw contents to virtual contents. - (Just copy them if the formats are the same.) */ - - REGISTER_CONVERT_TO_VIRTUAL (val, raw_buffer, virtual_buffer); - - if (REGISTER_CONVERTIBLE (val)) - { - /* 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 (val)) - { - /* 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 (val)); - 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. */ - - union { int i; char c; } test; - /* If we want less than the full size, we need to - test for a big-endian or little-endian machine. */ - test.i = 1; - if (test.c != 1 && len < REGISTER_RAW_SIZE (val)) - { - /* Big-endian, and we want less than full size. */ - VALUE_OFFSET (v) = REGISTER_RAW_SIZE (val) - len; - } - - bcopy (virtual_buffer + VALUE_OFFSET (v), - VALUE_CONTENTS (v), len); - } - - return v; - } + v = value_from_register (type, val, frame); + 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 address, @@ -350,7 +471,7 @@ locate_var_value (var, frame) { register CORE_ADDR addr = 0; int val = SYMBOL_VALUE (var); - struct frame_info fi; + struct frame_info *fi; struct type *type = SYMBOL_TYPE (var); if (frame == 0) frame = selected_frame; @@ -367,14 +488,12 @@ locate_var_value (var, frame) addr = find_saved_register (frame, val); if (addr != 0) { - union { int i; char c; } test; int len = TYPE_LENGTH (type); - /* If var is less than the full size of register, we need to - test for a big-endian or little-endian machine. */ - test.i = 1; - if (test.c != 1 && len < REGISTER_RAW_SIZE (val)) +#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.", @@ -405,11 +524,6 @@ locate_var_value (var, frame) } return value_cast (lookup_pointer_type (type), - value_from_long (builtin_type_long, addr)); + value_from_long (builtin_type_long, (LONGEST) addr)); } -static -initialize () -{} - -END_FILE diff --git a/gdb/frame.h b/gdb/frame.h index acaea8ff2..bd5ce5d 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -20,22 +20,62 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* Note that frame.h requires param.h! */ -#define FRAME CORE_ADDR - +/* + * 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 frame; + 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. */ - FRAME next_frame; - - /* The frame called by `next_frame', or 0 if there is none - (or `next_frame' is 0). */ - FRAME next_next_frame; + /* 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. */ @@ -52,13 +92,14 @@ struct frame_saved_regs extern FRAME selected_frame; -extern struct frame_info get_frame_info (); -extern struct frame_info get_prev_frame_info (); +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 struct block *get_frame_block (); @@ -66,3 +107,7 @@ 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 (); + diff --git a/gdb/gdb.1 b/gdb/gdb.1 deleted file mode 100644 index 11a42a6..0000000 --- a/gdb/gdb.1 +++ /dev/null @@ -1,91 +0,0 @@ -.TH GDB 1 "13 April 1987" -.UC 4 -.SH NAME -gdb \- Project GNU's DeBugger -.SH SYNOPSIS -\fBgdb\fP [ \fBoptions\fP ] See documentation mentioned below. -.SH DESCRIPTION -\fIgdb\fP is a source level symbolic debugger for C programs, created by -Richard M. Stallman (rms) for the GNU Project, and distributed by the -Free Software Foundation. Eventually GNU (Gnu's Not Unix) will be a -complete replacement for Berkeley Unix, all of which everyone will be -able to use freely. See the \fIGNU Emacs\fP man page for pointers to more -information. -.PP -\fIgdb\fP has something of the flavor of \fIdbx\fP, -but has more features and power. It can also be used to debug o/s -kernels, but needs to be configured differently for that task. -.PP -Project GNU isn't using Unix man pages. Its style of complete -documentation can be found by: -.PP -The help and info commands inside \fIgdb\fP. -.PP -In the Info system in \fIGNU Emacs\fP. Type C-h i, and follow the -directions. This is equivalent to the reference manual for -\fIgdb\fP, and has about 55 pages of text. -.PP -\fIgdb\fP could be extended to work with other languages (e.g. Pascal) and -machines (e.g. encores). If you like, copy the sources and give it a -try. When you have it working send \fIdiff -c\fP's of the changed files to -bug-gdb@prep.ai.mit.edu (fuller details below), so they can benefit everyone. -.SH DISTRIBUTION -\fIgdb\fP is free; anyone may redistribute copies of -\fIgdb\fP to anyone under the terms stated in the -\fIgdb\fP General Public License, a copy of which accompanies each copy of -\fIgdb\fP, is readable with the info command inside \fIgdb\fP, -and which also appears in the \fIgdb\fP reference manual. -.PP -Copies of \fIgdb\fP may sometimes be received packaged with -distributions of Unix systems, but it is never included in the scope -of any license covering those systems. Such inclusion would violate -the terms on which distribution is permitted. In fact, the primary -purpose of the General Public License is to prohibit anyone from -attaching any other restrictions to redistribution of \fIgdb\fP. -.PP -You can order printed copies of the \fIgdb\fP reference manual for $10.00/copy -postpaid from the Free Software Foundation, which develops GNU software -(contact them for quantity prices on the manual). Their address is: -.nf - Free Software Foundation - 1000 Mass Ave. - Cambridge, MA 02138 -.fi -As with all software and publications from FSF, everyone is permitted to -make and distribute copies of the \fIgdb\fP reference manual. -The TeX source to the \fIgdb\fP reference -manual is also included in the \fIGNU Emacs\fP source distribution. -.PP -.SH OPTIONS -See documentation. -.SH EXAMPLES -See documentation. -.SH "SEE ALSO" -adb(1), sdb(1), dbx(1) -.SH BUGS -There is a mailing list, bug-gdb@prep.ai.mit.edu on the internet -(ucbvax!prep.ai.mit.edu!bug-gdb on UUCPnet), for reporting \fIgdb\fP -bugs and fixes. But before reporting something as a bug, please try -to be sure that it really is a bug, not a misunderstanding or a -deliberate feature. We ask you to read the section ``Reporting Emacs -Bugs'' near the end of the \fIGNU Emacs\fP reference manual -(or Info system) for hints -on how and when to report bugs. Also, include the version number of -the \fIgdb\fP you are running in \fIevery\fR bug report that you send in. -.PP -Do not expect a personal answer to a bug report. The purpose of reporting -bugs is to get them fixed for everyone in the next release, if possible. -For personal assistance, look in the SERVICE file -(see the \fIGNU Emacs\fP man page) for -a list of people who offer it. -.PP -Please do not send anything but bug reports to this mailing list. -Send other stuff to gnu@prep.ai.mit.edu (or the -corresponding UUCP address). For more information about GNU mailing -lists, see the file MAILINGLISTS (see the \fIGNU Emacs\fP man page). Bugs tend -actually to be fixed if they can be isolated, so it is in your -interest to report them in such a way that they can be easily -reproduced. -.PP -No bugs are known at this time. - diff --git a/gdb/gdb.ideas b/gdb/gdb.ideas deleted file mode 100644 index 1b3b12f..0000000 --- a/gdb/gdb.ideas +++ /dev/null @@ -1,1034 +0,0 @@ -BABYL OPTIONS: -Version: 5 -Labels: -Note: This is the header of an rmail file. -Note: If you are seeing it in rmail, -Note: it means the file has no messages in it. - -From: mly@MICHAEL.AI.MIT.EDU (Richard Mlynarik) -To: rms@prep.ai.mit.edu -Subject: gdb suggestions (from hpux cdb) -Reply-To: mly-prep@prep.ai.mit.edu - -"find-bug" command says "I can see the problem, but it will do you -good to find it yourself" - -The gdb manual should explicitly state that gdb has no control over -forked (or execed or whatever) subprocesses. - -I'd still like it if "delete" said what it had done. - - -Date: Tuesday, 13 May 1986, 00:40-EDT -From: -Sender: JC@LMI-ANGEL -Subject: interesting sdb features -To: rms@angel - -output format p = pointer to procedure. - -foo/x or foo/4x uses size of foo as size to print. - -foo[1;4] to get elements 1 thru 4. - -Continue to specified line number. - -Interactively delete all breakpoints (asking about each one). - - - -Command to write backtrace into a file, or even better to duplicate all -output to a file. This could work by playing with descriptor 1, -making it a pipe to `tee'. The original descriptor 1 is saved and -this mode can be turned off by putting it back. - Date: Wed, 18 Feb 87 15:37:14 EST - From: rms (Richard M. Stallman) - Message-Id: <8702182037.AA16492@prep.ai.mit.edu> - To: mly-prep@prep.ai.mit.edu - In-Reply-To: <8702181913.AA16118@prep.ai.mit.edu> - Subject: gdb "photo" command - - I don't think all this is worth the trouble to do now, - because the right way to do it on TRIX is totally different - and much easier. - - -Commands to enable and disable the autodisplays. Associate -autodisplays with breakpoints perhaps, so they only display -at those breakpoints; this is easier than using breakpoint commands. - -Remember how each breakpoint's position was specified. -Have command to reread symbol table and respecify each -breakpoint using same args (line number or function name) as before. - -Have way to proceed process in background so that can then suspend -gdb but have subprocess continue - - -Date: Fri, 24 Jul 87 21:30:25 EDT -From: phr@PREP.AI.MIT.EDU (Paul Rubin) -To: bug-gdb@PREP.AI.MIT.EDU - -After rereading the symbol table when user runs the "symbol-file" -command, when GDB notices that some of the source files are newer -it should reload them rather than just printing a message saying -they are newer. - - - -Message-Id: <8704171941.AA05045@orville.arpa> -To: mly@prep.ai.mit.edu -Cc: raible@orville.arpa, fouts@orville.arpa, creon@orville.arpa -Subject: gdb hack/questions, etc -Date: 17 Apr 87 11:41:42 PST (Fri) -From: raible@orville.arpa - - -A couple of things: - -1) Will gdb ever get dbx-sytly tracing? Wouldn't it be fairly easy to add? - -2) How about an xemacs gdb mode which has various windows, perhaps using - terminal.el for generality? - -3) Any word about that stupid IRIS SIGIOT problem? Do you know of anyone - else who has gotten IRIS subprocesses to work more reliably? - -4) Below is a hack adapted from ramsdell@linus.uucp which can be pretty - useful in gdb. Instead of using gdb to patch extensive changes to a - particular function, you can do the following (assuming the 50 lines - of code below is part of your executable): - 1) create a new file (foo.c) containing the new function - 2) run cc -c foo.c - 3) in gdb, and patch in the new function as follows: - -(gdb) info breakpoints -/* Load in the new object code... */ -#1 y 0x00000125 in main (dyn.c line 46) - break only if $function = funload ("foo"), 1 - silent - echo new code for func ($function) initialized\n - cont - -/* ...and use it instead of the old code. */ -#2 y 0x000001c2 in func (dyn.c line 59) - break only if $ret = $function (a), 1 - silent - set a = $ret - j 60 /* func has a return on line 60 */ - - This is more complicated than it has to be because of 2 bugs in v2.1: - 1) function calls in a breakpoint command list seem to abort - the execution of the rest of the command list. This is - why all function calls are in the conditional part. - (gdb reference manual section 5.5). - - 2) A 'return' in a command list also aborts the execution, and - in addition, prompts you for a y/n. - (gdb reference manual section 11.1). - - On the other hand, after doing 'cc -c foo.c' (which is pretty fast), - you can simply rerun your program to check out the changes. - This can be a big win! - -The code for this is included below (compile with cc -g): -======================================================== - -#include -#include - -typedef int (*intfun)(); -char *myname; - -intfun funload (filename) /* Dynamically load 1st function from a .o */ - char *filename; -{ - int fd, size; - struct exec hdr; - char buf[100]; - intfun fun; - - /* -A => incremental loading - use dyn as the base symbol table - -T => set the text segment origin to the following hex address - -N => magic number 407 (text not read-only) - */ - sprintf (buf, "ld -A %s -T %x -N %s.o -o %s -lc", - myname, sbrk (0), filename, filename); - - /* NOTE: if anything mallocs space between here and below, this will fail */ - system (buf); - - fd = open (filename, 0); - read (fd, &hdr, sizeof(hdr)); - size = hdr.a_text + hdr.a_data + hdr.a_bss; - - if ((fun = (intfun) sbrk (size)) < 0) - printf ("Couldn't find the space"), exit(); - - read (fd, fun, size); /* Load code. */ - /* NOTE: if anything mallocs space between here and above, this will fail */ - - close (fd); - return ((intfun) fun); -} - -main (argc, argv) - char **argv; -{ - intfun fun1, fun2; - - myname = *argv; - - fun1 = funload("fun1"); - printf ("The answer is %d.\n", (*fun1)(11) ); - - fun2 = funload("fun2"); - printf ("The answer is %d.\n", (*fun2)() ); -} -1,edited,, -Received: by PREP.AI.MIT.EDU; Tue, 16 Jun 87 03:12:54 EDT -Date: Tue, 16 Jun 87 03:12:54 EDT -From: rms (Richard M. Stallman) -Message-Id: <8706160712.AA07910@prep.ai.mit.edu> -To: rms -Subject: GDB ideas - -*** EOOH *** -Date: Tue, 16 Jun 87 03:12:54 EDT -From: rms (Richard M. Stallman) -To: rms -Subject: GDB ideas - -* Within a user-defined command, have local convenience variables, -local functions, local defined commands. - -** Optionally echo commands within a user-defined command. - -** Optionally record all user-typed commands in a log file. -Optionally record GDB output there too, marked as output so it -will not be executed if replayed. - -* Execution commands - -** Step until next branch, or next call. -(finish is step until next return). - -step branch -or should it be -continue branch - -** Stop on any branch, call or return -affecting ordinary step and continue commands. - -stop branch - -** Trace all branches, calls, returns. -This could be done by stopping on those events -and having a continue command to be executed after. - -stop branch -commands branch -continue -end - -** Commands to continue or step without any display after stop. -These may be useful in user-defined commands. - -Have one prefix command that does this, modifying whatever other -command you might use. For example, - -silent step 5 -silent cont - -** Clear all breakpoint ignore-counts when inferior exits or is killed. - -** Trace changes to a location (watchpoint). -Enable and disable them. - -** Info command to show command-line for running the program. - -* Auto-display - -** Enable and disable display expressions. -Allow syntax 1d, 2d, etc. in enable, disable and delete commands. -Then there is no more need for an undisplay command. - -** Displaying an auto variable should not do it in the wrong stack frame. -Either it should search for the proper stack frame to apply to -or it should deactivate itself when in the wrong frame. - -* Printing - -** Print an address as +offset. - -** Abbreviate initial whitespace modulo 16. - -** p/x of an array should print each element with /x. - -** Change the stack scan so that it has a more general idea -of what info is needed to describe a frame fully. - -* Expressions - -** Array slices. Can replace @. - -** %name for use of symbol names containing funny characters. - -** User-defined convenience functions that can appear in expressions. - -** Expression syntax to convert line number to address. - -** Expression syntax to specify a name scope with an address, line number -or frame number. - -Use the line number by itself, or an address with *, just as in b or l cmd: -38:foo or *0x40a:foo. No good; the latter would be parsed as -*(0x40a:foo). - -** Expression syntax to convert a frame number to its pc. -Perhaps unary %. - -* Possible bugs - -** Does set $pc= cause the current scope to be recalculated? -It should. - -1,, -Received: by PREP.AI.MIT.EDU; Wed, 17 Jun 87 09:59:37 EDT -From: phr@ATHENA.MIT.EDU -Received: by ATHENA (5.45/4.7) - id AA09084; Wed, 17 Jun 87 08:54:36 EDT -Received: by ORPHEUS.MIT.EDU (5.45/4.7) id AA02565; Wed, 17 Jun 87 08:54:29 EDT -Date: Wed, 17 Jun 87 08:54:29 EDT -Message-Id: <8706171254.AA02565@ORPHEUS.MIT.EDU> -To: rms@prep.ai.mit.edu -Subject: gdb suggestion -Status: RO - -*** EOOH *** -From: phr@ATHENA.MIT.EDU -Date: Wed, 17 Jun 87 08:54:29 EDT -To: rms@prep.ai.mit.edu -Subject: gdb suggestion - -Completion of file and function names; e.g. typing - break XWriteBi -prints - No such symbol: XWriteBi. - Setting default command to "break XWriteBitmapFile" -so you can set a break at XWriteBitmapFile by hitting return a second -time. Other interfaces ("complete to XWriteBitmapFile? (y/n)") -are also possible. - - -1,edited,, -Received: by PREP.AI.MIT.EDU; Wed, 24 Sep 86 16:33:11 EDT -Date: Wed, 24 Sep 86 16:33:11 EDT -From: mly (Richard Mlynarik) -Message-Id: <8609242033.AA11520@prep.ai.mit.edu> -To: rms -Cc: mly-prep -Subject: gdb gripes/suggestions/requests - -*** EOOH *** -Date: Wed, 24 Sep 86 16:33:11 EDT -From: mly (Richard Mlynarik) -To: rms -Cc: mly-prep -Subject: gdb gripes/suggestions/requests - -If would be really nice to have some way to do conditionals in user - commands -- though this is really stretching the functionality of - gdb a little too much, perhaps. (see ~mly/e/.gdbint for some of - the contortions I go through with || to get conditional - evaluation...) - -A -real- win wuold be some way to execute until he next function-call - (like c-d in the cadr debugger) This would even be useful if it - were rather slow -- it would probably be faster than setting - temporary breakpoints in all the functions which might be called, - and would certainly be faster than "step"ping one's way until a - funcall happened. - -"info source" should mention what the directory search-path is (ie - what "info dir" says) and in which directory it found each of the - source files (and which source files it cannot locate in the - search-path) - - -1,, -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA22869; Thu, 22 Oct 87 09:50:30 PDT -Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Thu, 22 Oct 87 12:17:59 EDT -Received: by PREP.AI.MIT.EDU; Thu, 22 Oct 87 12:21:00 EDT -Received: from pp.mcc.com by MCC.COM with TCP; Thu 22 Oct 87 10:54:41-CDT -Posted-Date: Thu, 22 Oct 87 10:55:13 CDT -Received: from big-d.aca.mcc.com by pp.mcc.com (4.12/KA70822) - id AA16571; Thu, 22 Oct 87 10:55:19 cdt -Return-Path: -Received: by big-d.aca.mcc.com (3.2/KA70106) - id AA04247; Thu, 22 Oct 87 10:55:13 CDT -Date: Thu, 22 Oct 87 10:55:13 CDT -From: tiemann%pp.mcc.com@mcc.com (Michael Tiemann) -Message-Id: <8710221555.AA04247@big-d.aca.mcc.com> -To: bug-gdb@prep.ai.mit.edu -Subject: expanding file names - -*** EOOH *** -Posted-Date: Thu, 22 Oct 87 10:55:13 CDT -Return-Path: -Date: Thu, 22 Oct 87 10:55:13 CDT -From: tiemann%pp.mcc.com@mcc.com (Michael Tiemann) -To: bug-gdb@prep.ai.mit.edu -Subject: expanding file names - -When running a program, gdb thoughtfully passes the argument list -through the shell, expanding files and environment variables as -needed. It would be nice if the same facility were added to the -command which adds directories to search paths. For example, it would -be nice to say "dir ~/foo" . - -Michael - - -1,, -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA25075; Fri, 23 Oct 87 10:42:52 PDT -Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Fri, 23 Oct 87 13:39:37 EDT -Received: by PREP.AI.MIT.EDU; Fri, 23 Oct 87 13:42:53 EDT -Received: from relay2.cs.net by RELAY.CS.NET id ac11193; 23 Oct 87 13:03 EDT -Received: from umb.edu by RELAY.CS.NET id ac05949; 23 Oct 87 13:01 EDT -Received: by umb.umb.edu; Fri, 23 Oct 87 10:18:40 EDT -Received: by ileaf.uucp (1.1/SMI-3.0DEV3) - id AA00599; Wed, 21 Oct 87 10:56:52 EDT -Received: from marvin.io.uucp by io.uucp (1.1/SMI-3.0DEV3) - id AA01359; Wed, 21 Oct 87 10:58:45 EDT -Received: by marvin.io.uucp (3.2/SMI-3.2) - id AA00334; Wed, 21 Oct 87 11:02:20 EDT -Date: Wed, 21 Oct 87 11:02:20 EDT -From: Mark Dionne -Message-Id: <8710211502.AA00334@marvin.io.uucp> -To: ileaf!umb!bug-gdb@prep.ai.mit.edu -Subject: gdb bug - -*** EOOH *** -Date: Wed, 21 Oct 87 11:02:20 EDT -From: Mark Dionne -To: ileaf!umb!bug-gdb@prep.ai.mit.edu -Subject: gdb bug - -The /FMT and @ options of the "print" command seem to interact -in GDB 2.1. For example: - -(gdb) p ($cmpn.buf[-1])@($cmpn.gapb - $cmpn.buf + 1) -$17 = {-16383, -24285, 55, 27944, -24285, -24285, 55, 28010, -24285, --24285, 55, 28076, -24285, -24285, 55, 28142, -24285} -(gdb) p/x ($cmpn.buf[-1])@($cmpn.gapb - $cmpn.buf + 1) -$18 = 0xc001 - -I guess I see what's happening: the /x is applying to the whole -array rather than to the individual elements. Feature or bug? - - ...!harvard!umb!ileaf!md Mark Dionne, Interleaf - ...!sun!sunne!ileaf!md Ten Canal Park, Cambridge, MA 02141 - (617) 577-9813 x5551 - - - -1,, -Received: by PREP.AI.MIT.EDU; Sun, 6 Sep 87 14:27:19 EDT -Message-Id: <8709061827.AA18170@prep.ai.mit.edu> -Received: from relay2.cs.net by RELAY.CS.NET id af03990; 6 Sep 87 14:22 EDT -Received: from umb.edu by RELAY.CS.NET id ab03029; 6 Sep 87 14:16 EDT -Received: by umb.umb.edu; Sun, 6 Sep 87 12:10:34 EDT -Date: Sun, 6 Sep 87 12:10:34 EDT -Received: by typo.umb.edu; Sun, 6 Sep 87 12:04:21 EDT -From: Robert Morris -To: bug-gdb@PREP.AI.MIT.EDU -Subject: convenient script - -*** EOOH *** -Date: Sun, 6 Sep 87 12:10:34 EDT -From: Robert Morris -To: bug-gdb@PREP.AI.MIT.EDU -Subject: convenient script - -I find it easier to maintain binaries on our heterogenous -network if I keep this trivial script in gdb source directory. Use it -if you want. - - ------------- - -#! /bin/csh -f -# SETUP -# setup gdb files for presently known machines -# ram@umb.edu -# (ram%umb.edu@relay.cs.net if you have an incomplete mailer) -# or ...!harvard!umb!ram -# -# e.g. SETUP sun3 -# note that sunX means major release X of sun software, generally -# sun3 at this writing (gnu 18.41) -# -# note GDB with gnuemacs 18.41 is already configured for vaxen - -# Bob Morris, UMASS-Boston 9/6/87 -switch ($1) - case "sun2": - ; - case "sun3" : - set cputype="m68k"; - set inittype="suninit"; - breaksw; - default : - set cputype=$1; - set inittype=$1init; - breaksw; -endsw -echo \#include \"m-$1.h\" > param.h -echo \#include \"$cputype-pinsn.c\" > pinsn.c -ed initialize.h <& /dev/null -/init.h/ -c -#include "m-$inittype.h" -. -w -q -! - - - - -1,answered,, -Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Sat, 19 Dec 87 18:18:50 EST -Received: by PREP.AI.MIT.EDU; Sat, 19 Dec 87 18:24:38 EST -Received: from big-d.aca.mcc.com by MCC.COM with TCP; Sat 19 Dec 87 17:19:48-CST -Date: Sat, 19 Dec 87 17:19:41 CST -From: tiemann@mcc.com (Michael Tiemann) -Posted-Date: Sat, 19 Dec 87 17:19:41 CST -Message-Id: <8712192319.AA26775@big-d.aca.mcc.com> -Received: by big-d.aca.mcc.com (3.2/ACA-V2.1) - id AA26775; Sat, 19 Dec 87 17:19:41 CST -To: rms@prep.ai.mit.edu -Subject: gdb - -*** EOOH *** -Date: Sat, 19 Dec 87 17:19:41 CST -From: tiemann@mcc.com (Michael Tiemann) -Posted-Date: Sat, 19 Dec 87 17:19:41 CST -To: rms@prep.ai.mit.edu -Subject: gdb - -file values.c, function unpack_field_as_long: - - val &= (1 << bitsize) - 1; - -This is not as machine independent as it could be. If you feel like -fixing this potential problem, there are many other instances to worry -about. - -Michael - - -1,, -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA04771; Thu, 20 Aug 87 22:33:25 PDT -Received: from [128.52.22.14] by ucbvax.Berkeley.EDU (5.58/1.27) - id AA07119; Thu, 20 Aug 87 00:37:04 PDT -Received: by PREP.AI.MIT.EDU; Thu, 20 Aug 87 03:37:35 EDT -Date: Thu, 20 Aug 87 03:37:35 EDT -From: rms@prep.ai.mit.edu (Richard M. Stallman) -Message-Id: <8708200737.AA15589@prep.ai.mit.edu> -To: rms@prep.ai.mit.edu -Subject: GDB changes for next version - -*** EOOH *** -Date: Thu, 20 Aug 87 03:37:35 EDT -From: rms@prep.ai.mit.edu (Richard M. Stallman) -To: rms@prep.ai.mit.edu -Subject: GDB changes for next version - -1. Use links, rather than editing some files, to configure it. - -2. Can misc functions eval as their addresses rather than as - a char in that address? Is this reasonable in all cases - given that non-functions cannot be distinguished - and that you might use the result in various ways (arithmetic, etc.). - - -1,, -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA09136; Sat, 29 Aug 87 02:20:15 PDT -Received: from PREP.AI.MIT.EDU by ucbvax.Berkeley.EDU (5.58/1.27) - id AA26072; Sat, 29 Aug 87 02:21:51 PDT -Received: by PREP.AI.MIT.EDU; Sat, 29 Aug 87 05:22:30 EDT -Received: by RUTGERS.EDU (5.54/1.14) with UUCP - id AA22247; Sat, 29 Aug 87 05:21:13 EDT -Received: from sequent.UUCP by spool.wisc.edu; Sat, 29 Aug 87 04:18:41 CDT -Received: from reed.UUCP by ogcvax.OGC.EDU (5.51/OGC_4.8) - id AA08044; Fri, 28 Aug 87 20:06:41 PDT -Received: by reed.UUCP (5.51/5.17) - id AA05059; Fri, 28 Aug 87 19:19:15 PDT -From: uwvax!sequent!ogcvax!reed!keith@rutgers.edu (Keith Packard) -Message-Id: <8708290219.AA05059@reed.UUCP> -To: rms@prep.ai.mit.edu -Subject: Re: GDB -In-Reply-To: Your message of Thu, 20 Aug 87 03:39:37 EDT. - <8708200735.AA26546@EDDIE.MIT.EDU> -Date: Fri, 28 Aug 87 19:19:13 PDT - -*** EOOH *** -From: uwvax!sequent!ogcvax!reed!keith@rutgers.edu (Keith Packard) -To: rms@prep.ai.mit.edu -Subject: Re: GDB -In-Reply-To: Your message of Thu, 20 Aug 87 03:39:37 EDT. - <8708200735.AA26546@EDDIE.MIT.EDU> -Date: Fri, 28 Aug 87 19:19:13 PDT - - -Here is a simple test program for exibiting the trouble with signals: - ------ -# include - -main () -{ - int handle (); - int i; - signal (SIGALRM, handle); - alarm (5); - for (i = 0; i < 100000; i++) - printf ("%d\n", i); -} - -handle () -{ - printf ("signal!\n"); - alarm (5); -} ------ - -To demonstrate the problem, simply place a breakpoint before the call to -alarm and then start stepping through the program: - -(gdb) break 7 -(gdb) step -... -... - -Eventually, the alarm call occurs and the program ends up in some -signal handling code -- unfortuantely a machine dependent location. At this -point, because the fp has moved out of the current function (in fact on -many machines the frame is not in a consistent state at this point) gdb -assumes that a new function has started and suspends execution with another -prompt. - -A reasonable solution would be to have gdb insert a breakpoint at the -expected signal return address and continue to that breakpoint -- I've -implemented this and found that it works. There is, however, one nasty -problem -- longjmp around the suspended frame and the breakpoint is not hit -at the expected time. - -Have fun... - -keith packard - -tektronix!reed!keith - - -1,, -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA09143; Sat, 29 Aug 87 02:24:58 PDT -Received: by neptune.Berkeley.EDU (5.57/1.25) - id AA03738; Sat, 29 Aug 87 02:24:50 PDT -Date: Sat, 29 Aug 87 02:24:50 PDT -From: rms@neptune.berkeley.edu (Richard Stallman) -Message-Id: <8708290924.AA03738@neptune.Berkeley.EDU> -To: rms@neptune.Berkeley.EDU -Subject: GDB bug -Reply-To: rms@prep.ai.mit.edu - -*** EOOH *** -Date: Sat, 29 Aug 87 02:24:50 PDT -From: rms@neptune.berkeley.edu (Richard Stallman) -To: rms@neptune.Berkeley.EDU -Subject: GDB bug -Reply-To: rms@prep.ai.mit.edu - -Is there any way to make GDB, when stepping across a function call, -notice any attempt to longjump out of that call? -Perhaps an implicit breakpoint at longjump. -If longjump is called, find the pc in the jmp_buf and put -a self-deleting breakpoint there. - - -1,, -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA07976; Fri, 28 Aug 87 09:26:12 PDT -Received: from PREP.AI.MIT.EDU by ucbvax.Berkeley.EDU (5.58/1.27) - id AA03230; Fri, 28 Aug 87 09:28:04 PDT -Received: by PREP.AI.MIT.EDU; Fri, 28 Aug 87 12:28:43 EDT -Date: Fri, 28 Aug 87 12:28:43 EDT -From: phr@prep.ai.mit.edu (Paul Rubin) -Message-Id: <8708281628.AA09926@prep.ai.mit.edu> -To: rms@prep.ai.mit.edu -Subject: gdb suggestions - -*** EOOH *** -Date: Fri, 28 Aug 87 12:28:43 EDT -From: phr@prep.ai.mit.edu (Paul Rubin) -To: rms@prep.ai.mit.edu -Subject: gdb suggestions - -1. I wish gdb had a command to re-read the sources so that I can edit -the program and recompile it without having to kill and restart gdb. - -2. Would be nice if gdb could somehow connect the subprocess's tty channels -to a pty, so I can run gdb in an X window and the subprocess in a different -(xterm) window. - -This might need hair to detect if the subprocess is running when you try -to examine variables, etc. and stop the subproc or report an error if it is. - - -1,, -Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Mon, 4 Apr 88 12:43:31 EDT -Received: from CCA.CCA.COM by prep.ai.mit.edu; Mon, 4 Apr 88 11:30:55 EST -Received: by CCA.CCA.COM; Mon, 4 Apr 88 12:42:16 EDT -Date: Mon, 4 Apr 88 12:42:16 EDT -From: alex@cca.cca.com (Alexis Layton) -Message-Id: <8804041642.AA28917@CCA.CCA.COM> -To: rms@prep.ai.mit.edu -Subject: Wish List for GDB -Cc: tiemann@mcc.com - -*** EOOH *** -Date: Mon, 4 Apr 88 12:42:16 EDT -From: alex@cca.cca.com (Alexis Layton) -To: rms@prep.ai.mit.edu -Subject: Wish List for GDB -Cc: tiemann@mcc.com - -GDB is a good debugger. I like it. I think it is lacking in functionality -in the following areas: - -1. "Finish this loop" capability. If I am stepping through code and -encounter a for-, do-, or while-loop, after a few iterations I generally -get bored. I want to be able to say "finish this loop"; i.e. continue -until the next statement after the loop is executed. Note this is -complicated by gotos and nested loops. - -2. GDB only prints the last line of a multi-line statement which has been -continued. Since this is often of the form - - foobar)); - -it is not very convenient. When stepping through a file using next (or step), -ALL non-blank text lines (excepting perhaps close-braces?) between the last -displayed line and the current one should be displayed. - -3. If there is a way to call a function interactively, I couldn't find it -in the on-line help. (Having neither GNU Emacs or TeX, reading the .texinfo -files is a bit tedious.) - -4. On occasion, when debugging a function with deeply nested code in a loop, -I want to have "hierarchical" breakpoints -- that is, I want certain -breakpoints automatically enabled if a certain breakpoint is triggered, -but not if it hasn't. I haven't thought of a good design for this yet. - -5. tbreak is not temporary enough; It should delete the breakpoint, not -disable it. - -6. what about "next to linenumber", or "continue to linenumber" -- the -only difference being next single-steps and continue sets an ephemeral -breakpoint and then deletes it. This would also make debugging large -functions easier. - -7. variable access breakpoints (break when variable changes value) - -8. should be able to use "set" to change initialization values before -"run" is issued. Makes setting of static debugging control variables -easier. Right now I have to break main all the time. - -9. GDB seems to be slow in reading/processing the symbol table -- can -this be improved? - -10. Preprocessor support. Is there any way to run the command input through -the preprocessor or otherwise get a handle on defines? Particlarly in -debugging things like ncurses, which use umpteen defines. - -(E.g., "delete_line" is defined as SP->_StrCaps[28] or some such nonsense.) - -Perhaps you could spawn off a CPP and then pipe the command input to it, -appropriately down-loading the included files and whatever # text was in -the C file being debugged.... - -Most of these comments of course apply to GDB+ as well. - -Well, that's just a few of my thoughts. Hope they give you some ideas. - - Alexis Layton - alex@CCA.CCA.COM - - -1,, -Summary-line: 27-Nov steve%next.com@relay.cs.n #gdb -Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Wed, 2 Dec 87 16:58:16 EST -Received: by PREP.AI.MIT.EDU; Wed, 2 Dec 87 17:00:22 EST -Message-Id: <8712022200.AA09856@prep.ai.mit.edu> -Received: from relay2.cs.net by RELAY.CS.NET id ag03066; 2 Dec 87 16:06 EST -Received: from next.com by RELAY.CS.NET id ae26721; 2 Dec 87 16:00 EST -Received: from indiana.next.com by next.next.com (3.2/SMI-3.0DEV3) - id AA08711; Fri, 27 Nov 87 10:47:36 PST -Date: Fri, 27 Nov 87 10:41:41 PST -From: steve%next.com@relay.cs.net -To: rms@prep.ai.mit.edu -Subject: gdb - -*** EOOH *** -Date: Fri, 27 Nov 87 10:41:41 PST -From: steve%next.com@relay.cs.net -To: rms@prep.ai.mit.edu -Subject: gdb - - I copied it into wheaties:gdb.tar.next.Z. The following is our "TODO" list. -An asterisk notes an entry is completed. - -- objc features: - * printing objects: - - printing indexed instance variables. - * implement object-print command which lists - class, methods, source file, etc. - * info objects command which lists all objects. - - * message expression evaluation: - * Use symbolic method name/object name. - - Add varargs support. - - printing instance variables: - - When all else fails, attempt to lookup an unknown - local as an instance variable (if currently in a - method handler/.m file). - * breakpoints: - - set breakpoints in object/method handler. - * stepping: - - stepm command that steps over _msg call into the - message handler when source is available. - * printing methods: - * info method that lists objects that implement a given - method. - * list command: - - modifiy it so that you can list the source for a given - object/method pair. - - backtrace: - - fix braindamaged backtrace (_msg doesn't maintain a6 linkage). - - poseAs: - - Reinitialize Obj-C-Data when poseAs is used. -- tenex: - * Finish incremental history searches. - * Add history search/reverse search. - * Add \e< and \e> - - Save macros on exit. - - Add commands to reset/append/prepend macrofiles. - - Add ability to read macrofiles once in emacs mode. - - print bindings command. - - command completion: - - gdb commands? - - symbol table entries? -- symbol tables: - - Modify current .sym file information to be left in .o files and - relocated by the debugger at load time. - - Load .sym file info on demand. -- documentation: -- mach port: - - use shared memory. - - multiple threads. - - multiple tasks. - - /dev/proc???? - - debug an already running task. - - debug a program with minimal symbol information. - - debugger support for shared libraries. -- misc: - - watchpoints. - - add a way to set evaluation scope/context to a file. - - disassembly enhancement: - - support symbolic names for locals and registers and - args. - - macro args (for user commands). - - case insensitivity for searches (info command/list searches). - - by default, load symbol table with exec-file. - - clean up structure printing. - - assmebler source level debugging. - - CPP info in the debugger (be able to get to #defines). -- gdbtool: - Source windows: - menus: - - tag support (callee/caller ala dir). - - break on line. - - unbreak on line. - - set one shot breakpoint. - - continue until line (with/without enabling other breakpoints). - - search forward/reverse. - - yank text for command window. - attributes: - - dir-like interface where each stack frame has a window. - Windows can be closed and are re-created when that stack frame - is reached again. If windows are too slow, beat up Leo. - - source windows have line-numbers/breakpoint indicator/last - PC in that window/current PC. - - full dir-like tags support for bringing up new windows (not on - the execution stack). - - Allow editing of source in a window (gray-scale for new lines/ - deleted lines) so that current debugging session still works. ??? - - incremental compiles (dream on!). - Data display windows: - - auto display window. - - graphic structure display. - Stack display window: - - stack trace display. Menu buttons: - - up/down. - - continue until stack level. - Command window: - menu: - - evaluate selected expression. - attributes: -- Remote debugging: - - Add other protocols (ethernet?, shared memory). -- C Interpreter. - - Control flow. - - Interpret changed code. - - Add subroutines. - - - -1,, -Summary-line: 22-Oct tiemann%pp.mcc.com@mcc.co #expanding file names -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA22869; Thu, 22 Oct 87 09:50:30 PDT -Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Thu, 22 Oct 87 12:17:59 EDT -Received: by PREP.AI.MIT.EDU; Thu, 22 Oct 87 12:21:00 EDT -Received: from pp.mcc.com by MCC.COM with TCP; Thu 22 Oct 87 10:54:41-CDT -Posted-Date: Thu, 22 Oct 87 10:55:13 CDT -Received: from big-d.aca.mcc.com by pp.mcc.com (4.12/KA70822) - id AA16571; Thu, 22 Oct 87 10:55:19 cdt -Return-Path: -Received: by big-d.aca.mcc.com (3.2/KA70106) - id AA04247; Thu, 22 Oct 87 10:55:13 CDT -Date: Thu, 22 Oct 87 10:55:13 CDT -From: tiemann%pp.mcc.com@mcc.com (Michael Tiemann) -Message-Id: <8710221555.AA04247@big-d.aca.mcc.com> -To: bug-gdb@prep.ai.mit.edu -Subject: expanding file names - -*** EOOH *** -Posted-Date: Thu, 22 Oct 87 10:55:13 CDT -Return-Path: -Date: Thu, 22 Oct 87 10:55:13 CDT -From: tiemann%pp.mcc.com@mcc.com (Michael Tiemann) -To: bug-gdb@prep.ai.mit.edu -Subject: expanding file names - -When running a program, gdb thoughtfully passes the argument list -through the shell, expanding files and environment variables as -needed. It would be nice if the same facility were added to the -command which adds directories to search paths. For example, it would -be nice to say "dir ~/foo" . - -Michael - - -1, edited, answered,, -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA26610; Wed, 2 Mar 88 05:27:51 PST -Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Wed, 2 Mar 88 08:26:23 EST -Received: from cgl.ucsf.EDU by prep.ai.mit.edu; Wed, 2 Mar 88 08:25:58 EST -Received: by cgl.ucsf.edu (5.54/GSC4.5) - id AA27646; Wed, 2 Mar 88 05:23:57 PST -Received: by hop.toad.com id AA00787; Wed, 2 Mar 88 05:22:55 PST -Date: Wed, 2 Mar 88 05:22:55 PST -From: hoptoad.UUCP!gnu@cgl.ucsf.edu (John Gilmore) -Message-Id: <8803021322.AA00787@hop.toad.com> -To: rms@cgl.ucsf.edu -Subject: A few things Sun dbx does that gdb doesn't... - -*** EOOH *** -Date: Wed, 2 Mar 88 05:22:55 PST -From: hoptoad.UUCP!gnu@cgl.ucsf.edu (John Gilmore) -To: rms@cgl.ucsf.edu -Subject: A few things Sun dbx does that gdb doesn't... - - * gdb won't reread the executable's symbol table when its mod time -has changed. The user has to explicitly reread it after recompiling -the software and before typing "run". - - * gdb has no command to report the current argv for "run" commands. -"info program" or "info environment" should display this info. (dbx -doesn't do this either, but I noticed it at the same time.) - - -1, answered,, -Received: by xcssun.Berkeley.EDU (5.57/1.25) - id AA14587; Tue, 16 Feb 88 16:19:12 PST -Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Tue, 16 Feb 88 19:17:21 EST -Received: from UNIX.SRI.COM by prep.ai.mit.edu; Tue, 16 Feb 88 19:08:02 EST -Received: by sri-unix.ARPA (5.31/5.14) - id AA25586; Tue, 16 Feb 88 16:12:32 PST -From: ozona!chase@pisa.orc.olivetti.com -Received: from ozona.orc.olivetti.com by orc.uucp (3.2/SMI-3.2) - id AA01567; Tue, 16 Feb 88 16:01:02 PST -Received: from localhost by ozona.orc.olivetti.com (3.2/SMI-3.2) - id AA08259; Tue, 16 Feb 88 16:02:22 PST -Message-Id: <8802170002.AA08259@ozona.orc.olivetti.com> -To: rms@prep.ai.mit.edu -Subject: GDB suggestion -Reply-To: chase%orc.uucp@unix.sri.com -Date: Tue, 16 Feb 88 16:02:18 -0800 - -*** EOOH *** -From: ozona!chase@pisa.orc.olivetti.com -To: rms@prep.ai.mit.edu -Subject: GDB suggestion -Reply-To: chase%orc.uucp@unix.sri.com -Date: Tue, 16 Feb 88 16:02:18 -0800 - - -Today I found myself wanting a feature in a debugger that neither GDB -nor DBX supports. I checked the GDB documentation and could not find -it there. This may be too Unix-specific, so you may not want to add -it. It may also not be of general use. Nevertheless, I will suggest -it; it's certainly easy to ignore the suggestion. - -What I wanted to do was limit the datasize of a program that I was -debugging (I am debugging someone else's garbage collector, lucky -me) without also imposing that limit on the debugger. I didn't see -any mention of such a command in either debugger's documentation. - -In other news, the alleged (ansi) C and Modula library is beginning to -work. (The garbage collector is part of the Modula-2+ half.) - -David Chase -Olivetti Research Center, Menlo Park - - -1,, -Return-Path: -Received: by frosted-flakes.ai.mit.edu; Sat, 30 Apr 88 17:05:42 EDT -Date: Sat, 30 Apr 88 17:05:42 EDT -From: rms@wheaties.ai.mit.edu (Richard Stallman) -Message-Id: <8804302105.AA25303@frosted-flakes.ai.mit.edu> -To: rms -Subject: GDB idea - -*** EOOH *** -Return-Path: -Date: Sat, 30 Apr 88 17:05:42 EDT -From: rms@wheaties.ai.mit.edu (Richard Stallman) -To: rms -Subject: GDB idea - -Expressions should record the block that symbols were looked up in, -if the symbols proved not to be static, -and an auto-display should be disabled automatically when it is -not in the block where the results would be meaningful. - - \ No newline at end of file diff --git a/gdb/gdb.texinfo b/gdb/gdb.texinfo new file mode 100644 index 0000000..db83964 --- /dev/null +++ b/gdb/gdb.texinfo @@ -0,0 +1,2924 @@ +\input texinfo +@setfilename ../info/gdb +@settitle GDB, The GNU Debugger +@ifinfo +This file documents the GNU debugger GDB. + +Copyright (C) 1988 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Distribution'' and ``GDB General Public License'' are +included exactly as in the original, and provided that the entire resulting +derived work is distributed under the terms of a permission notice +identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that the sections entitled ``Distribution'' and ``GDB General Public +License'' may be included in a translation approved by the author instead +of in the original English. +@end ifinfo + +@setchapternewpage odd +@settitle GDB Manual +@titlepage +@sp 6 +@center @titlefont{GDB Manual} +@sp 1 +@center The GNU Source-Level Debugger +@sp 4 +@center Third Edition, GDB version 3.1 +@sp 1 +@center January 1989 +@sp 5 +@center Richard M. Stallman +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1988, 1989 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Distribution'' and ``GDB General Public License'' are +included exactly as in the original, and provided that the entire resulting +derived work is distributed under the terms of a permission notice +identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that the sections entitled ``Distribution'' and ``GDB General Public +License'' may be included in a translation approved by the author instead +of in the original English. +@end titlepage +@page + +@node Top, Commands,, (DIR) +@unnumbered Summary of GDB + +The purpose of a debugger such as GDB is to allow you to execute another +program while examining what is going on inside it. We call the other +program ``your program'' or ``the program being debugged''. + +GDB can do four kinds of things (plus other things in support of these): + +@enumerate +@item +Start the program, specifying anything that might affect its behavior. + +@item +Make the program stop on specified conditions. + +@item +Examine what has happened, when the program has stopped, so that you +can see bugs happen. + +@item +Change things in the program, so you can correct the effects of one bug +and go on to learn about another without having to recompile first. +@end enumerate + +GDB can be used to debug programs written in C and C++. Pascal support +is being implemented, and Fortran support will be added when a GNU +Fortran compiler is written. + +@menu +* License:: The GDB General Public License gives you permission + to redistribute GDB on certain terms; and also + explains that there is no warranty. +* Input:: GDB command syntax and input conventions. +* Files:: Specifying files for GDB to operate on. +* Options:: GDB arguments and options. +* Compilation::Compiling your program so you can debug it. +* Running:: Running your program under GDB. +* Stopping:: Making your program stop. Why it may stop. What to do then. +* Stack:: Examining your program's stack. +* Source:: Examining your program's source files. +* Data:: Examining data in your program. +* Symbols:: Examining the debugger's symbol table. +* Altering:: Altering things in your program. +* Sequences:: Canned command sequences for repeated use. +* Emacs:: Using GDB through GNU Emacs. +* Remote:: Remote kernel debugging across a serial line. +* Commands:: Index of GDB commands. +* Concepts:: Index of GDB concepts. +@end menu + +@node License, Input, Top, Top +@unnumbered GDB General Public License +@center (Clarified 11 Feb 1988) + + The license agreements of most software companies keep you at the mercy +of those companies. By contrast, our general public license is intended to +give everyone the right to share GDB. To make sure that you get the rights +we want you to have, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. Hence this +license agreement. + + Specifically, we want to make sure that you have the right to give away +copies of GDB, that you receive source code or else can get it if you want +it, that you can change GDB or use pieces of it in new free programs, and +that you know you can do these things. + + To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute copies +of GDB, 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. + + Also, for our own protection, we must make certain that everyone finds +out that there is no warranty for GDB. If GDB is modified by someone else +and passed on, we want its recipients to know that what they have is not +what we distributed, so that any problems introduced by others will not +reflect on our reputation. + + Therefore we (Richard Stallman and the Free Software Foundation, +Inc.) make the following terms which say what you must do to be +allowed to distribute or change GDB. + +@unnumberedsec Copying Policies + +@enumerate +@item +You may copy and distribute verbatim copies of GDB source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each file a valid copyright notice ``Copyright +@copyright{} 1988 Free Software Foundation, Inc.'' (or with whatever year +is appropriate); keep intact the notices on all files that +refer to this License Agreement and to the absence of any warranty; and +give any other recipients of the GDB program a copy of this License +Agreement along with the program. You may charge a distribution fee +for the physical act of transferring a copy. + +@item +You may modify your copy or copies of GDB source code 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: + +@itemize @bullet +@item +cause the modified files to carry prominent notices stating +that you changed the files and the date of any change; and + +@item +cause the whole of any work that you distribute or publish, that +in whole or in part contains or is a derivative of GDB or any +part thereof, to be licensed at no charge to all third parties on +terms identical to those contained in this License Agreement +(except that you may choose to grant more extensive warranty +protection to some or all third parties, at your option). + +@item +if the modified program serves as a debugger, cause it, when +started running in the simplest and usual way, to print an +announcement including a valid copyright notice ``Copyright +@copyright{} 1988 Free Software Foundation, Inc.'' (or with the +year that is appropriate), saying 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 License Agreement. + +@item +You may charge a distribution fee for the physical act of +transferring a copy, and you may at your option offer warranty +protection in exchange for a fee. +@end itemize + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + +@item +You may copy and distribute GDB (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: + +@itemize @bullet +@item +accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of +Paragraphs 1 and 2 above; or, + +@item +accompany it with a written offer, valid for at least three +years, to give any third party free (except for a nominal +shipping charge) a complete machine-readable copy of the +corresponding source code, to be distributed under the terms of +Paragraphs 1 and 2 above; or, + +@item +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.) +@end itemize + +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. + +@item +You may not copy, sublicense, distribute or transfer GDB except as +expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer GDB is void and +your rights to use GDB under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full +compliance. + +@item +If you wish to incorporate parts of GDB into other free programs whose +distribution conditions are different, write to the Free Software +Foundation. We have not yet worked out a simple rule that can be +stated here, but we will often permit this. We will be guided by the +two goals of preserving the free status of all derivatives our free +software and of promoting the sharing and reuse of software. +@end enumerate + +@iftex +@vfil +@eject +@end iftex +@unnumberedsec NO WARRANTY + + BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, THE FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB ``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 GDB +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY +SERVICING, REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL FREE SOFTWARE +FOUNDATION, INC., RICHARD M. STALLMAN, AND/OR ANY OTHER PARTY WHO MAY +MODIFY AND REDISTRIBUTE GDB AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY +FREE SOFTWARE FOUNDATION, INC.) THE PROGRAM, EVEN IF YOU HAVE BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY +OTHER PARTY. + +@node Input, Files, License, Top +@chapter GDB Input Conventions + +GDB is invoked with the shell command @samp{gdb}. Once started, it reads +commands from the terminal until you tell it to exit. + +A GDB command is a single line of input. There is no limit on how long +it can be. It starts with a command name, which is followed by arguments +whose meaning depends on the command name. Some command names do not +allow arguments. + +GDB command names may always be abbreviated if the abbreviation is +unambiguous. Sometimes even ambiguous abbreviations are allowed; for +example, @samp{s} is specially defined as equivalent to @samp{step} +even though there are other commands whose names start with @samp{s}. +Possible command abbreviations are often stated in the documentation +of the individual commands. + +A blank line as input to GDB means to repeat the previous command verbatim. +Certain commands do not allow themselves to be repeated this way; these are +commands for which unintentional repetition might cause trouble and which +you are unlikely to want to repeat. Certain others (@samp{list} and +@samp{x}) act differently when repeated because that is more useful. + +A line of input starting with @samp{#} is a comment; it does nothing. +This is useful mainly in command files (@xref{Command Files}). + +Occasionally it is useful to execute a shell command from within gdb. +This can be done with the @samp{shell} command, or the shell escape +character @samp{!}. + +@table @code +@item shell @var{shell command string} +@kindex shell +@item !@var{shell command string} +@kindex ! +@cindex shell escape +Directs GDB to invoke an inferior shell to execute @samp{shell command string}. +The environmental variable @samp{SHELL} is used if it exists, otherwise gdb +uses @samp{/bin/sh}. +@end table + +GDB @dfn{prompts} for commands with a string that is normally @samp{(gdb)}. +When debugging GDB with GDB, it is useful to change the prompt in one of +the GDBs so that you can distinguish them. This can be done with the +@samp{set prompt} command. + +@table @code +@item set prompt @var{newprompt} +@kindex set prompt +Directs GDB to use @var{newprompt} as its prompt string henceforth. +@end table + +@cindex exiting GDB +@kindex quit +To exit GDB, use the @samp{quit} command (abbreviated @samp{q}). +@kbd{Ctrl-c} will not exit from GDB, but rather will terminate the action +of any GDB command that is in progress and return to GDB command level. +It is safe to type @kbd{Ctrl-c} at any time because GDB does not allow +it to take effect until a time when it is safe. + +@node Files, Options, Input, Top +@chapter Specifying GDB's Files + +@cindex core dump file +@cindex executable file +@cindex symbol table +GDB needs to know the filename of the program to be debugged. To debug a +core dump of a previous run, GDB must be told the filename of the core +dump. + +@menu +* Arguments: File Arguments. Specifying files with arguments + (when you start GDB). +* Commands: File Commands. Specifying files with GDB commands. +@end menu + +@node File Arguments, File Commands, Files, Files +@section Specifying Files with Arguments + +The usual way to specify the executable and core dump file names is with +two command arguments given when you start GDB. The first argument is used +as the file for execution and symbols, and the second argument (if any) is +used as the core dump file name. Thus, + +@example +gdb progm core +@end example + +@noindent +specifies @file{progm} as the executable program and @file{core} as a core +dump file to examine. (You do not need to have a core dump file if what +you plan to do is debug the program interactively.) + +@xref{Options}, for full information on command options and arguments for +GDB. + +@node File Commands,, File Arguments, Files +@section Specifying Files with Commands + +Usually you specify the files for GDB to work with by giving arguments when +you invoke GDB. But occasionally it is necessary to change to a different +file during a GDB session. Or you may run GDB and forget to specify the +files you want to use. In these situations the GDB commands to specify new +files are useful. + +@table @code +@item exec-file @var{filename} +@kindex exec-file +Specify that the program to be run is found in @var{filename}. If you +do not specify a directory and the file is not found in GDB's working +directory, GDB will use the environment variable @samp{PATH} as a list +of directories to search, just as the shell does when looking for a +program to run. + +@item symbol-file @var{filename} +@kindex symbol-file +Read symbol table information from file @var{filename}. @samp{PATH} +is searched when necessary. Most of the time you will use both the +@samp{exec-file} and @samp{symbol-file} commands on the same file. + +@samp{symbol-file} with no argument clears out GDB's symbol table. + +@item core-file @var{filename} +@kindex core-file +Specify the whereabouts of a core dump file to be used as the +``contents of memory''. Note that the core dump contains only the +writable parts of memory; the read-only parts must come from the +executable file. + +@samp{core-file} with no argument specifies that no core file is +to be used. + +@item add-file @var{filename} @var{address} +@kindex add-file +The @samp{add-file} command takes two arguments, a file name, and the +address at which that file has been (or should be) dynamically loaded. +GDB will then treat that file as though it had always been dynamically +linked, and provide the user with all the normal GDB features, including +symbolic debugging. + +With the @samp{add-file} command, it is possible to debug code which was +not present in the initial load image of the program under test. +Suppose you have a program which can, while running, dynamically link a +program fragment into its address space. One program which does this is +KCL, a free common lisp implementation. The fragment will be loaded +into the main program's address space at some address, and the main +program can then call functions within the fragment by calculating (or +otherwise obtaining) their addresses. + +@item kill +@kindex kill +Cancel running the program under GDB. This could be used if you wish +to debug a core dump instead. GDB ignores any core dump file if it is +actually running the program, so the @samp{kill} command is the only +sure way to go back to using the core dump file. + +@item info files +@kindex info files +Print the names of the executable and core dump files currently in +use by GDB, and the file from which symbols were loaded. +@end table + +While all three file-specifying commands allow both absolute and relative +file names as arguments, GDB always converts the file name to an absolute +one and remembers it that way. + +The @samp{symbol-file} command causes GDB to forget the contents of its +convenience variables, the value history, and all breakpoints and +auto-display expressions. This is because they may contain pointers to the +internal data recording symbols and data types, which are part of the old +symbol table data being discarded inside GDB. + +@node Options, Compilation, Files, Top +@chapter Options and Arguments for GDB + +When you invoke GDB, you can pass commands telling it what files to +operate on and what other things to do. + +@menu +* Mode Options:: Options controlling modes of operation. +* File Options:: Options to specify files (executable, coredump, commands) +* Other Arguments:: Any other arguments without options + also specify files. +@end menu + +@node Mode Options, File Options, Options, Options +@section Mode Options + +@table @samp +@item -nx +Do not execute commands from the init files @file{.gdbinit}. +Normally, the commands in these files are executed after all the +command options and arguments have been processed. @xref{Command +Files}. + +@item -q +``Quiet''. Do not print the usual introductory messages. + +@item -batch +Run in batch mode. Exit with code 1 after processing all the command +files specified with @samp{-x} (and @file{.gdbinit}, if not +inhibited). Exit also if, due to an error, GDB would otherwise +attempt to read a command from the terminal. + +@item -fullname +This option is used when Emacs runs GDB as a subprocess. It tells GDB +to output the full file name and line number in a standard, +recognizable fashion each time a stack frame is displayed (which +includes each time the program stops). This recognizable format looks +like two @samp{\032} characters, followed by the filename, line number +and character position separated by colons, and a newline. The +Emacs-to-GDB interface program uses the two @samp{\032} characters as +a signal to display the source code for the frame. +@end table + +@node File Options, Other Arguments, Mode Options, Options +@section File-specifying Options + +All the options and command line arguments given are processed +in sequential order. The order makes a difference when the +@samp{-x} command is used. + +@table @samp +@item -s @var{file} +Read symbol table from file @var{file}. + +@item -e @var{file} +Use file @var{file} as the executable file to execute when +appropriate, and for examining pure data in conjunction with a core +dump. + +@item -se @var{file} +Read symbol table from file @var{file} and use it as the executable +file. + +@item -c @var{file} +Use file @var{file} as a core dump to examine. + +@item -x @var{file} +Execute GDB commands from file @var{file}. + +@item -d @var{directory} +Add @var{directory} to the path to search for source files. +@end table + +@node Other Arguments,, File Options, Options +@section Other Arguments + +If there are arguments to GDB that are not options or associated with +options, the first one specifies the symbol table and executable file name +(as if it were preceded by @samp{-se}) and the second one specifies a core +dump file name (as if it were preceded by @samp{-c}). + +@node Compilation, Running, Options, Top +@chapter Compiling Your Program for Debugging + +In order to debug a program effectively, you need to ask for debugging +information when you compile it. This information in the object file +describes the data type of each variable or function and the correspondence +between source line numbers and addresses in the executable code. + +To request debugging information, specify the @samp{-g} option when you run +the compiler. + +The Unix C compiler is unable to handle the @samp{-g} and @samp{-O} options +together. This means that you cannot ask for optimization if you ask for +debugger information. + +The GNU C compiler supports @samp{-g} with or without @samp{-O}, making it +possible to debug optimized code. We recommend that you @emph{always} use +@samp{-g} whenever you compile a program. You may think the program is +correct, but there's no sense in pushing your luck. + +If you are using the GNU C compiler, the GNU assembler and the GNU linker, +you can choose between two formats of debugging information: the standard +Unix format, which is what you get with @samp{-g}, and GDB's own format, +which you request by using @samp{-gg} instead of @samp{-g}. This stores +debugging information in the executable file in a format much like that +which is used inside GDB. This has these advantages and disadvantages: + +@itemize @bullet +@item +GDB can read @samp{-gg} format more than twice as fast as Unix +@samp{-g} format. + +@item +The @samp{-gg} format uses much more disk space than Unix format. + +@item +The Unix debuggers can understand only Unix format, so you cannot use +Unix source-level debuggers if you compile with @samp{-gg}. (The +@code{adb} debugger works with either format; it does not use this +information in any case.) +@end itemize + +@node Running, Stopping, Compilation, Top +@chapter Running Your Program Under GDB + +@cindex running +@kindex run +To start your program under GDB, use the @samp{run} command. The program +must already have been specified using the @samp{exec-file} command or with +an argument to GDB (@pxref{Files}); what @samp{run} does is create an +inferior process, load the program into it, and set it in motion. + +The execution of a program is affected by certain information it receives +from its superior. GDB provides ways to specify them, which you must do +@i{before} starting the program. (You can change them after starting the +program, but such changes do not affect the program unless you start it +over again.) + +@table @asis +@item The @i{arguments.} +You specify the arguments to give the program as the arguments of the +@samp{run} command. + +@item The @i{environment.} +The program normally inherits its environment from GDB, but you can +use the GDB commands @samp{set environment} and +@samp{unset environment} to change parts of the environment that will +be given to the program.@refill + +@item The @i{working directory.} +The program inherits its working directory from GDB. You can set GDB's +working directory with the @samp{cd} command in GDB. +@end table + +After the @samp{run} command, the debugger does nothing but wait for your +program to stop. @xref{Stopping}. + +Note that once your program has been started by the @samp{run} command, +you may evaluate expressions that involve calls to functions in the +inferior. @xref{Expressions}. If you wish to evaluate a function +simply for it's side affects, you may use the @samp{set} command. +@xref{Assignment}. + +@menu +* Arguments:: Specifying the arguments for your program. +* Environment:: Specifying the environment for your program. +* Working Directory:: Specifying the working directory for giving + to your program when it is run. +* Input/Output:: Specifying the program's standard input and output. +* Attach:: Debugging a process started outside GDB. +@end menu + +@node Arguments, Environment, Running, Running +@section Your Program's Arguments + +@cindex arguments (to your program) +You specify the arguments to give the program as the arguments of the +@samp{run} command. They are passed to a shell, which expands wildcard +characters and performs redirection of I/O, and thence to the program. + +@samp{run} with no arguments uses the same arguments used by the previous +@samp{run}. + +@kindex set args +The command @samp{set args} can be used to specify the arguments to be used +the next time the program is run. If @samp{set args} has no arguments, it +means to use no arguments the next time the program is run. If you have +run your program with arguments and want to run it again with no arguments, +this is the only way to do so. + +@node Environment, Working Directory, Arguments, Running +@section Your Program's Environment + +@cindex environment (of your program) +The @dfn{environment} consists of a set of @dfn{environment variables} and +their values. Environment variables conventionally record such things as +your user name, your home directory, your terminal type, and your search +path for programs to run. Usually you set up environment variables with +the shell and they are inherited by all the other programs you run. When +debugging, it can be useful to try running the program with different +environments without having to start the debugger over again. + +@table @code +@item info environment @var{varname} +@kindex info environment +Print the value of environment variable @var{varname} to be given to +your program when it is started. This command can be abbreviated +@samp{i env @var{varname}}. + +@item info environment +Print the names and values of all environment variables to be given to +your program when it is started. This command can be abbreviated +@samp{i env}. + +@item set environment @var{varname} @var{value} +@item set environment @var{varname} = @var{value} +@kindex set environment +Sets environment variable @var{varname} to @var{value}, for your program +only, not for GDB itself. @var{value} may be any string; the values of +environment variables are just strings, and any interpretation is +supplied by your program itself. The @var{value} parameter is optional; +if it is eliminated, the variable is set to a null value. This command +can be abbreviated as short as @samp{set e}. + +@item delete environment @var{varname} +@kindex delete environment +@item unset environment @var{varname} +@kindex unset environment +Remove variable @var{varname} from the environment to be passed to +your program. This is different from @samp{set env @var{varname} =} +because @samp{delete environment} makes a variable not be defined at +all, which is distinguishable from an empty value. This command can +be abbreviated @samp{d e}. +@end table + +@node Working Directory, Input/Output, Environment, Running +@section Your Program's Working Directory + +@cindex working directory (of your program) +Each time you start your program with @samp{run}, it inherits its working +directory from the current working directory of GDB. GDB's working +directory is initially whatever it inherited from its superior, but you can +specify the working directory for GDB with the @samp{cd} command. + +The GDB working directory also serves as a default for the commands +that specify files for GDB to operate on. @xref{Files}. + +@table @code +@item cd @var{directory} +@kindex cd +Set GDB's working directory to @var{directory}. + +@item pwd +@kindex pwd +Print GDB's working directory. +@end table + +@node Input/Output, Attach, Working Directory, Running +@section Your Program's Input and Output + +@cindex redirection +@cindex controlling terminal +By default, the program you run under GDB does input and output to the same +terminal that GDB uses. + +You can redirect the program's input and/or output using @samp{sh}-style +redirection commands in the @samp{run} command. For example, + +@example +run > outfile +@end example + +@noindent +starts the program, diverting its output to the file @file{outfile}. + +@kindex tty +Another way to specify where the program should do input and output is with +the @samp{tty} command. This command accepts a file name as argument, and +causes this file to be the default for future @samp{run} commands. It also +resets the controlling terminal for future @samp{run} commands. For +example, + +@example +tty /dev/ttyb +@end example + +@noindent +directs that processes started with subsequent @samp{run} commands default +to do input and output on the terminal @file{/dev/ttyb} and sets the +controlling terminal to @file{/dev/ttyb}. An explicit redirection in +@samp{run} overrides the @samp{tty} command's effect on input/output +redirection. + +When you use the @samp{tty} command or redirect input in the @samp{run} +command, the @emph{input for your program} comes from the specified file, +but the input for GDB still comes from your terminal. + +@node Attach,, Input/Output, Running +@section Debugging an Already-Running Process +@kindex detach +@kindex attach +@cindex attach + +Some operating systems (in particular, Sun) allow GDB to begin debugging an +already-running process that was started outside of GDB. To do this you +must use the @samp{attach} command instead of the @samp{run} command. + +The @samp{attach} command requires one argument, which is the process-id of +the process you want to debug. (The usual way to find out the process-id +of the process is with the @samp{ps} utility.) + +The first thing GDB does after arranging to debug the process is to stop +it. You can examine and modify an attached process with all the GDB +commands that ordinarily available when you start processes with +@samp{run}. You can insert breakpoints; you can step and continue; you +can modify storage. If you would rather the process continue running, +use the @samp{continue} command after attaching. + +When you are finished debugging the attached process, you can use the +@samp{detach} command to release it from GDB's control. Detaching +the process continues its execution. After the @samp{detach} command, +that process and GDB become completely independent once more, and you +are ready to @samp{attach} another process or start one with @samp{run}. + +If you exit GDB or use the @samp{run} command while you have an attached +process, you kill that process. You will be asked for confirmation if you +try to do either of these things. + +@node Stopping, Stack, Running, Top +@chapter Stopping and Continuing + +When you run a program normally, it runs until exiting. The purpose +of using a debugger is so that you can stop it before that point; +or so that if the program runs into trouble you can find out why. + +@menu +* Signals:: Fatal signals in your program just stop it; + then you can use GDB to see what is going on. +* Breakpoints:: Breakpoints let you stop your program when it + reaches a specified point in the code. +* Continuing:: Resuming execution until the next signal or breakpoint. +* Stepping:: Stepping runs the program a short distance and + then stops it wherever it has come to. +@end menu + +@node Signals, Breakpoints, Stopping, Stopping +@section Signals + +A signal is an asynchronous event that can happen in a program. The +operating system defines the possible kinds of signals, and gives each kind +a name and a number. For example, @code{SIGINT} is the signal a program +gets when you type @kbd{Ctrl-c}; @code{SIGSEGV} is the signal a program +gets from referencing a place in memory far away from all the areas in use; +@code{SIGALRM} occurs when the alarm clock timer goes off (which happens +only if the program has requested an alarm). + +Some signals, including @code{SIGALRM}, are a normal part of the +functioning of the program. Others, such as @code{SIGSEGV}, indicate +errors; these signals are @dfn{fatal} (kill the program immediately) if the +program has not specified in advance some other way to handle the signal. +@code{SIGINT} does not indicate an error in the program, but it is normally +fatal so it can carry out the purpose of @kbd{Ctrl-c}: to kill the program. + +GDB has the ability to detect any occurrence of a signal in the program +running under GDB's control. You can tell GDB in advance what to do for +each kind of signal. + +Normally, GDB is set up to ignore non-erroneous signals like @code{SIGALRM} +(so as not to interfere with their role in the functioning of the program) +but to stop the program immediately whenever an error signal happens. +You can change these settings with the @samp{handle} command. You must +specify which signal you are talking about with its number. + +@table @code +@item info signal +@kindex info signal +Print a table of all the kinds of signals and how GDB has been told to +handle each one. You can use this to see the signal numbers of all +the defined types of signals. + +@item handle @var{signalnum} @var{keywords}@dots{} +@kindex handle +Change the way GDB handles signal @var{signalnum}. The @var{keywords} +say what change to make. +@end table + +To use the @samp{handle} command you must know the code number of the +signal you are concerned with. To find the code number, type @samp{info +signal} which prints a table of signal names and numbers. + +The keywords allowed by the handle command can be abbreviated. Their full +names are + +@table @code +@item stop +GDB should stop the program when this signal happens. This implies +the @samp{print} keyword as well. + +@item print +GDB should print a message when this signal happens. + +@item nostop +GDB should not stop the program when this signal happens. It may +still print a message telling you that the signal has come in. + +@item noprint +GDB should not mention the occurrence of the signal at all. This +implies the @samp{nostop} keyword as well. + +@item pass +GDB should allow the program to see this signal; the program will be +able to handle the signal, or may be terminated if the signal is fatal +and not handled. + +@item nopass +GDB should not allow the program to see this signal. +@end table + +When a signal has been set to stop the program, the program cannot see the +signal until you continue. It will see the signal then, if @samp{pass} is +in effect for the signal in question @i{at that time}. In other words, +after GDB reports a signal, you can use the @samp{handle} command with +@samp{pass} or @samp{nopass} to control whether that signal will be seen by +the program when you later continue it. + +You can also use the @samp{signal} command to prevent the program from +seeing a signal, or cause it to see a signal it normally would not see, +or to give it any signal at any time. @xref{Signaling}. + +@node Breakpoints, Continuing, Signals, Stopping +@section Breakpoints + +@cindex breakpoints +A @dfn{breakpoint} makes your program stop whenever a certain point in the +program is reached. You set breakpoints explicitly with GDB commands, +specifying the place where the program should stop by line number, function +name or exact address in the program. You can add various other conditions +to control whether the program will stop. + +Each breakpoint is assigned a number when it is created; these numbers are +successive integers starting with 1. In many of the commands for controlling +various features of breakpoints you use the breakpoint number to say which +breakpoint you want to change. Each breakpoint may be @dfn{enabled} or +@dfn{disabled}; if disabled, it has no effect on the program until you +enable it again. + +@kindex info break +@kindex $_ +The command @samp{info break} prints a list of all breakpoints set and not +cleared, showing their numbers, where in the program they are, and any +special features in use for them. Disabled breakpoints are included in the +list, but marked as disabled. @samp{info break} with a breakpoint number +as argument lists only that breakpoint. The convenience variable @samp{$_} +and the default examining-address for the @samp{x} command are set to the +address of the last breakpoint listed (@pxref{Memory}). + +@menu +* Set Breaks:: How to establish breakpoints. +* Clear Breaks:: How to remove breakpoints no longer needed. +* Disabling:: How to disable breakpoints (turn them off temporarily). +* Conditions:: Making extra conditions on whether to stop. +* Break Commands:: Commands to be executed at a breakpoint. +* Error in Breakpoints:: "Cannot insert breakpoints" error--why, what to do. +@end menu + +@node Set Breaks, Clear Breaks, Breakpoints, Breakpoints +@subsection Setting Breakpoints + +@kindex break +Breakpoints are set with the @samp{break} command (abbreviated @samp{b}). +You have several ways to say where the breakpoint should go. + +@table @code +@item break @var{function} +Set a breakpoint at entry to function @var{function}. + +@item break @var{linenum} +Set a breakpoint at line @var{linenum} in the current source file. +That file is the last file whose source text was printed. This +breakpoint will stop the program just before it executes any of the +code on that line. + +@item break @var{filename}:@var{linenum} +Set a breakpoint at line @var{linenum} in source file @var{filename}. + +@item break @var{filename}:@var{function} +Set a breakpoint at entry to function @var{function} found in file +@var{filename}. Specifying a filename as well as a function name is +superfluous except when multiple files contain similarly named +functions. + +@item break *@var{address} +Set a breakpoint at address @var{address}. You can use this to set +breakpoints in parts of the program which do not have debugging +information or source files. + +@item break +Set a breakpoint at the next instruction to be executed in the selected +stack frame (@pxref{Stack}). In any selected frame but the innermost, +this will cause the program to stop as soon as control returns to that +frame. This is equivalent to a @samp{finish} command in the frame +inside the selected frame. If this is done in the innermost frame gdb +will stop the next time it reaches the current location; this may be +useful inside of loops. It does not stop at this breakpoint immediately +upon continuation of the program since no code would be executed if it +did. + +@item break @dots{} if @var{cond} +Set a breakpoint with condition @var{cond}; evaluate the expression +@var{cond} each time the breakpoint is reached, and stop only if the +value is nonzero. @samp{@dots{}} stands for one of the possible +arguments described above (or no argument) specifying where to break. +@xref{Conditions}, for more information on breakpoint conditions. + +@item tbreak @var{args} +@kindex tbreak +Set a breakpoint enabled only for one stop. @var{args} are the +same as in the @samp{break} command, and the breakpoint is set in the same +way, but the breakpoint is automatically @dfn{disabled} the first time it +is hit. +@end table + +GDB allows you to set any number of breakpoints at the same place in the +program. There is nothing silly or meaningless about this. When the +breakpoints are conditional, this is even useful (@pxref{Conditions}). + +@node Clear Breaks, Disabling, Set Breaks, Breakpoints +@subsection Clearing Breakpoints + +@cindex clear breakpoint +@cindex delete breakpoints +It is often necessary to eliminate a breakpoint once it has done its job +and you no longer want the program to stop there. This is called +@dfn{clearing} or @samp{deleting} the breakpoint. A breakpoint that +has been cleared no longer exists in any sense. + +With the @samp{clear} command you can clear breakpoints according to where +they are in the program. With the @samp{delete} command you can clear +individual breakpoints by specifying their breakpoint numbers. + +@b{It is not necessary to clear a breakpoint to proceed past it.} GDB +automatically ignores breakpoints in the first instruction to be executed +when you continue execution at the same address where the program stopped. + +@table @code +@item clear +@kindex clear +Clear any breakpoints at the next instruction to be executed in the +selected stack frame (@pxref{Selection}). When the innermost frame +is selected, this is a good way to clear a breakpoint that the program +just stopped at. + +@item clear @var{function} +@itemx clear @var{filename}:@var{function} +Clear any breakpoints set at entry to the function @var{function}. + +@item clear @var{linenum} +@item clear @var{filename}:@var{linenum} +Clear any breakpoints set at or within the code of the specified line. + +@item delete @var{bnums}@dots{} +@kindex delete +Delete the breakpoints of the numbers specified as arguments. +A breakpoint deleted is forgotten completely. +@end table + +@node Disabling, Conditions, Clear Breaks, Breakpoints +@subsection Disabling Breakpoints + +@cindex disabled breakpoints +@cindex enabled breakpoints +Rather than clearing a breakpoint, you might prefer to @dfn{disable} it. +This makes the breakpoint inoperative as if it had been cleared, but +remembers the information on the breakpoint so that you can @dfn{enable} +it again later. + +You disable and enable breakpoints with the @samp{enable} and +@samp{disable} commands, specifying one or more breakpoint numbers as +arguments. Use @samp{info break} to print a list of breakpoints if you +don't know which breakpoint numbers to use. + +A breakpoint can have any of four different states of enablement: + +@itemize @bullet +@item +Enabled. The breakpoint will stop the program. A breakpoint made +with the @samp{break} command starts out in this state. +@item +Disabled. The breakpoint has no effect on the program. +@item +Enabled once. The breakpoint will stop the program, but +when it does so it will become disabled. A breakpoint made +with the @samp{tbreak} command starts out in this state. +@item +Enabled for deletion. The breakpoint will stop the program, but +immediately after it does so it will be deleted permanently. +@end itemize + +You change the state of enablement of a breakpoint with the following +commands: + +@table @code +@item disable breakpoints @var{bnums}@dots{} +@kindex disable breakpoints +@item disable @var{bnums}@dots{} +@kindex disable +Disable the specified breakpoints. A disabled breakpoint has no +effect but is not forgotten. All options such as ignore-counts, +conditions and commands are remembered in case the breakpoint is +enabled again later. + +@item enable breakpoints @var{bnums}@dots{} +@kindex enable breakpoints +@item enable @var{bnums}@dots{} +@kindex enable +Enable the specified breakpoints. They become effective once again in +stopping the program, until you specify otherwise. + +@item enable breakpoints once @var{bnums}@dots{} +@item enable once @var{bnums}@dots{} +Enable the specified breakpoints temporarily. Each will be disabled +again the next time it stops the program (unless you have used one of +these commands to specify a different state before that time comes). + +@item enable breakpoints delete @var{bnums}@dots{} +@item enable delete @var{bnums}@dots{} +Enable the specified breakpoints to work once and then die. Each of +the breakpoints will be deleted the next time it stops the program +(unless you have used one of these commands to specify a different +state before that time comes). +@end table + +Aside from the automatic disablement or deletion of a breakpoint when it +stops the program, which happens only in certain states, the state of +enablement of a breakpoint changes only when one of the commands above +is used. + +@node Conditions, Break Commands, Disabling, Breakpoints +@subsection Break Conditions + +@cindex conditions +The simplest sort of breakpoint breaks every time the program reaches a +specified place. You can also specify a @dfn{condition} for a breakpoint. +A condition is just a boolean expression in your programming language +(@xref{Expressions}). A breakpoint with a condition evaluates the +expression each time the program reaches it, and the program stops +only if the condition is true. + +Break conditions may have side effects, and may even call functions in your +program. These may sound like strange things to do, but their effects are +completely predictable unless there is another enabled breakpoint at the +same address. (In that case, GDB might see the other breakpoint first and +stop the program without checking the condition of this one.) Note that +breakpoint commands are usually more convenient and flexible for the +purpose of performing side effects when a breakpoint is reached +(@pxref{Break Commands}). + +Break conditions can be specified when a breakpoint is set, by using +@samp{if} in the arguments to the @samp{break} command. @xref{Set Breaks}. +They can also be changed at any time with the @samp{condition} command: + +@table @code +@item condition @var{bnum} @var{expression} +@kindex condition +Specify @var{expression} as the break condition for breakpoint number +@var{bnum}. From now on, this breakpoint will stop the program only if +the value of @var{expression} is true (nonzero, in C). @var{expression} +is not evaluated at the time the @samp{condition} command is given. +@xref{Expressions}. + +@item condition @var{bnum} +Remove the condition from breakpoint number @var{bnum}. It becomes +an ordinary unconditional breakpoint. +@end table + +@cindex ignore count (of breakpoint) +A special feature is provided for one kind of condition: to prevent the +breakpoint from doing anything until it has been reached a certain number +of times. This is done with the @dfn{ignore count} of the breakpoint. +When the program reaches a breakpoint whose ignore count is positive, then +instead of stopping, it just decrements the ignore count by one and +continues. + +@table @code +@item ignore @var{bnum} @var{count} +@kindex ignore +Set the ignore count of breakpoint number @var{bnum} to @var{count}. +The next @var{count} times the breakpoint is reached, it will not stop. + +To make the breakpoint stop the next time it is reached, specify +a count of zero. + +@item cont @var{count} +Continue execution of the program, setting the ignore count of the +breakpoint that the program stopped at to @var{count} minus one. +Continuing through the breakpoint does not itself count as one of +@var{count}. Thus, the program will not stop at this breakpoint until the +@var{count}'th time it is hit. + +This command is allowed only when the program stopped due to a +breakpoint. At other times, the argument to @samp{cont} is ignored. +@end table + +If a breakpoint has a positive ignore count and a condition, the condition +is not checked. Once the ignore count reaches zero, the condition will +start to be checked. + +Note that you could achieve the effect of the ignore count with a condition +such as @samp{$foo-- <= 0} using a debugger convenience variable that is +decremented each time. That is why the ignore count is considered a +special case of a condition. @xref{Convenience Vars}. + +@node Break Commands, Error in Breakpoints, Conditions, Breakpoints +@subsection Commands Executed on Breaking + +@cindex breakpoint commands +You can give any breakpoint a series of commands to execute when the +program stops due to that breakpoint. For example, you might want to +print the values of certain expressions, or enable other breakpoints. + +@table @code +@item commands @var{bnum} +Specify commands for breakpoint number @var{bnum}. The commands +themselves appear on the following lines. Type a line containing just +@samp{end} to terminate the commands. + +To remove all commands from a breakpoint, use the command +@samp{commands} and follow it immediately by @samp{end}; that is, give +no commands. + +With no arguments, @samp{commands} refers to the last breakpoint set. +@end table + +It is possible for breakpoint commands to start the program up again. +Simply use the @samp{cont} command, or @samp{step}, or any other command +to resume execution. However, any remaining breakpoint commands are +ignored. When the program stops again, GDB will act according to why +that stop took place. + +@kindex silent +If the first command specified is @samp{silent}, the usual message about +stopping at a breakpoint is not printed. This may be desirable for +breakpoints that are to print a specific message and then continue. +If the remaining commands too print nothing, you will see no sign that +the breakpoint was reached at all. @samp{silent} is not really a command; +it is meaningful only at the beginning of the commands for a breakpoint. + +The commands @samp{echo} and @samp{output} that allow you to print precisely +controlled output are often useful in silent breakpoints. @xref{Output}. + +For example, here is how you could use breakpoint commands to print the +value of @code{x} at entry to @code{foo} whenever it is positive. We +assume that the newly created breakpoint is number 4; @samp{break} will +print the number that is assigned. + +@example +break foo if x>0 +commands 4 +silent +echo x is\040 +output x +echo \n +cont +end +@end example + +One application for breakpoint commands is to correct one bug so you can +test another. Put a breakpoint just after the erroneous line of code, give +it a condition to detect the case in which something erroneous has been +done, and give it commands to assign correct values to any variables that +need them. End with the @samp{cont} command so that the program does not +stop, and start with the @samp{silent} command so that no output is +produced. Here is an example: + +@example +break 403 +commands 5 +silent +set x = y + 4 +cont +end +@end example + +One deficiency in the operation of automatically continuing breakpoints +under Unix appears when your program uses raw mode for the terminal. +GDB switches back to its own terminal modes (not raw) before executing +commands, and then must switch back to raw mode when your program is +continued. This causes any pending terminal input to be lost. + +In the GNU system, this will be fixed by changing the behavior of +terminal modes. + +Under Unix, when you have this problem, you might be able to get around +it by putting your actions into the breakpoint condition instead of +commands. For example + +@example +condition 5 (x = y + 4), 0 +@end example + +@noindent +is a condition expression (@xref{Expressions}) that will change @code{x} +as needed, then always have the value 0 so the program will not stop. +Loss of input is avoided here because break conditions are evaluated +without changing the terminal modes. When you want to have nontrivial +conditions for performing the side effects, the operators @samp{&&}, +@samp{||} and @samp{?@: @dots{} :@:} may be useful. + +@node Error in Breakpoints,, Break Commands, Breakpoints +@subsection ``Cannot Insert Breakpoints'' Error + +Under some Unix systems, breakpoints cannot be used in a program if any +other process is running that program. Attempting to run or continue +the program with a breakpoint in this case will cause GDB to stop it. + +When this happens, you have three ways to proceed: + +@enumerate +@item +Remove or disable the breakpoints, then continue. + +@item +Suspend GDB, and copy the file containing the program to a new name. +Resume GDB and use the @samp{exec-file} command to specify that GDB +should run the program under that name. Then start the program again. + +@item +Recompile the program so that the text is non-sharable (a.out format +OMAGIC). +@end enumerate + +@node Continuing, Stepping, Breakpoints, Stopping +@section Continuing + +After your program stops, most likely you will want it to run some more if +the bug you are looking for has not happened yet. + +@table @code +@item cont +@kindex cont +Continue running the program at the place where it stopped. +@end table + +If the program stopped at a breakpoint, the place to continue running +is the address of the breakpoint. You might expect that continuing would +just stop at the same breakpoint immediately. In fact, @samp{cont} +takes special care to prevent that from happening. You do not need +to clear the breakpoint to proceed through it after stopping at it. + +You can, however, specify an ignore-count for the breakpoint that the +program stopped at, by means of an argument to the @samp{cont} command. +@xref{Conditions}. + +If the program stopped because of a signal other than @code{SIGINT} or +@code{SIGTRAP}, continuing will cause the program to see that signal. +You may not want this to happen. For example, if the program stopped +due to some sort of memory reference error, you might store correct +values into the erroneous variables and continue, hoping to see more +execution; but the program would probably terminate immediately as +a result of the fatal signal once it sees the signal. To prevent this, +you can continue with @samp{signal 0}. @xref{Signaling}. You can +also act in advance to prevent the program from seeing certain kinds +of signals, using the @samp{handle} command (@pxref{Signals}). + +@node Stepping,, Continuing, Stopping +@section Stepping + +@cindex stepping +@dfn{Stepping} means setting your program in motion for a limited time, so +that control will return automatically to the debugger after one line of +code or one machine instruction. Breakpoints are active during stepping +and the program will stop for them even if it has not gone as far as the +stepping command specifies. + +@table @code +@item step +@kindex step +Proceed the program until control reaches a different line, then stop +it and return to the debugger. This command is abbreviated @samp{s}. + +@item step @var{count} +Proceed as in @samp{step}, but do so @var{count} times. If a breakpoint +or a signal not related to stepping is reached before @var{count} steps, +stepping stops right away. + +This command may be given when control is within a routine for which +there is no debugging information. In that case, execution will proceed +until control reaches a different routine, or is about to return from +this routine. An argument repeats this action. + +@item next +@kindex next +Similar to @samp{step}, but any function calls appearing within the line of +code are executed without stopping. Execution stops when control reaches a +different line of code at the stack level which was executing when the +@samp{next} command was given. This command is abbreviated @samp{n}. + +An argument is a repeat count, as in @samp{step}. + +@samp{next} within a routine without debugging information acts as does +@samp{step}, but any function calls appearing within the code of the +routine are executed without stopping. + +@item finish +@kindex finish +Continue running until just after the selected stack frame returns +(or until there is some other reason to stop, such as a fatal signal +or a breakpoint). Print value returned by the selected stack frame (if +any). + +Contrast this with the @samp{return} command (@pxref{Returning}). + +@item until +@kindex until +Proceed the program until control reaches a line greater than the current +line, then stop is and return to the debugger. Control is also returned to +the debugger if the program exits the current stack frame. Note that this +form of the command uses single stepping, and hence is slower than +@samp{until} with an argument. This command is abbreviated @samp{u}. + +@item until @var{location} +Proceed the program until either the specified location is reached, or the +current (innermost) stack frame returns. This form of the command uses +breakpoints, and hence is quicker than @samp{until} without an argument. + +@item stepi +@itemx si +@kindex stepi +@kindex si +Proceed one machine instruction, then stop and return to the debugger. + +It is often useful to do @samp{display/i $pc} when stepping by machine +instructions. This will cause the next instruction to be executed to +be displayed automatically at each stop. @xref{Auto Display}. + +An argument is a repeat count, as in @samp{step}. + +@item nexti +@itemx ni +@kindex nexti +@kindex ni +Proceed one machine instruction, but if it is a subroutine call, +proceed until the subroutine returns. + +An argument is a repeat count, as in @samp{next}. +@end table + +A typical technique for using stepping is to put a breakpoint +(@pxref{Breakpoints}) at the beginning of the function or the section of +the program in which a problem is believed to lie, and then step through +the suspect area, examining the variables that are interesting, until the +problem happens. + +The @samp{cont} command can be used after stepping to resume execution +until the next breakpoint or signal. + +@node Stack, Source, Stopping, Top +@chapter Examining the Stack + +When your program has stopped, the first thing you need to know is where it +stopped and how it got there. + +@cindex call stack +Each time your program performs a function call, the information about +where in the program the call was made from is saved in a block of data +called a @dfn{stack frame}. The frame also contains the arguments of the +call and the local variables of the function that was called. All the +stack frames are allocated in a region of memory called the @dfn{call +stack}. + +When your program stops, the GDB commands for examining the stack allow you +to see all of this information. + +One of the stack frames is @dfn{selected} by GDB and many GDB commands +refer implicitly to the selected frame. In particular, whenever you ask +GDB for the value of a variable in the program, the value is found in the +selected frame. There are special GDB commands to select whichever frame +you are interested in. + +When the program stops, GDB automatically selects the currently executing +frame and describes it briefly as the @samp{frame} command does +(@pxref{Frame Info, Info}). + +@menu +* Frames:: Explanation of stack frames and terminology. +* Backtrace:: Summarizing many frames at once. +* Selection:: How to select a stack frame. +* Info: Frame Info, Commands to print information on stack frames. +@end menu + +@node Frames, Backtrace, Stack, Stack +@section Stack Frames + +@cindex frame +The call stack is divided up into contiguous pieces called @dfn{frames}; +each frame is the data associated with one call to one function. The frame +contains the arguments given to the function, the function's local +variables, and the address at which the function is executing. + +@cindex initial frame +@cindex outermost frame +@cindex innermost frame +When your program is started, the stack has only one frame, that of the +function @code{main}. This is called the @dfn{initial} frame or the +@dfn{outermost} frame. Each time a function is called, a new frame is +made. Each time a function returns, the frame for that function invocation +is eliminated. If a function is recursive, there can be many frames for +the same function. The frame for the function in which execution is +actually occurring is called the @dfn{innermost} frame. This is the most +recently created of all the stack frames that still exist. + +@cindex frame pointer +Inside your program, stack frames are identified by their addresses. A +stack frame consists of many bytes, each of which has its own address; each +kind of computer has a convention for choosing one of those bytes whose +address serves as the address of the frame. Usually this address is kept +in a register called the @dfn{frame pointer register} while execution is +going on in that frame. + +@cindex frame number +GDB assigns numbers to all existing stack frames, starting with zero for +the innermost frame, one for the frame that called it, and so on upward. +These numbers do not really exist in your program; they are to give you a +way of talking about stack frames in GDB commands. + +@cindex selected frame +Many GDB commands refer implicitly to one stack frame. GDB records a stack +frame that is called the @dfn{selected} stack frame; you can select any +frame using one set of GDB commands, and then other commands will operate +on that frame. When your program stops, GDB automatically selects the +innermost frame. + +@node Backtrace, Selection, Frames, Stack +@section Backtraces + +A backtrace is a summary of how the program got where it is. It shows one +line per frame, for many frames, starting with the currently executing +frame (frame zero), followed by its caller (frame one), and on up the +stack. + +@table @code +@item backtrace +@itemx bt +Print a backtrace of the entire stack: one line per frame for all +frames in the stack. + +You can stop the backtrace at any time by typing the system interrupt +character, normally @kbd{Control-C}. + +@item backtrace @var{n} +@itemx bt @var{n} +Similar, but stop after @var{n} frames. + +@item backtrace @var{-n} +@itemx bt @var{-n} +Similar, but print the outermost @var{n} frames instead of the +innermost. +@end table + +Each line in a backtrace shows the frame number, the program counter, the +function and its arguments, and the source file name and line number (if +known). The program counter is omitted if is the beginning of the code for +the source line. This is the same as the first of the two lines printed +when you select a frame. + +@node Selection, Frame Info, Backtrace, Stack +@section Selecting a Frame + +Most commands for examining the stack and other data in the program work on +whichever stack frame is selected at the moment. Here are the commands for +selecting a stack frame; all of them finish by printing a brief description +of the stack frame just selected. + +@table @code +@item frame @var{n} +@kindex frame +Select frame number @var{n}. Recall that frame zero is the innermost +(currently executing) frame, frame one is the frame that called the +innermost one, and so on. The highest-numbered frame is @code{main}'s +frame. + +@item frame @var{addr} +Select the frame at address @var{addr}. This is useful mainly if the +chaining of stack frames has been damaged by a bug, making it +impossible for GDB to assign numbers properly to all frames. In +addition, this can be useful when the program has multiple stacks and +switches between them. + +@item up @var{n} +@kindex up +Select the frame @var{n} frames up from the frame previously selected. +For positive numbers @var{n}, this advances toward the outermost +frame, to higher frame numbers, to frames that have existed longer. +@var{n} defaults to one. + +@item down @var{n} +@kindex down +Select the frame @var{n} frames down from the frame previously +selected. For positive numbers @var{n}, this advances toward the +innermost frame, to lower frame numbers, to frames that were created +more recently. @var{n} defaults to one. +@end table + +All of these commands end by printing some information on the frame that +has been selected: the frame number, the function name, the arguments, the +source file and line number of execution in that frame, and the text of +that source line. For example: + +@example +#3 main (argc=3, argv=??, env=??) at main.c, line 67 +67 read_input_file (argv[i]); +@end example + +After such a printout, the @samp{list} command with no arguments will print +ten lines centered on the point of execution in the frame. @xref{List}. + +@node Frame Info,, Selection, Stack +@section Information on a Frame + +There are several other commands to print information about the selected +stack frame. + +@table @code +@item frame +This command prints a brief description of the selected stack frame. +It can be abbreviated @samp{f}. With an argument, this command is +used to select a stack frame; with no argument, it does not change +which frame is selected, but still prints the same information. + +@item info frame +@kindex info frame +This command prints a verbose description of the selected stack frame, +including the address of the frame, the addresses of the next frame in +(called by this frame) and the next frame out (caller of this frame), +the address of the frame's arguments, the program counter saved in it +(the address of execution in the caller frame), and which registers +were saved in the frame. The verbose description is useful when +something has gone wrong that has made the stack format fail to fit +the usual conventions. + +@item info frame @var{addr} +Print a verbose description of the frame at address @var{addr}, +without selecting that frame. The selected frame remains unchanged by +this command. + +@item info args +@kindex info args +Print the arguments of the selected frame, each on a separate line. + +@item info locals +@kindex info locals +Print the local variables of the selected frame, each on a separate +line. These are all variables declared static or automatic within all +program blocks that execution in this frame is currently inside of. +@end table + +@node Source, Data, Stack, Top +@chapter Examining Source Files + +GDB knows which source files your program was compiled from, and +can print parts of their text. When your program stops, GDB +spontaneously prints the line it stopped in. Likewise, when you +select a stack frame (@pxref{Selection}), GDB prints the line +which execution in that frame has stopped in. You can also +print parts of source files by explicit command. + +@menu +* List:: Using the @samp{list} command to print source files. +* Search:: Commands for searching source files. +* Source Path:: Specifying the directories to search for source files. +@end menu + +@node List, Search, Source, Source +@section Printing Source Lines + +@kindex list +To print lines from a source file, use the @samp{list} command +(abbreviated @samp{l}). There are several ways to specify what part +of the file you want to print. + +Here are the forms of the @samp{list} command most commonly used: + +@table @code +@item list @var{linenum} +Print ten lines centered around line number @var{linenum} in the +current source file. + +@item list @var{function} +Print ten lines centered around the beginning of function +@var{function}. + +@item list +Print ten more lines. If the last lines printed were printed with a +@samp{list} command, this prints ten lines following the last lines +printed; however, if the last line printed was a solitary line printed +as part of displaying a stack frame (@pxref{Stack}), this prints ten +lines centered around that line. + +@item list @minus{} +Print ten lines just before the lines last printed. +@end table + +Repeating a @samp{list} command with @key{RET} discards the argument, +so it is equivalent to typing just @samp{list}. This is more useful +than listing the same lines again. An exception is made for an +argument of @samp{-}; that argument is preserved in repetition so that +each repetition moves up in the file. + +In general, the @samp{list} command expects you to supply zero, one or two +@dfn{linespecs}. Linespecs specify source lines; there are several ways +of writing them but the effect is always to specify some source line. +Here is a complete description of the possible arguments for @samp{list}: + +@table @code +@item list @var{linespec} +Print ten lines centered around the line specified by @var{linespec}. + +@item list @var{first},@var{last} +Print lines from @var{first} to @var{last}. Both arguments are +linespecs. + +@item list ,@var{last} +Print ten lines ending with @var{last}. + +@item list @var{first}, +Print ten lines starting with @var{first}. + +@item list + +Print ten lines just after the lines last printed. + +@item list @minus{} +Print ten lines just before the lines last printed. + +@item list +As described in the preceding table. +@end table + +Here are the ways of specifying a single source line---all the +kinds of linespec. + +@table @asis +@item @var{linenum} +Specifies line @var{linenum} of the current source file. +When a @samp{list} command has two linespecs, this refers to +the same source file as the first linespec. + +@item +@var{offset} +Specifies the line @var{offset} lines after the last line printed. +When used as the second linespec in a @samp{list} command that has +two, this specifies the line @var{offset} lines down from the +first linespec. + +@item @minus{}@var{offset} +Specifies the line @var{offset} lines before the last line printed. + +@item @var{filename}:@var{linenum} +Specifies line @var{linenum} in the source file @var{filename}. + +@item @var{function} +Specifies the line of the open-brace that begins the body of the +function @var{function}. + +@item @var{filename}:@var{function} +Specifies the line of the open-brace that begins the body of the +function @var{function} in the file @var{filename}. The file name is +needed with a function name only for disambiguation of identically +named functions in different source files. + +@item *@var{address} +Specifies the line containing the program address @var{address}. +@var{address} may be any expression. +@end table + +One other command is used to map source lines to program addresses. + +@table @code +@item info line @var{linenum} +@kindex info line +Print the starting and ending addresses of the compiled code for +source line @var{linenum}. + +@kindex $_ +The default examine address for the @samp{x} command is changed to the +starting address of the line, so that @samp{x/i} is sufficient to +begin examining the machine code (@pxref{Memory}). Also, this address +is saved as the value of the convenience variable @samp{$_} +(@pxref{Convenience Vars}). +@end table + +@node Search, Source Path, List, Source +@section Searching Source Files +@cindex searching +@kindex forward-search +@kindex reverse-search + +There are two commands for searching through the current source file for a +regular expression. + +The command @samp{forward-search @var{regexp}} checks each line, starting +with the one following the last line listed, for a match for @var{regexp}. +It lists the line that is found. You can abbreviate the command name +as @samp{fo}. + +The command @samp{reverse-search @var{regexp}} checks each line, starting +with the one before the last line listed and going backward, for a match +for @var{regexp}. It lists the line that is found. You can abbreviate +this command with as little as @samp{rev}. + +@node Source Path,, Search, Source +@section Specifying Source Directories + +@cindex source path +@cindex directories for source files +Executable programs do not record the directories of the source files they +were compiled from, just the names. GDB remembers a list of directories to +search for source files; this is called the @dfn{source path}. Each time +GDB wants a source file, it tries all the directories in the list, in the +order they are present in the list, until it finds a file with the desired +name. + +@kindex directory +When you start GDB, its source path contains just the current working +directory. To add other directories, use the @samp{directory} command. +@b{Note that the search path for executable files and the working directory +are @i{not} used for finding source files.} + +@table @code +@item directory @var{dirname} +Add directory @var{dirname} to the end of the source path. + +@item directory +Reset the source path to just the current working directory of GDB. +This requires confirmation. + +@samp{directory} with no argument can cause source files previously +found by GDB to be found in a different directory. To make this work +correctly, this command also clears out the tables GDB maintains +about the source files it has already found. + +@item info directories +@kindex info directories +Print the source path: show which directories it contains. +@end table + +Because the @samp{directory} command adds to the end of the source path, +it does not affect any file that GDB has already found. If the source +path contains directories that you do not want, and these directories +contain misleading files with names matching your source files, the +way to correct the situation is as follows: + +@enumerate +@item +Choose the directory you want at the beginning of the source path. +Use the @samp{cd} command to make that the current working directory. + +@item +Use @samp{directory} with no argument to reset the source path to just +that directory. + +@item +Use @samp{directory} with suitable arguments to add any other +directories you want in the source path. +@end enumerate + +@node Data, Symbols, Source, Top +@chapter Examining Data + +@cindex printing data +@cindex examining data +@kindex print +The usual way of examining data in your program is with the @samp{print} +command (abbreviated @samp{p}). It evaluates and prints the value of any +valid expression of the language the program is written in (for now, C). +You type + +@example +print @var{exp} +@end example + +@noindent +where @var{exp} is any valid expression, and the value of @var{exp} +is printed in a format appropriate to its data type. + +A more low-level way of examining data is with the @samp{x} command. +It examines data in memory at a specified address and prints it in a +specified format. + +GDB supports one command to modify the default format of displayed data: + +@table @samp +@item set array-max +@kindex set array-max +@samp{set array-max} sets the maximum number of elements of an array which +will be printed. This limit also applies to the display of strings. +@end table + +@menu +* Expressions:: Expressions that can be computed and printed. +* Variables:: Using your program's variables in expressions. +* Assignment:: Setting your program's variables. +* Arrays:: Examining part of memory as an array. +* Formats:: Specifying formats for printing values. +* Memory:: Examining memory explicitly. +* Auto Display:: Printing certain expressions whenever program stops. +* Value History:: Referring to values previously printed. +* Convenience Vars:: Giving names to values for future reference. +* Registers:: Referring to and storing in machine registers. +@end menu + +@node Expressions, Variables, Data, Data +@section Expressions + +@cindex expressions +Many different GDB commands accept an expression and compute its value. +Any kind of constant, variable or operator defined by the programming +language you are using is legal in an expression in GDB. This includes +conditional expressions, function calls, casts and string constants. +It unfortunately does not include symbols defined by preprocessor +#define commands. + +Casts are supported in all languages, not just in C, because it is so +useful to cast a number into a pointer so as to examine a structure +at that address in memory. + +GDB supports three kinds of operator in addition to those of programming +languages: + +@table @code +@item @@ +@samp{@@} is a binary operator for treating parts of memory as arrays. +@xref{Arrays}, for more information. + +@item :: +@samp{::} allows you to specify a variable in terms of the file or +function it is defined in. @xref{Variables}. + +@item @{@var{type}@} @var{addr} +Refers to an object of type @var{type} stored at address @var{addr} in +memory. @var{addr} may be any expression whose value is an integer or +pointer (but parentheses are required around nonunary operators, just as in +a cast). This construct is allowed regardless of what kind of data is +officially supposed to reside at @var{addr}.@refill +@end table + +@node Variables, Arrays, Expressions, Data +@section Program Variables + +The most common kind of expression to use is the name of a variable +in your program. + +Variables in expressions are understood in the selected stack frame +(@pxref{Selection}); they must either be global (or static) or be visible +according to the scope rules of the programming language from the point of +execution in that frame. This means that in the function + +@example +foo (a) + int a; +@{ + bar (a); + @{ + int b = test (); + bar (b); + @} +@} +@end example + +@noindent +the variable @code{a} is usable whenever the program is executing +within the function @code{foo}, but the variable @code{b} is visible +only while the program is executing inside the block in which @code{b} +is declared. + +As a special exception, you can refer to a variable or function whose +scope is a single source file even if the current execution point is not +in this file. But it is possible to have more than one such variable +or function with the same name (if they are in different source files). +In such a case, it is not defined which one you will get. If you wish, +you can specify any one of them using the colon-colon construct: + +@example +@var{block}::@var{variable} +@end example + +@noindent +Here @var{block} is the name of the source file whose variable you want. + +@node Arrays, Formats, Variables, Data +@section Artificial Arrays + +@cindex artificial array +It is often useful to print out several successive objects of the +same type in memory; a section of an array, or an array of +dynamically determined size for which only a pointer exists in the +program. + +This can be done by constructing an @dfn{artificial array} with the +binary operator @samp{@@}. The left operand of @samp{@@} should be +the first element of the desired array, as an individual object. +The right operand should be the length of the array. The result is +an array value whose elements are all of the type of the left argument. +The first element is actually the left argument; the second element +comes from bytes of memory immediately following those that hold the +first element, and so on. Here is an example. If a program says + +@example +int *array = (int *) malloc (len * sizeof (int)); +@end example + +@noindent +you can print the contents of @code{array} with + +@example +p *array@@len +@end example + +The left operand of @samp{@@} must reside in memory. Array values made +with @samp{@@} in this way behave just like other arrays in terms of +subscripting, and are coerced to pointers when used in expressions. +(It would probably appear in an expression via the value history, +after you had printed it out.) + +@node Formats, Memory, Arrays, Data +@section Formats + +@cindex formatted output +@cindex output formats +GDB normally prints all values according to their data types. Sometimes +this is not what you want. For example, you might want to print a number +in hex, or a pointer in decimal. Or you might want to view data in memory +at a certain address as a character string or an instruction. These things +can be done with @dfn{output formats}. + +The simplest use of output formats is to say how to print a value +already computed. This is done by starting the arguments of the +@samp{print} command with a slash and a format letter. The format +letters supported are: + +@table @samp +@item x +Regard the bits of the value as an integer, and print the integer in +hexadecimal. + +@item d +Print as integer in signed decimal. + +@item u +Print as integer in unsigned decimal. + +@item o +Print as integer in octal. + +@item a +Print as an address, both absolute in hex and then relative +to a symbol defined as an address below it. + +@item c +Regard as an integer and print it as a character constant. + +@item f +Regard the bits of the value as a floating point number and print +using typical floating point syntax. +@end table + +For example, to print the program counter in hex (@pxref{Registers}), type + +@example +p/x $pc +@end example + +@noindent +Note that no space is required before the slash; this is because command +names in GDB cannot contain a slash. + +To reprint the last value in the value history with a different format, +you can use the @samp{print} command with just a format and no +expression. For example, @samp{p/x} reprints the last value in hex. + +@node Memory, Auto Display, Formats, Data +@subsection Examining Memory + +@cindex examining memory +@kindex x +The command @samp{x} (for `examine') can be used to examine memory under +explicit control of formats, without reference to the program's data types. + +@samp{x} is followed by a slash and an output format specification, +followed by an expression for an address. The expression need not have +a pointer value (though it may); it is used as an integer, as the +address of a byte of memory. @xref{Expressions} for more information +on expressions. + +The output format in this case specifies both how big a unit of memory +to examine and how to print the contents of that unit. It is done +with one or two of the following letters: + +These letters specify just the size of unit to examine: + +@table @samp +@item b +Examine individual bytes. + +@item h +Examine halfwords (two bytes each). + +@item w +Examine words (four bytes each). + +@cindex word +Many assemblers and cpu designers still use `word' for a 16-bit quantity, +as a holdover from specific predecessor machines of the 1970's that really +did use two-byte words. But more generally the term `word' has always +referred to the size of quantity that a machine normally operates on and +stores in its registers. This is 32 bits for all the machines that GNU +runs on. + +@item g +Examine giant words (8 bytes). +@end table + +These letters specify just the way to print the contents: + +@table @samp +@item x +Print as integers in unsigned hexadecimal. + +@item d +Print as integers in signed decimal. + +@item u +Print as integers in unsigned decimal. + +@item o +Print as integers in unsigned octal. + +@item a +Print as an address, both absolute in hex and then relative +to a symbol defined as an address below it. + +@item c +Print as character constants. + +@item f +Print as floating point. This works only with sizes @samp{w} and +@samp{g}. + +@item s +Print a null-terminated string of characters. The specified unit size +is ignored; instead, the unit is however many bytes it takes to reach +a null character (including the null character). + +@item i +Print a machine instruction in assembler syntax (or nearly). The +specified unit size is ignored; the number of bytes in an instruction +varies depending on the type of machine, the opcode and the addressing +modes used. +@end table + +If either the manner of printing or the size of unit fails to be specified, +the default is to use the same one that was used last. If you don't want +to use any letters after the slash, you can omit the slash as well. + +You can also omit the address to examine. Then the address used is +just after the last unit examined. This is why string and instruction +formats actually compute a unit-size based on the data: so that the +next string or instruction examined will start in the right place. +The @samp{print} command sometimes sets the default address for +the @samp{x} command; when the value printed resides in memory, the +default is set to examine the same location. @samp{info line} also +sets the default for @samp{x}, to the address of the start of the +machine code for the specified line and @samp{info breakpoints} sets +it to the address of the last breakpoint listed. + +When you use @key{RET} to repeat an @samp{x} command, it does not repeat +exactly the same: the address specified previously (if any) is ignored, so +that the repeated command examines the successive locations in memory +rather than the same ones. + +You can examine several consecutive units of memory with one command by +writing a repeat-count after the slash (before the format letters, if any). +The repeat count must be a decimal integer. It has the same effect as +repeating the @samp{x} command that many times except that the output may +be more compact with several units per line. + +@example +x/10i $pc +@end example + +@noindent +Prints ten instructions starting with the one to be executed next in the +selected frame. After doing this, you could print another ten following +instructions with + +@example +x/10 +@end example + +@noindent +in which the format and address are allowed to default. + +@kindex $_ +@kindex $__ +The addresses and contents printed by the @samp{x} command are not put in +the value history because there is often too much of them and they would +get in the way. Instead, GDB makes these values available for subsequent +use in expressions as values of the convenience variables @samp{$_} and +@samp{$__}. + +After an @samp{x} command, the last address examined is available for use +in expressions in the convenience variable @samp{$_}. The contents of that +address, as examined, are available in the convenience variable @samp{$__}. + +If the @samp{x} command has a repeat count, the address and contents saved +are from the last memory unit printed; this is not the same as the last +address printed if several units were printed on the last line of output. + +@node Auto Display, Value History, Memory, Data +@section Automatic Display + +If you find that you want to print the value of an expression frequently +(to see how it changes), you might want to add it to the @dfn{automatic +display list} so that GDB will print its value each time the program stops. +Each expression added to the list is given a number to identify it; +to remove an expression from the list, you specify that number. +The automatic display looks like this: + +@example +2: foo = 38 +3: bar[5] = (struct hack *) 0x3804 +@end example + +@noindent +showing item numbers, expressions and their current values. + +@table @code +@item display @var{exp} +@kindex display +Add the expression @var{exp} to the list of expressions to display +each time the program stops. @xref{Expressions}. + +@item display/@var{fmt} @var{exp} +For @var{fmt} specifying only a display format and not a size or +count, add the expression @var{exp} to the auto-display list but +arranges to display it each time in the specified format @var{fmt}. + +@item display/@var{fmt} @var{addr} +For @var{fmt} @samp{i} or @samp{s}, or including a unit-size or a +number of units, add the expression @var{addr} as a memory address to +be examined each time the program stops. Examining means in effect +doing @samp{x/@var{fmt} @var{addr}}. @xref{Memory}. + +@item undisplay @var{dnums}@dots{} +@kindex undisplay +@item delete display @var{dnums}@dots{} +@kindex delete display +Remove item numbers @var{dnums} from the list of expressions to display. + +@item disable display @var{dnums}@dots{} +@kindex disable display +Disable the display of item numbers @var{dnums}. A disabled display item +has no effect but is not forgotten. It may be later enabled. + +@item enable display @var{dnums}@dots{} +@kindex enable display +Enable display of item numbers @var{dnums}. It becomes effective once +again in auto display of its expression, until you specify otherwise. + +@item display +Display the current values of the expressions on the list, just as is +done when the program stops. + +@item info display +@kindex info display +Print the list of expressions to display automatically, each one +with its item number, but without showing the values. +@end table + +@node Value History, Convenience Vars, Auto Display, Data +@section Value History + +@cindex value history +Every value printed by the @samp{print} command is saved for the entire +session in GDB's @dfn{value history} so that you can refer to it in +other expressions. + +@cindex $ +@cindex $$ +The values printed are given @dfn{history numbers} for you to refer to them +by. These are successive integers starting with 1. @samp{print} shows you +the history number assigned to a value by printing @samp{$@var{n} = } +before the value; here @var{n} is the history number. + +To refer to any previous value, use @samp{$} followed by the value's +history number. The output printed by @samp{print} is designed to remind +you of this. Just @samp{$} refers to the most recent value in the history, +and @samp{$$} refers to the value before that. + +For example, suppose you have just printed a pointer to a structure and +want to see the contents of the structure. It suffices to type + +@example +p *$ +@end example + +If you have a chain of structures where the component @samp{next} points +to the next one, you can print the contents of the next one with + +@example +p *$.next +@end example + +It might be useful to repeat this command many times by typing @key{RET}. + +Note that the history records values, not expressions. If the value of +@code{x} is 4 and you type + +@example +print x +set x=5 +@end example + +@noindent +then the value recorded in the value history by the @samp{print} command +remains 4 even though @code{x}'s value has changed. + +@table @code +@item info history +@kindex info history +Print the last ten values in the value history, with their item +numbers. This is like @samp{p $$9} repeated ten times, except that +@samp{info history} does not change the history. + +@item info history @var{n} +Print ten history values centered on history item number @var{n}. +@end table + +@node Convenience Vars, Registers, Value History, Data +@section Convenience Variables + +@cindex convenience variables +GDB provides @dfn{convenience variables} that you can use within GDB to +hold on to a value and refer to it later. These variables exist entirely +within GDB; they are not part of your program, and setting a convenience +variable has no effect on further execution of your program. That's why +you can use them freely. + +Convenience variables have names starting with @samp{$}. Any name starting +with @samp{$} can be used for a convenience variable, unless it is one of +the predefined set of register names (@pxref{Registers}). + +You can save a value in a convenience variable with an assignment +expression, just as you would set a variable in your program. Example: + +@example +set $foo = *object_ptr +@end example + +@noindent +would save in @samp{$foo} the value contained in the object pointed to by +@code{object_ptr}. + +Using a convenience variable for the first time creates it; but its value +is @code{void} until you assign a new value. You can alter the value with +another assignment at any time. + +Convenience variables have no fixed types. You can assign a convenience +variable any type of value, even if it already has a value of a different +type. The convenience variable as an expression has whatever type its +current value has. + +@table @code +@item info convenience +@kindex info convenience +Print a list of convenience variables used so far, and their values. +Abbreviated @samp{i con}. +@end table + +One of the ways to use a convenience variable is as a counter to be +incremented or a pointer to be advanced. For example: + +@example +set $i = 0 +print bar[$i++]->contents +@i{@dots{}repeat that command by typing @key{RET}.} +@end example + +Some convenience variables are created automatically by GDB and given +values likely to be useful. + +@table @samp +@item $_ +The variable @samp{$_} is automatically set by the @samp{x} command to +the last address examined (@pxref{Memory}). Other commands which +provide a default address for @samp{x} to examine also set @samp{$_} +to that address; these commands include @samp{info line} and @samp{info +breakpoint}. + +@item $__ +The variable @samp{$__} is automatically set by the @samp{x} command +to the value found in the last address examined. +@end table + +@node Registers,, Convenience Vars, Data +@section Registers + +@cindex registers +Machine register contents can be referred to in expressions as variables +with names starting with @samp{$}. The names of registers are different +for each machine; use @samp{info registers} to see the names used on your +machine. The names @samp{$pc} and @samp{$sp} are used on all machines for +the program counter register and the stack pointer. Often @samp{$fp} is +used for a register that contains a pointer to the current stack frame. + +GDB always considers the contents of an ordinary register as an integer +when the register is examined in this way. Some machines have special +registers which can hold nothing but floating point; these registers are +considered floating point. There is no way to refer to the contents of an +ordinary register as floating point value (although you can @emph{print} +it as a floating point value with @samp{print/f $@var{regname}}). + +Some registers have distinct ``raw'' and ``virtual'' data formats. This +means that the data format in which the register contents are saved by the +operating system is not the same one that your program normally sees. For +example, the registers of the 68881 floating point coprocessor are always +saved in ``extended'' format, but virtually all C programs expect to work with +``double'' format. In such cases, GDB normally works with the virtual +format only (the format that makes sense for your program), but the +@samp{info registers} command prints the data in both formats. + +Register values are relative to the selected stack frame +(@pxref{Selection}). This means that you get the value that the register +would contain if all stack frames farther in were exited and their saved +registers restored. In order to see the real contents of all registers, +you must select the innermost frame (with @samp{frame 0}). + +Some registers are never saved (typically those numbered zero or one) +because they are used for returning function values; for these registers, +relativization makes no difference. + +@table @code +@item info registers +@kindex info registers +Print the names and relativized values of all registers. + +@item info registers @var{regname} +Print the relativized value of register @var{regname}. @var{regname} +may be any register name valid on the machine you are using, with +or without the initial @samp{$}. +@end table + +@subsection Examples + +You could print the program counter in hex with + +@example +p/x $pc +@end example + +@noindent +or print the instruction to be executed next with + +@example +x/i $pc +@end example + +@noindent +or add four to the stack pointer with + +@example +set $sp += 4 +@end example + +@noindent +The last is a way of removing one word from the stack, on machines where +stacks grow downward in memory (most machines, nowadays). This assumes +that the innermost stack frame is selected. Setting @samp{$sp} is +not allowed when other stack frames are selected. + +@node Symbols, Altering, Data, Top +@chapter Examining the Symbol Table + +The commands described in this section allow you to make inquiries for +information about the symbols (names of variables, functions and types) +defined in your program. This information is found by GDB in the symbol +table loaded by the @samp{symbol-file} command; it is inherent in the text +of your program and does not change as the program executes. + +@table @code +@item whatis @var{exp} +@kindex whatis +Print the data type of expression @var{exp}. @var{exp} is not +actually evaluated, and any side-effecting operations (such as +assignments or function calls) inside it do not take place. +@xref{Expressions}. + +@item whatis +Print the data type of @samp{$}, the last value in the value history. + +@item info address @var{symbol} +@kindex info address +Describe where the data for @var{symbol} is stored. For register +variables, this says which register. For other automatic variables, +this prints the stack-frame offset at which the variable is always +stored. Note the contrast with @samp{print &@var{symbol}}, which does +not work at all for register variables and for automatic variables +prints the exact address of the current instantiation of the variable. + +@item ptype @var{typename} +@kindex ptype +Print a description of data type @var{typename}. @var{typename} may be +the name of a type, or for C code it may have the form +@samp{struct @var{struct-tag}}, @samp{union @var{union-tag}} or +@samp{enum @var{enum-tag}}.@refill + +@item info sources +@kindex info sources +Print the names of all source files in the program for which there +is debugging information. + +@item info functions +@kindex info functions +Print the names and data types of all defined functions. + +@item info functions @var{regexp} +Print the names and data types of all defined functions +whose names contain a match for regular expression @var{regexp}. +Thus, @samp{info fun step} finds all functions whose names +include @samp{step}; @samp{info fun ^step} finds those whose names +start with @samp{step}. + +@item info variables +@kindex info variables +Print the names and data types of all variables that are declared +outside of functions. + +@item info variables @var{regexp} +Print the names and data types of all variables, declared outside of +functions, whose names contain a match for regular expression +@var{regexp}. + +@item info types +@kindex info types +Print all data types that are defined in the program. + +@item info types @var{regexp} +Print all data types that are defined in the program whose names +contain a match for regular expression @var{regexp}. + +@item info methods +@item info methods @var{regexp} +@kindex info methods +The @samp{info-methods} command permits the user to examine all defined +methods within C@code{++} program, or (with the @var{regexp} argument) a +specific set of methods found in the various C@code{++} classes. Many +C@code{++} classes which implement a large number of differently typed +methods implement a large number of methods as well. Thus, the +@samp{ptype} command can give the user a tremendous overdose of +information about what methods are associated with a given class. The +@samp{info-methods} command filters these methods do to only those +methods which match the regular-expression search key. + +@item printsyms @var{filename} +@kindex printsyms +Write a complete dump of the debugger's symbol data into the +file @var{filename}. +@end table + +@node Altering, Sequences, Symbols, Top +@chapter Altering Execution + +There are several ways to alter the execution of your program with GDB +commands. + +@menu +* Assignment:: Altering variable values or memory contents. +* Jumping:: Altering control flow. +* Signaling:: Making signals happen in the program. +* Returning:: Making a function return prematurely. +@end menu + +@node Assignment, Jumping, Altering, Altering +@section Assignment to Variables + +@cindex assignment +@cindex setting variables +To alter the value of a variable, evaluate an assignment expression. +@xref{Expressions}. For example, + +@example +print x=4 +@end example + +@noindent +would store the value 4 into the variable @code{x}, and then print +the value of the assignment expression (which is 4). + +@kindex set +@kindex set variable +If you are not interested in seeing the value of the assignment, use the +@samp{set} command instead of the @samp{print} command. @samp{set} is +really the same as @samp{print} except that the expression's value is not +printed and is not put in the value history (@pxref{Value History}). The +expression is evaluated only for side effects. + +Note that if the beginning of the argument string of the @samp{set} command +appears identical to a @samp{set} subcommand, it may be necessary to use +the @samp{set variable} command. This command is identical to @samp{set} +except for its lack of subcommands. + +GDB allows more implicit conversions in assignments than C does; you can +freely store an integer value into a pointer variable or vice versa, and +any structure can be converted to any other structure that is the same +length or shorter. + +In C, all the other assignment operators such as @samp{+=} and @samp{++} +are supported as well. + +To store into arbitrary places in memory, use the @samp{@{@dots{}@}} +construct to generate a value of specified type at a specified address +(@pxref{Expressions}). For example, + +@example +set @{int@}0x83040 = 4 +@end example + +@node Jumping, Signaling, Assignment, Altering +@section Continuing at a Different Address + +@table @code +@item jump @var{linenum} +@kindex jump +Resume execution at line number @var{linenum}. Execution may stop +immediately if there is a breakpoint there. + +The @samp{jump} command does not change the current stack frame, or +the stack pointer, or the contents of any memory location or any +register other than the program counter. If line @var{linenum} is in +a different function from the one currently executing, the results may +be wild if the two functions expect different patterns of arguments or +of local variables. For this reason, the @samp{jump} command requests +confirmation if the specified line is not in the function currently +executing. However, even wild results are predictable based on +changing the program counter. + +@item jump *@var{address} +Resume execution at the instruction at address @var{address}. +@end table + +A similar effect can be obtained by storing a new value into the register +@samp{$pc}, but not exactly the same. + +@example +set $pc = 0x485 +@end example + +@noindent +specifies the address at which execution will resume, but does not resume +execution. That does not happen until you use the @samp{cont} command or a +stepping command (@pxref{Stepping}). + +@node Signaling, Returning, Jumping, Altering +@section Giving the Program a Signal + +@table @code +@item signal @var{signalnum} +@kindex signal +Resume execution where the program stopped, but give it immediately +the signal number @var{signalnum}. + +Alternatively, if @var{signalnum} is zero, continue execution and give +no signal. This is useful when the program has received a signal +but you don't want the program to see that signal; the @samp{cont} command +would signal the program. +@end table + +@node Returning,, Signaling, Altering +@section Returning from a Function + +@cindex returning from a function +@kindex return +You can make any function call return immediately, using the @samp{return} +command. + +First select the stack frame that you wish to return from +(@pxref{Selection}). Then type the @samp{return} command. If you wish to +specify the value to be returned, give that as an argument. + +This pops the selected stack frame (and any other frames inside of it), +leaving its caller as the innermost remaining frame. That frame becomes +selected. The specified value is stored in the registers used for +returning values of functions. + +The @samp{return} command does not resume execution; it leaves the program +stopped in the state that would exist if the function had just returned. +Contrast this with the @samp{finish} command (@pxref{Stepping}), which +resumes execution @i{until} the selected stack frame returns naturally. + +@node Sequences, Emacs, Altering, Top +@chapter Canned Sequences of Commands + +GDB provides two ways to store sequences of commands for execution as a +unit: user-defined commands and command files. + +@menu +* Define:: User-defined commands. +* Command Files:: Command files. +* Output:: Controlled output commands useful in + user-defined commands and command files. +@end menu + +@node Define, Command Files, Sequences, Sequences +@section User-Defined Commands + +@cindex user-defined commands +A @dfn{user-defined command} is a sequence of GDB commands to which you +assign a new name as a command. This is done with the @samp{define} +command. + +@table @code +@item define @var{commandname} +@kindex define +Define a command named @var{commandname}. If there is already a command +by that name, you are asked to confirm that you want to redefine it. + +The definition of the command is made up of other GDB command lines, +which are given following the @samp{define} command. The end of these +commands is marked by a line containing @samp{end}. + +@item document @var{commandname} +@kindex document +Give documentation to the user-defined command @var{commandname}. The +command @var{commandname} must already be defined. This command reads +lines of documentation just as @samp{define} reads the lines of the +command definition, ending with @samp{end}. After the @samp{document} command is finished, +@samp{help} on command @var{commandname} will print the documentation +you have specified. + +You may use the @samp{document} command again to change the +documentation of a command. Redefining the command with @samp{define} +does not change the documentation. +@end table + +User-defined commands do not take arguments. When they are executed, the +commands of the definition are not printed. An error in any command +stops execution of the user-defined command. + +Commands that would ask for confirmation if used interactively proceed +without asking when used inside a user-defined command. Many GDB commands +that normally print messages to say what they are doing omit the messages +when used in user-defined command. + +@node Command Files, Output, Define, Sequences +@section Command Files + +@cindex command files +A command file for GDB is a file of lines that are GDB commands. Comments +(lines starting with @samp{#}) may also be included. An empty line in a +command file does nothing; it does not mean to repeat the last command, as +it would from the terminal. + +@cindex init file +@cindex .gdbinit +When GDB starts, it automatically executes its @dfn{init files}, command +files named @file{.gdbinit}. GDB reads the init file (if any) in your home +directory and then the init file (if any) in the current working +directory. (The init files are not executed if the @samp{-nx} option +is given.) You can also request the execution of a command file with the +@samp{source} command: + +@table @code +@item source @var{filename} +@kindex source +Execute the command file @var{filename}. +@end table + +The lines in a command file are executed sequentially. They are not +printed as they are executed. An error in any command terminates execution +of the command file. + +Commands that would ask for confirmation if used interactively proceed +without asking when used in a command file. Many GDB commands that +normally print messages to say what they are doing omit the messages +when used in a command file. + +@node Output,, Command Files, Sequences +@section Commands for Controlled Output + +During the execution of a command file or a user-defined command, the only +output that appears is what is explicitly printed by the commands of the +definition. This section describes three commands useful for generating +exactly the output you want. + +@table @code +@item echo @var{text} +@kindex echo +Print @var{text}. Nonprinting characters can be included in +@var{text} using C escape sequences, such as @samp{\n} to print a +newline. @b{No newline will be printed unless you specify one.} + +A backslash at the end of @var{text} is ignored. It is useful for +outputting a string ending in spaces, since trailing spaces are +trimmed from all arguments. A backslash at the beginning preserves +leading spaces in the same way, because @samp{\ } as an escape +sequence stands for a space. Thus, to print @samp{ and foo = }, do + +@example +echo \ and foo = \ +@end example + +@item output @var{expression} +@kindex output +Print the value of @var{expression} and nothing but that value: no +newlines, no @samp{$@var{nn} = }. The value is not entered in the +value history either. @xref{Expressions} for more information +on expressions. + +@item output/@var{fmt} @var{expression} +Print the value of @var{expression} in format @var{fmt}. +@xref{Formats}, for more information. + +@item printf @var{string}, @var{expressions}@dots{} +@kindex printf +Print the values of the @var{expressions} under the control of +@var{string}. The @var{expressions} are separated by commas and may +be either numbers or pointers. Their values are printed as specified +by @var{string}, exactly as if the program were to execute + +@example +printf (@var{string}, @var{expressions}@dots{}); +@end example + +For example, you can print two values in hex like this: + +@example +printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo +@end example + +The only backslash-escape sequences that you can use in the string are +the simple ones that consist of backslash followed by a letter. +@end table + +@node Emacs, Remote, Sequences, Top +@chapter Using GDB under GNU Emacs + +A special interface allows you to use GNU Emacs to view (and +edit) the source files for the program you are debugging with +GDB. + +To use this interface, use the command @kbd{M-x gdb} in Emacs. +Give the executable file you want to debug as an argument. This +command starts a GDB process as a subprocess of Emacs, with input +and output through a newly created Emacs buffer. + +Using this GDB process is just like using GDB normally except for two things: + +@itemize @bullet +@item +All ``terminal'' input and output goes through the Emacs buffer. This +applies both to GDB commands and their output, and to the input and +output done by the program you are debugging. + +This is useful because it means that you can copy the text of previous +commands and input them again; you can even use parts of the output +in this way. + +All the facilities of Emacs's Shell mode are available for this purpose. + +@item +GDB displays source code through Emacs. Each time GDB displays a +stack frame, Emacs automatically finds the source file for that frame +and puts an arrow (@samp{=>}) at the left margin of the current line. + +Explicit GDB @samp{list} or search commands still produce output as +usual, but you probably will have no reason to use them. +@end itemize + +In the GDB I/O buffer, you can use these special Emacs commands: + +@table @kbd +@item M-s +Execute to another source line, like the GDB @samp{step} command. + +@item M-n +Execute to next source line in this function, skipping all function +calls, like the GDB @samp{next} command. + +@item M-i +Execute one instruction, like the GDB @samp{stepi} command. + +@item M-u +Move up one stack frame (and display that frame's source file in +Emacs), like the GDB @samp{up} command. + +@item M-d +Move down one stack frame (and display that frame's source file in +Emacs), like the GDB @samp{down} command. (This means that you cannot +delete words in the usual fashion in the GDB buffer; I am guessing you +won't often want to do that.) + +@item C-c C-f +Execute until exit from the selected stack frame, like the GDB +@samp{finish} command. +@end table + +In any source file, the Emacs command @kbd{C-x SPC} (@code{gdb-break}) +tells GDB to set a breakpoint on the source line point is on. + +The source files displayed in Emacs are in ordinary Emacs buffers +which are visiting the source files in the usual way. You can edit +the files with these buffers if you wish; but keep in mind that GDB +communicates with Emacs in terms of line numbers. If you add or +delete lines from the text, the line numbers that GDB knows will cease +to correspond properly to the code. + +@node Remote, Commands, Emacs, Top +@chapter Remote Kernel Debugging + +GDB has a special facility for debugging a remote machine via a serial +connection. This can be used for kernel debugging. + +The program to be debugged on the remote machine needs to contain a +debugging device driver which talks to GDB over the serial line using the +protocol described below. The same version of GDB that is used ordinarily +can be used for this. + +@menu +* Remote Commands:: Commands used to start and finish remote debugging. +@end menu + +For details of the communication protocol, see the comments in the GDB +source file @file{remote.c}. + +@node Remote Commands,, Remote, Remote +@section Commands for Remote Debugging + +To start remote debugging, first run GDB and specify as an executable file +the program that is running in the remote machine. This tells GDB how +to find the program's symbols and the contents of its pure text. Then +establish communication using the @samp{attach} command with a device +name rather than a pid as an argument. For example: + +@example +attach /dev/ttyd +@end example + +@noindent +if the serial line is connected to the device named @file{/dev/ttyd}. This +will stop the remote machine if it is not already stopped. + +Now you can use all the usual commands to examine and change data and to +step and continue the remote program. + +To resume the remote program and stop debugging it, use the @samp{detach} +command. + +@node Commands, Concepts, Remote, Top +@unnumbered Command Index + +@printindex ky + +@node Concepts,, Commands, Top +@unnumbered Concept Index + +@printindex cp + +@contents +@bye diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h new file mode 100644 index 0000000..b03e66c --- /dev/null +++ b/gdb/gdbcore.h @@ -0,0 +1,68 @@ +/* Machine independent variables that describe the core file under GDB. + Copyright (C) 1986, 1987, 1989 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! +*/ + +/* 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; diff --git a/gdb/getpagesize.h b/gdb/getpagesize.h new file mode 100644 index 0000000..32adae6 --- /dev/null +++ b/gdb/getpagesize.h @@ -0,0 +1,25 @@ +#ifdef BSD +#ifndef BSD4_1 +#define HAVE_GETPAGESIZE +#endif +#endif + +#ifndef HAVE_GETPAGESIZE + +#include + +#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/gdb/gld-pinsn.c b/gdb/gld-pinsn.c index 947c979..1567180 100644 --- a/gdb/gld-pinsn.c +++ b/gdb/gld-pinsn.c @@ -192,14 +192,14 @@ print_insn (memaddr, stream) * Find the number of arguments to a function. */ findarg(frame) - struct frame_info frame; + struct frame_info *frame; { register struct symbol *func; register unsigned pc; #ifdef notdef /* find starting address of frame function */ - pc = get_pc_function_start (frame.pc); + pc = get_pc_function_start (frame->pc); /* find function symbol info */ func = find_pc_function (pc); @@ -220,29 +220,35 @@ findarg(frame) * 1.) stored in the code function header xA(Br1). * 2.) must be careful of recurssion. */ +FRAME_ADDR findframe(thisframe) FRAME thisframe; { - register FRAME pointer; - struct frame_info frame; + register FRAME_ADDR pointer; +#if 0 + struct frame_info *frame; + FRAME_ADDR framechain(); /* Setup toplevel frame structure */ - frame.pc = read_pc(); - frame.next_frame = 0; - frame.frame = read_register (SP_REGNUM); /* Br2 */ + frame->pc = read_pc(); + frame->next_frame = 0; + frame->frame = read_register (SP_REGNUM); /* Br2 */ /* Search for this frame (start at current Br2) */ do { pointer = framechain(frame); - frame.next_frame = frame.frame; - frame.frame = pointer; - frame.pc = FRAME_SAVED_PC(frame.next_frame); + frame->next_frame = frame->frame; + frame->frame = pointer; + frame->pc = FRAME_SAVED_PC(frame); } - while (frame.next_frame != thisframe); + while (frame->next_frame != thisframe); +#endif + + pointer = framechain (thisframe); /* stop gap for now, end at __base3 */ - if (frame.pc == 0) + if (thisframe->pc == 0) return 0; return pointer; @@ -252,20 +258,21 @@ findframe(thisframe) * Gdb front-end and internal framechain routine. * Go back up stack one level. Tricky... */ +FRAME_ADDR framechain(frame) - register struct frame_info frame; + register struct frame_info *frame; { register CORE_ADDR func, prevsp; register unsigned value; /* Get real function start address from internal frame address */ - func = get_pc_function_start(frame.pc); + func = get_pc_function_start(frame->pc); /* If no stack given, read register Br1 "(sp)" */ - if (!frame.frame) + if (!frame->frame) prevsp = read_register (SP_REGNUM); else - prevsp = frame.frame; + prevsp = frame->frame; /* Check function header, case #2 */ value = read_memory_integer (func, 4); diff --git a/gdb/gould-dep.c b/gdb/gould-dep.c new file mode 100644 index 0000000..c078ec1 --- /dev/null +++ b/gdb/gould-dep.c @@ -0,0 +1,550 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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); + } + } +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes 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. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#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; + +#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) + { + 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. */ + core_aouthdr.a_magic = 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) + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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; + + FILHDR exec_coffhdr; + + val = myread (execchan, &exec_coffhdr, sizeof exec_coffhdr); + if (val < 0) + perror_with_name (filename); + + 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_coffhdr, exec_aouthdr); + exec_data_offset = N_TXTOFF (exec_coffhdr, 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); +} diff --git a/gdb/hp-include/a.out.h b/gdb/hp-include/a.out.h new file mode 100644 index 0000000..85d4275 --- /dev/null +++ b/gdb/hp-include/a.out.h @@ -0,0 +1,132 @@ +/* Special version of for use under hp-ux. + Copyright (C) 1988 Free Software Foundation, Inc. */ + +/* The `exec' structure and overall layout must be close to HP's when + we are running on an HP system, otherwise we will not be able to + execute the resulting file. */ + +/* Allow this file to be included twice. */ +#ifndef EXEC_PAGESIZE + +struct exec + { + unsigned short a_machtype; /* machine type */ + unsigned short a_magic; /* magic number */ + unsigned long a_spare1; + unsigned long a_spare2; + unsigned long a_text; /* size of text segment */ + unsigned long a_data; /* size of data segment */ + unsigned long a_bss; /* size of bss segment */ + unsigned long a_trsize; /* text relocation size */ + unsigned long a_drsize; /* data relocation size */ + unsigned long a_spare3; /* HP = pascal interface size */ + unsigned long a_spare4; /* HP = symbol table size */ + unsigned long a_spare5; /* HP = debug name table size */ + unsigned long a_entry; /* entry point */ + unsigned long a_spare6; /* HP = source line table size */ + unsigned long a_spare7; /* HP = value table size */ + unsigned long a_syms; /* symbol table size */ + unsigned long a_spare8; + }; + +#define OMAGIC 0x107 +#define NMAGIC 0x108 +#define ZMAGIC 0x10B + +#define N_BADTYPE(x) \ + ((((x) . a_magic) != OMAGIC) \ + && (((x) . a_magic) != NMAGIC) \ + && (((x) . a_magic) != ZMAGIC)) + +#define HP98x6_ID 0x20A +#define HP9000S200_ID 0x20C + +#define N_BADMACH(x) \ + ((((x) . a_machtype) != HP9000S200_ID) \ + && (((x) . a_machtype) != HP98x6_ID)) + +#define N_BADMAG(x) ((N_BADTYPE (x)) || (N_BADMACH (x))) + +#define EXEC_PAGESIZE 0x1000 + +#define EXEC_ALIGN(offset) \ + (((offset) + (EXEC_PAGESIZE - 1)) & (~ (EXEC_PAGESIZE - 1))) + +#define N_TXTOFF(x) \ + ((((x) . a_magic) == ZMAGIC) \ + ? (EXEC_ALIGN (sizeof (struct exec))) \ + : (sizeof (struct exec))) + +#define N_DATOFF(x) \ + ((((x) . a_magic) == ZMAGIC) \ + ? ((EXEC_ALIGN (sizeof (struct exec))) \ + + (EXEC_ALIGN ((x) . a_text))) \ + : ((sizeof (struct exec)) + ((x) . a_text))) + +#define N_TROFF(x) \ + ((((x) . a_magic) == ZMAGIC) \ + ? ((EXEC_ALIGN (sizeof (struct exec))) \ + + (EXEC_ALIGN ((x) . a_text)) \ + + (EXEC_ALIGN ((x) . a_data))) \ + : ((sizeof (struct exec)) + ((x) . a_text) + ((x) . a_data))) + +#define N_SYMOFF(x) ((N_TROFF (x)) + ((x) . a_trsize) + ((x) . a_drsize)) + +#define N_STROFF(x) ((N_SYMOFF (x)) + ((x) . a_syms)) + +/* Macros which take exec structures as arguments and tell where the + various pieces will be loaded. */ + +#define N_TXTADDR(x) 0 + +#define N_DATADDR(x) \ + ((((x) . a_magic) == OMAGIC) \ + ? ((x) . a_text) \ + : (EXEC_ALIGN ((x) . a_text))) + +#define N_BSSADDR(x) ((N_DATADDR (x)) + ((x) . a_data)) + +struct relocation_info + { + long r_address; /* address which is relocated */ + unsigned int + r_symbolnum : 24, /* local symbol ordinal */ + r_pcrel : 1, /* was relocated pc relative already */ + r_length : 2, /* 0=byte, 1=word, 2=long */ + r_extern : 1, /* does not include value of sym referenced */ + : 4; /* nothing, yet */ + }; + +struct nlist + { + union + { + char *n_name; /* for use when in-core */ + long n_strx; /* index into file string table */ + } n_un; + unsigned char n_type; /* type flag (N_TEXT,..) */ + char n_other; /* unused */ + short n_desc; /* see */ + unsigned long n_value; /* value of symbol (or sdb offset) */ + }; + +/* Simple values for n_type. */ +#define N_UNDF 0x00 /* undefined */ +#define N_ABS 0x02 /* absolute */ +#define N_TEXT 0x04 /* text */ +#define N_DATA 0x06 /* data */ +#define N_BSS 0x08 /* bss */ +#define N_COMM 0x12 /* common (internal to ld) */ +#define N_FN 0x1F /* file name symbol */ + +#define N_EXT 0x01 /* external bit, or'ed in */ +#define N_TYPE 0x1E /* mask for all the type bits */ + +/* dbx entries have some of the N_STAB bits set. + These are given in */ +#define N_STAB 0xE0 /* if any of these bits set, a dbx symbol */ + +/* Format for namelist values. */ +#define N_FORMAT "%08x" + +#endif /* EXEC_PAGESIZE */ diff --git a/gdb/hp-include/stab.h b/gdb/hp-include/stab.h new file mode 100644 index 0000000..9741fdc --- /dev/null +++ b/gdb/hp-include/stab.h @@ -0,0 +1,47 @@ +/* @(#)stab.h 1.1 86/07/07 SMI; from UCB X.X XX/XX/XX */ + + +/* IF YOU ADD DEFINITIONS, ADD THEM TO nm.c as well */ +/* + * This file gives definitions supplementing + * for permanent symbol table entries. + * These must have one of the N_STAB bits on, + * and are subject to relocation according to the masks in . + */ +/* + * for symbolic debugger, sdb(1): + */ +#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */ +#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */ +#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */ +#define N_STSYM 0x26 /* static symbol: name,,0,type,address */ +#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */ +#define N_MAIN 0x2a /* name of main routine : name,,0,0,0 */ +#define N_RSYM 0x40 /* register sym: name,,0,type,register */ +#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */ +#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */ +#define N_SO 0x64 /* source file name: name,,0,0,address */ +#define N_LSYM 0x80 /* local sym: name,,0,type,offset */ +#define N_BINCL 0x82 /* header file: name,,0,0,0 */ +#define N_SOL 0x84 /* #included file name: name,,0,0,address */ +#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ +#define N_EINCL 0xa2 /* end of include file */ +#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */ +#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */ +#define N_EXCL 0xc2 /* excluded include file */ +#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */ +#define N_BCOMM 0xe2 /* begin common: name,, */ +#define N_ECOMM 0xe4 /* end common: name,, */ +#define N_ECOML 0xe8 /* end common (local name): ,,address */ +#define N_LENG 0xfe /* second stab entry with length information */ + +/* + * for the berkeley pascal compiler, pc(1): + */ +#define N_PC 0x30 /* global pascal symbol: name,,0,subtype,line */ + +/* + * for modula-2 compiler only + */ +#define N_M2C 0x42 /* compilation unit stab */ +#define N_SCOPE 0xc4 /* scope information */ diff --git a/gdb/hp-include/sys/fcntl.h b/gdb/hp-include/sys/fcntl.h new file mode 100644 index 0000000..6d94600 --- /dev/null +++ b/gdb/hp-include/sys/fcntl.h @@ -0,0 +1,73 @@ +/* @(#)fcntl.h 1.3 86/07/16 SMI; from UCB 5.1 85/05/30 */ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef __FCNTL_HEADER__ +#define __FCNTL_HEADER__ + +/* + * Flag values accessible to open(2) and fcntl(2) + * (The first three can only be set by open) + */ +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_NDELAY FNDELAY /* Non-blocking I/O */ +#define O_APPEND FAPPEND /* append (writes guaranteed at the end) */ +#define O_CREAT FCREAT /* open with file create */ +#define O_TRUNC FTRUNC /* open with truncation */ +#define O_EXCL FEXCL /* error on create if file exists */ + +/* flags for F_GETFL, F_SETFL-- needed by */ +#define FNDELAY 00004 /* non-blocking reads */ +#define FAPPEND 00010 /* append on each write */ +#define FASYNC 00100 /* signal pgrp when data ready */ +#define FCREAT 01000 /* create if nonexistant */ +#define FTRUNC 02000 /* truncate to zero length */ +#define FEXCL 04000 /* error if already created */ + +/* fcntl(2) requests */ +#define F_DUPFD 0 /* Duplicate fildes */ +#define F_GETFD 1 /* Get fildes flags */ +#define F_SETFD 2 /* Set fildes flags */ +#define F_GETFL 3 /* Get file flags */ +#define F_SETFL 4 /* Set file flags */ +#define F_GETOWN 5 /* Get owner */ +#define F_SETOWN 6 /* Set owner */ +#define F_GETLK 7 /* Get record-locking information */ +#define F_SETLK 8 /* Set or Clear a record-lock (Non-Blocking) */ +#define F_SETLKW 9 /* Set or Clear a record-lock (Blocking) */ + +/* access(2) requests */ +#define F_OK 0 /* does file exist */ +#define X_OK 1 /* is it executable by caller */ +#define W_OK 2 /* writable by caller */ +#define R_OK 4 /* readable by caller */ + +/* System-V record-locking options */ +/* lockf(2) requests */ +#define F_ULOCK 0 /* Unlock a previously locked region */ +#define F_LOCK 1 /* Lock a region for exclusive use */ +#define F_TLOCK 2 /* Test and lock a region for exclusive use */ +#define F_TEST 3 /* Test a region for other processes locks */ + +/* fcntl(2) flags (l_type field of flock structure) */ +#define F_RDLCK 1 /* read lock */ +#define F_WRLCK 2 /* write lock */ +#define F_UNLCK 3 /* remove lock(s) */ + + +/* file segment locking set data type - information passed to system by user */ +struct flock { + short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */ + short l_whence; /* flag to choose starting offset */ + long l_start; /* relative offset, in bytes */ + long l_len; /* length, in bytes; 0 means lock to EOF */ + short l_pid; /* returned with F_GETLK */ + short l_xxx; /* reserved for future use */ +}; + +#endif !__FCNTL_HEADER__ diff --git a/gdb/hp9k320-dep.c b/gdb/hp9k320-dep.c new file mode 100644 index 0000000..2774303 --- /dev/null +++ b/gdb/hp9k320-dep.c @@ -0,0 +1,643 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#define WOPR +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +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"); + } +} + +#define INFERIOR_AR0(u) \ + ((ptrace \ + (PT_RUAREA, inferior_pid, ((char *) &u.u_ar0 - (char *) &u), 0)) \ + - KERNEL_U_ADDR) + +static void +fetch_inferior_register (regno, regaddr) + register int regno; + register unsigned int regaddr; +{ +#ifndef HPUX_VERSION_5 + if (regno == PS_REGNUM) + { + union { int i; short s[2]; } ps_val; + int regval; + + ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0)); + regval = ps_val.s[0]; + supply_register (regno, ®val); + } + else +#endif /* not HPUX_VERSION_5 */ + { + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (PT_RUAREA, inferior_pid, regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } + return; +} + +static void +store_inferior_register_1 (regno, regaddr, value) + int regno; + unsigned int regaddr; + int value; +{ + errno = 0; + ptrace (PT_WUAREA, inferior_pid, regaddr, value); +#if 0 + /* HP-UX randomly sets errno to non-zero for regno == 25. + However, the value is correctly written, so ignore errno. */ + if (errno != 0) + { + char string_buf[64]; + + sprintf (string_buf, "writing register number %d", regno); + perror_with_name (string_buf); + } +#endif + return; +} + +static void +store_inferior_register (regno, regaddr) + register int regno; + register unsigned int regaddr; +{ +#ifndef HPUX_VERSION_5 + if (regno == PS_REGNUM) + { + union { int i; short s[2]; } ps_val; + + ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0)); + ps_val.s[0] = (read_register (regno)); + store_inferior_register_1 (regno, regaddr, ps_val.i); + } + else +#endif /* not HPUX_VERSION_5 */ + { + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + extern char registers[]; + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + store_inferior_register_1 + (regno, regaddr, + (*(int *) ®isters[(REGISTER_BYTE (regno)) + i])); + regaddr += sizeof (int); + } + } + return; +} + +void +fetch_inferior_registers () +{ + struct user u; + register int regno; + register unsigned int ar0_offset; + + ar0_offset = (INFERIOR_AR0 (u)); + for (regno = 0; (regno < FP0_REGNUM); regno++) + fetch_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + for (; (regno < NUM_REGS); regno++) + fetch_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); +} + +/* 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) + register int regno; +{ + struct user u; + register unsigned int ar0_offset; + + if (regno >= FP0_REGNUM) + { + store_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); + return; + } + + ar0_offset = (INFERIOR_AR0 (u)); + if (regno >= 0) + { + store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + return; + } + + for (regno = 0; (regno < FP0_REGNUM); regno++) + store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + for (; (regno < NUM_REGS); regno++) + store_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); + return; +} + + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes 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. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#endif + +#ifdef HPUX_VERSION_5 +#define e_PS e_regs[PS] +#define e_PC e_regs[PC] +#endif /* HPUX_VERSION_5 */ + + +#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 +#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; + +#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) + { + 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. */ + core_aouthdr.a_magic = 0; + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + struct exception_stack es; + int val; + + val = lseek (corechan, (REGISTER_ADDR (reg_offset, 0)), 0); + if (val < 0) + perror_with_name (filename); + val = myread (corechan, es, + ((char *) &es.e_offset - (char *) &es.e_regs[R0])); + if (val < 0) + perror_with_name (filename); + for (regno = 0; (regno < PS_REGNUM); regno++) + supply_register (regno, &es.e_regs[regno + R0]); + val = es.e_PS; + supply_register (regno++, &val); + supply_register (regno++, &es.e_PC); + for (; (regno < NUM_REGS); regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, (FP_REGISTER_ADDR (u, regno)), 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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; + + 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); +} + diff --git a/gdb/i386-dep.c b/gdb/i386-dep.c new file mode 100644 index 0000000..23a553a --- /dev/null +++ b/gdb/i386-dep.c @@ -0,0 +1,1203 @@ +/* Low level interface to ptrace, for GDB when running on the Intel 386. + Copyright (C) 1988 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include +#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 +#include + +#include + +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 +#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; + +#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) + { + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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); +} + +/* + * parse the first few instructions of the function to see + * what registers were stored. + * + * We handle these cases: + * + * The startup sequence can be at the start of the function, + * or the function can start with a branch to startup code at the end. + * + * %ebp can be set up with either the 'enter' instruction, or + * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful, + * but was once used in the sys5 compiler) + * + * Local space is allocated just below the saved %ebp by either the + * 'enter' instruction, or by 'subl $, %esp'. 'enter' has + * a 16 bit unsigned argument for space to allocate, and the + * 'addl' instruction could have either a signed byte, or + * 32 bit immediate. + * + * Next, the registers used by this function are pushed. In + * the sys5 compiler they will always be in the order: %edi, %esi, %ebx + * (and sometimes a harmless bug causes it to also save but not restore %eax); + * however, the code below is willing to see the pushes in any order, + * and will handle up to 8 of them. + * + * If the setup sequence is at the end of the function, then the + * next instruction will be a branch back to the start. + */ + +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + 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 */ +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); +} + +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; + /* fpstate defined in */ + 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.u_fpstate - (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/gdb/i386-pinsn.c b/gdb/i386-pinsn.c new file mode 100644 index 0000000..437d44d --- /dev/null +++ b/gdb/i386-pinsn.c @@ -0,0 +1,1813 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988 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! +*/ + +/* + * 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 +#include + +#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 (""); + 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 (""); + 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 = ""; + 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 (""); + 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 (""); + 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 (""); + 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 (""); + 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/gdb/infcmd.c b/gdb/infcmd.c index 4f7230c..086e1f3 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -19,9 +19,8 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" -#include "initialize.h" -#include "symtab.h" #include "param.h" +#include "symtab.h" #include "frame.h" #include "inferior.h" #include "environ.h" @@ -59,7 +58,7 @@ CORE_ADDR stop_pc; /* Stack frame when program stopped. */ -FRAME stop_frame; +FRAME_ADDR stop_frame_address; /* Number of breakpoint it stopped at, or 0 if none. */ @@ -73,6 +72,11 @@ int stop_step; 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. */ @@ -84,7 +88,7 @@ CORE_ADDR step_range_end; /* Exclusive */ 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. */ -CORE_ADDR step_frame; +FRAME_ADDR step_frame_address; /* 1 means step over all subroutine calls. -1 means step over calls to undebuggable functions. */ @@ -105,7 +109,6 @@ struct environ *inferior_environ; CORE_ADDR read_pc (); struct command_line *get_breakpoint_commands (); -START_FILE int have_inferior_p () @@ -150,11 +153,11 @@ run_command (args, from_tty) if (inferior_pid) { - if (query ("The program being debugged has been started already.\n\ + if ( + !query ("The program being debugged has been started already.\n\ Start it from the beginning? ")) - kill_inferior (); - else - error ("Program already started."); + error ("Program not restarted."); + kill_inferior (); } if (remote_debugging) @@ -200,7 +203,7 @@ cont_command (proc_count_exp, from_tty) /* If have argument, set proceed count of breakpoint we stopped at. */ - if (stop_breakpoint && proc_count_exp) + if (stop_breakpoint > 0 && proc_count_exp) { set_ignore_count (stop_breakpoint, parse_and_eval_address (proc_count_exp) - 1, @@ -261,21 +264,36 @@ step_1 (skip_subroutines, single_inst, count_string) { clear_proceed_status (); - step_frame = get_current_frame (); + 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 (); - error ("Current function has no line number information."); + 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. */ + Don't step through subroutine calls even to undebuggable + functions. */ step_range_start = step_range_end = 1; if (!skip_subroutines) step_over_calls = 0; @@ -307,7 +325,7 @@ jump_command (arg, from_tty) if (!arg) error_no_arg ("starting address"); - sals = decode_line_spec (arg, 1); + sals = decode_line_spec_1 (arg, 1); if (sals.nelts != 1) { error ("Unreasonable jump request"); @@ -393,20 +411,6 @@ run_stack_dummy (addr, buffer) CORE_ADDR addr; REGISTER_TYPE *buffer; { - int saved_pc_changed = pc_changed; - int saved_stop_signal = stop_signal; - int saved_stop_pc = stop_pc; - int saved_stop_frame = stop_frame; - int saved_stop_breakpoint = stop_breakpoint; - int saved_stop_step = stop_step; - int saved_stop_stack_dummy = stop_stack_dummy; - FRAME saved_selected_frame; - int saved_selected_level; - struct command_line *saved_breakpoint_commands - = get_breakpoint_commands (); - - record_selected_frame (&saved_selected_frame, &saved_selected_level); - /* Now proceed, having reached the desired place. */ clear_proceed_status (); if (stack_dummy_testing & 4) @@ -419,21 +423,86 @@ run_stack_dummy (addr, buffer) if (!stop_stack_dummy) error ("Cannot continue previously requested operation."); - set_breakpoint_commands (saved_breakpoint_commands); - select_frame (saved_selected_frame, saved_selected_level); - stop_signal = saved_stop_signal; - stop_pc = saved_stop_pc; - stop_frame = saved_stop_frame; - stop_breakpoint = saved_stop_breakpoint; - stop_step = saved_stop_step; - stop_stack_dummy = saved_stop_stack_dummy; - pc_changed = saved_pc_changed; - /* On return, the stack dummy has been popped already. */ bcopy (stop_registers, buffer, sizeof stop_registers); } +/* 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. */ @@ -444,8 +513,7 @@ finish_command (arg, from_tty) { struct symtab_and_line sal; register FRAME frame; - struct frame_info fi; - + struct frame_info *fi; register struct symbol *function; if (!have_inferior_p ()) @@ -460,14 +528,14 @@ finish_command (arg, from_tty) clear_proceed_status (); fi = get_frame_info (frame); - sal = find_pc_line (fi.pc, 0); - sal.pc = fi.pc; + 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 (fi.next_frame, fi.next_next_frame); - function = find_pc_function (fi.pc); + fi = get_frame_info (selected_frame); + function = find_pc_function (fi->pc); if (from_tty) { @@ -481,12 +549,22 @@ finish_command (arg, from_tty) { struct type *value_type; register value val; + CORE_ADDR funcaddr; value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); + if (!value_type) + fatal ("internal: finish_command: function has no target type"); + if (TYPE_CODE (value_type) == TYPE_CODE_VOID) return; - val = value_being_returned (value_type, stop_registers); + funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function)); + + val = value_being_returned (value_type, stop_registers, + using_struct_return (function, + funcaddr, + value_type)); + printf ("Value returned is $%d = ", record_latest_value (val)); value_print (val, stdout, 0); putchar ('\n'); @@ -506,7 +584,7 @@ program_info () inferior_pid, stop_pc); if (stop_step) printf ("It stopped after being stepped.\n"); - else if (stop_breakpoint) + 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", @@ -540,30 +618,58 @@ 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) - p = arg + min (p - arg, val - arg); + { + /* 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 == 0) - error ("Space or \"=\" must separate variable name and its value"); - if (p[1] == 0) - error_no_arg ("value for the variable"); if (p == arg) error_no_arg ("environment variable to set"); - val = p + 1; - while (*val == ' ' || *val == '\t') val++; + 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); - set_in_environ (inferior_environ, var, val); + 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); } @@ -579,6 +685,7 @@ unset_environment_command (var) /* Read an integer from debugged memory, given address and number of bytes. */ +long read_memory_integer (memaddr, len) CORE_ADDR memaddr; int len; @@ -617,6 +724,7 @@ read_pc () return (CORE_ADDR) read_register (PC_REGNUM); } +void write_pc (val) CORE_ADDR val; { @@ -635,6 +743,9 @@ registers_info (addr_exp) register int i; 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') @@ -669,7 +780,7 @@ registers_info (addr_exp) { printf ("--Type Return to print more--"); fflush (stdout); - read_line (); + gdb_read_line (0, 0); } /* Get the data in raw format, then convert also to virtual format. */ @@ -681,7 +792,8 @@ registers_info (addr_exp) /* 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); + val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, + stdout, 0, 1); /* 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)) @@ -824,16 +936,31 @@ detach_command (args, from_tty) inferior_pid = 0; } #endif /* ATTACH_DETACH */ + +/* ARGUSUED */ +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 +} -static -initialize () +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_com ("set-args", class_run, set_args_command, + 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."); +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\ @@ -841,14 +968,17 @@ 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_com ("unset-environment", class_run, unset_environment_command, + 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."); - add_com ("set-environment", class_run, set_environment_command, +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."); +This does not affect the program until the next \"run\" command.", + &setlist); #ifdef ATTACH_DETACH add_com ("attach", class_run, attach_command, @@ -892,6 +1022,12 @@ Argument N means do this N times (or till program stops for another reason)."); 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\ @@ -919,9 +1055,11 @@ 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); } -END_FILE diff --git a/gdb/inferior.h b/gdb/inferior.h index 8fa1c19..c2d6e95 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -19,6 +19,40 @@ 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! */ +/* + * 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 stop_registers[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; @@ -41,7 +75,7 @@ extern CORE_ADDR stop_pc; /* Stack frame when program stopped. */ -extern FRAME stop_frame; +extern FRAME_ADDR stop_frame_address; /* Number of breakpoint it stopped at, or 0 if none. */ @@ -55,6 +89,11 @@ extern int stop_step; 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. */ @@ -66,7 +105,7 @@ extern CORE_ADDR step_range_end; /* Exclusive */ 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 CORE_ADDR step_frame; +extern FRAME_ADDR step_frame_address; /* 1 means step over all subroutine calls. -1 means step over calls to undebuggable functions. */ @@ -87,3 +126,6 @@ extern char stop_registers[REGISTER_BYTES]; since the inferior stopped. */ extern int pc_changed; + + +long read_memory_integer (); diff --git a/gdb/inflow.c b/gdb/inflow.c index 11e5e92..19da996 100644 --- a/gdb/inflow.c +++ b/gdb/inflow.c @@ -17,40 +17,20 @@ 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! */ - #include "defs.h" -#include "initialize.h" #include "param.h" #include "frame.h" #include "inferior.h" +#ifdef USG +#include +#include +#endif + #include #include #include -#ifndef UMAX_PTRACE -#include -#endif #include -#include -#include - -#ifdef UMAX_PTRACE -#include -#include -#define PTRACE_ATTACH PT_ATTACH -#define PTRACE_DETACH PT_FREEPROC -#endif - -#ifdef NEW_SUN_PTRACE -#include -#include -#endif - -#ifdef HP9K320 -#include -#include -#include -#endif #ifdef HAVE_TERMIO #include @@ -62,34 +42,48 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define TIOCSETP TCSETAF #define TERMINAL struct termio #else +#include +#include #include #define TERMINAL struct sgttyb #endif +#ifdef SET_STACK_LIMIT_HUGE +#include +#include +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. */ -static int attach_flag; +int attach_flag; -START_FILE /* Record terminal status separately for debugger and inferior. */ static TERMINAL sg_inferior; static TERMINAL sg_ours; + static int tflags_inferior; static int tflags_ours; -#ifdef TIOCGLTC +#ifdef TIOCGETC static struct tchars tc_inferior; static struct tchars tc_ours; +#endif + +#ifdef TIOCGLTC static struct ltchars ltc_inferior; static struct ltchars ltc_ours; +#endif /* TIOCGLTC */ + +#ifdef TIOCLGET static int lmode_inferior; static int lmode_ours; -#endif /* TIOCGLTC */ +#endif #ifdef TIOCGPGRP static int pgrp_inferior; @@ -120,11 +114,17 @@ terminal_init_inferior () sg_inferior = sg_ours; tflags_inferior = tflags_ours; -#ifdef TIOCGLTC +#ifdef TIOCGETC tc_inferior = tc_ours; +#endif + +#ifdef TIOCGLTC ltc_inferior = ltc_ours; +#endif + +#ifdef TIOCLGET lmode_inferior = lmode_ours; -#endif /* TIOCGLTC */ +#endif #ifdef TIOCGPGRP pgrp_inferior = inferior_pid; @@ -147,18 +147,21 @@ terminal_inferior () fcntl (0, F_SETFL, tflags_inferior); fcntl (0, F_SETFL, tflags_inferior); ioctl (0, TIOCSETN, &sg_inferior); - -#ifdef TIOCGLTC +#ifdef TIOCGETC ioctl (0, TIOCSETC, &tc_inferior); +#endif +#ifdef TIOCGLTC ioctl (0, TIOCSLTC, <c_inferior); +#endif +#ifdef TIOCLGET ioctl (0, TIOCLSET, &lmode_inferior); -#endif /* TIOCGLTC */ +#endif #ifdef TIOCGPGRP ioctl (0, TIOCSPGRP, &pgrp_inferior); #else - sigint_ours = (signal (SIGINT, SIG_IGN)); - sigquit_ours = (signal (SIGQUIT, SIG_IGN)); + sigint_ours = (int (*) ()) signal (SIGINT, SIG_IGN); + sigquit_ours = (int (*) ()) signal (SIGQUIT, SIG_IGN); #endif /* TIOCGPGRP */ } terminal_is_ours = 0; @@ -222,11 +225,15 @@ terminal_ours_1 (output_only) tflags_inferior = fcntl (0, F_GETFL, 0); ioctl (0, TIOCGETP, &sg_inferior); -#ifdef TIOCGLTC +#ifdef TIOCGETC ioctl (0, TIOCGETC, &tc_inferior); +#endif +#ifdef TIOCGLTC ioctl (0, TIOCGLTC, <c_inferior); +#endif +#ifdef TIOCLGET ioctl (0, TIOCLGET, &lmode_inferior); -#endif /* TIOCGLTC */ +#endif } #ifdef HAVE_TERMIO @@ -243,11 +250,15 @@ terminal_ours_1 (output_only) fcntl (0, F_SETFL, tflags_ours); ioctl (0, TIOCSETN, &sg_ours); -#ifdef TIOCGLTC +#ifdef TIOCGETC ioctl (0, TIOCSETC, &tc_ours); +#endif +#ifdef TIOCGLTC ioctl (0, TIOCSLTC, <c_ours); +#endif +#ifdef TIOCLGET ioctl (0, TIOCLSET, &lmode_ours); -#endif /* TIOCGLTC */ +#endif #ifdef HAVE_TERMIO @@ -283,18 +294,29 @@ term_status_command () #else /* not HAVE_TERMIO */ - printf ("fcntl flags = 0x%x, lmode = 0x%x,\nsgttyb.sg_flags = 0x%x, owner pid = %d.\n", - tflags_inferior, lmode_inferior, - sg_inferior.sg_flags, pgrp_inferior); + printf ("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 */ + +#ifdef TIOCGETC printf ("tchars: "); for (i = 0; i < sizeof (struct tchars); i++) printf ("0x%x ", ((char *)&tc_inferior)[i]); printf ("\n"); +#endif + +#ifdef TIOCGLTC printf ("ltchars: "); for (i = 0; i < sizeof (struct ltchars); i++) printf ("0x%x ", ((char *)<c_inferior)[i]); + printf ("\n"); + ioctl (0, TIOCSLTC, <c_ours); +#endif -#endif /* not HAVE_TERMIO */ +#ifdef TIOCLGET + printf ("lmode: %x\n", lmode_inferior); +#endif } static void @@ -304,11 +326,7 @@ new_tty (ttyname) register int tty; register int fd; -#if 0 - /* I think it is better not to do this. Then C-z on the GDB terminal - will still stop the program, while C-z on the data terminal - will be input. */ - +#ifdef TIOCNOTTY /* Disconnect the child process from our controlling terminal. */ tty = open("/dev/tty", O_RDWR); if (tty > 0) @@ -317,6 +335,7 @@ new_tty (ttyname) close(tty); } #endif + /* Now open the specified new terminal. */ tty = open(ttyname, O_RDWR); @@ -361,19 +380,29 @@ create_inferior (allargs, env) /* exec is said to fail if the executable is open. */ close_exec_file (); - pid = vfork (); + pid = fork (); if (pid < 0) - perror_with_name ("vfork"); + perror_with_name ("fork"); if (pid == 0) { - char *args[4]; - #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); @@ -383,14 +412,8 @@ create_inferior (allargs, env) /*??? signal (SIGQUIT, SIG_DFL); signal (SIGINT, SIG_DFL); */ - ptrace (0); - - args[0] = "sh"; - args[1] = "-c"; - args[2] = shell_command; - args[3] = 0; - - execve (SHELL_FILE, args, env); + 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"); @@ -414,538 +437,17 @@ kill_command () kill_inferior (); } -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); -} - +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 (read_register (FP_REGNUM)); -} - -/* 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 - { -#ifdef NO_SINGLE_STEP - if (step) - { - single_step (signal); - } - else ptrace (7, inferior_pid, 1, signal); -#else - ptrace (step ? 9 : 7, inferior_pid, 1, signal); -#endif - if (errno) - perror_with_name ("ptrace"); - } -} - -#ifdef ATTACH_DETACH - -/* Start debugging the process whose number is PID. */ - -attach (pid) - int pid; -{ - errno = 0; - ptrace (PTRACE_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 (PTRACE_DETACH, inferior_pid, 1, signal); - if (errno) - perror_with_name ("ptrace"); - attach_flag = 0; -} -#endif /* ATTACH_DETACH */ - -#ifdef NEW_SUN_PTRACE - -void -fetch_inferior_registers () -{ - struct regs inferior_registers; - struct fp_status inferior_fp_registers; - extern char registers[]; - - if (remote_debugging) - remote_fetch_registers (registers); - else - { - ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); - ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); - -#if defined(sun2) || defined(sun3) - bcopy (&inferior_registers, registers, 16 * 4); - bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], - sizeof inferior_fp_registers.fps_regs); - *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; - *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; - bcopy (&inferior_fp_registers.fps_control, - ®isters[REGISTER_BYTE (FPC_REGNUM)], - sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); -#endif -#if defined(sun4) - registers[REGISTER_BYTE (0)] = 0; - bcopy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (1)], 15 * 4); - bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], - sizeof inferior_fp_registers.fpu_fr); - *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; - *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; - *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc; - *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y; -/* *(int *)®isters[REGISTER_BYTE (RP_REGNUM)] = - inferior_registers.r_o7 + 8; - bcopy (&inferior_fp_registers.Fpu_fsr, - ®isters[REGISTER_BYTE (FPS_REGNUM)], - sizeof (FPU_FSR_TYPE)); */ - read_inferior_memory (inferior_registers.r_sp, - ®isters[REGISTER_BYTE (16)], - 16*4); -#endif - } -} - -/* Store our register values back into the inferior. - If REGNO is -1, do this for all registers. - Otherwise, REGNO specifies which register (so we can save time). */ - -store_inferior_registers (regno) - int regno; -{ - struct regs inferior_registers; - struct fp_status inferior_fp_registers; - extern char registers[]; - - if (remote_debugging) - remote_store_registers (registers); - else - { - int in_regs = 1, in_fpregs = 1, in_fparegs, in_cpregs = 1; - -#if defined(sun2) || defined(sun3) - if (in_regs) - { - bcopy (registers, &inferior_registers, 16 * 4); - inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; - inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; - } - if (in_fpregs) - { - bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, - sizeof inferior_fp_registers.fps_regs); - bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], - &inferior_fp_registers.fps_control, - sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); - } - if (in_regs) - ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); - if (in_fpregs) - ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); -#endif -#if defined(sun4) - if (regno >= 0) - if (FP0_REGNUM <= regno && regno <= FP0_REGNUM + 32) - in_regs = 0; - else - in_fpregs = 0; - - if (in_regs) - { - bcopy (®isters[REGISTER_BYTE (1)], &inferior_registers.r_g1, 15 * 4); - inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; - inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; - inferior_registers.r_npc = *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)]; - inferior_registers.r_y = *(int *)®isters[REGISTER_BYTE (Y_REGNUM)]; - write_inferior_memory (*(int *)®isters[REGISTER_BYTE (SP_REGNUM)], - ®isters[REGISTER_BYTE (16)], - 16*4); - } - if (in_fpregs) - { - bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, - sizeof inferior_fp_registers.fpu_fr); - /* bcopy (®isters[REGISTER_BYTE (FPS_REGNUM)], - &inferior_fp_registers.Fpu_fsr, - sizeof (FPU_FSR_TYPE)); - ****/ - } - - if (in_regs) - ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); - if (in_fpregs) - ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); -#endif - } -} - -#else -#ifdef HP9K320 - -#define FP_REGISTER_ADDR_DIFF(u, regno) \ - (((char *) (FP_REGISTER_ADDR (u, regno))) - ((char *) &(u))) - -#define INFERIOR_AR0(u) \ - ((ptrace \ - (PT_RUAREA, inferior_pid, ((char *) &u.u_ar0 - (char *) &u), 0)) \ - - KERNEL_U_ADDR) - -static void -fetch_inferior_register (regno, regaddr) - register int regno; - register unsigned int regaddr; -{ -#ifndef HPUX_VERSION_5 - if (regno == PS_REGNUM) - { - union { int i; short s[2]; } ps_val; - int regval; - - ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0)); - regval = ps_val.s[0]; - supply_register (regno, ®val); - } - else -#endif /* not HPUX_VERSION_5 */ - { - char buf[MAX_REGISTER_RAW_SIZE]; - register int i; - - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) - { - *(int *) &buf[i] = ptrace (PT_RUAREA, inferior_pid, regaddr, 0); - regaddr += sizeof (int); - } - supply_register (regno, buf); - } - return; -} - -static void -store_inferior_register_1 (regno, regaddr, value) - int regno; - unsigned int regaddr; - int value; -{ - errno = 0; - ptrace (PT_WUAREA, inferior_pid, regaddr, value); -#if 0 - /* HP-UX randomly sets errno to non-zero for regno == 25. - However, the value is correctly written, so ignore errno. */ - if (errno != 0) - { - char string_buf[64]; - - sprintf (string_buf, "writing register number %d", regno); - perror_with_name (string_buf); - } -#endif - return; -} - -static void -store_inferior_register (regno, regaddr) - register int regno; - register unsigned int regaddr; -{ -#ifndef HPUX_VERSION_5 - if (regno == PS_REGNUM) - { - union { int i; short s[2]; } ps_val; - - ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0)); - ps_val.s[0] = (read_register (regno)); - store_inferior_register_1 (regno, regaddr, ps_val.i); - } - else -#endif /* not HPUX_VERSION_5 */ - { - char buf[MAX_REGISTER_RAW_SIZE]; - register int i; - extern char registers[]; - - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) - { - store_inferior_register_1 - (regno, regaddr, - (*(int *) ®isters[(REGISTER_BYTE (regno)) + i])); - regaddr += sizeof (int); - } - } - return; -} - -void -fetch_inferior_registers () -{ - struct user u; - register int regno; - register unsigned int ar0_offset; - - ar0_offset = (INFERIOR_AR0 (u)); - for (regno = 0; (regno < FP0_REGNUM); regno++) - fetch_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); - for (; (regno < NUM_REGS); regno++) - fetch_inferior_register (regno, (FP_REGISTER_ADDR_DIFF (u, regno))); -} - -/* 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) - register int regno; -{ - struct user u; - register unsigned int ar0_offset; - - if (regno >= FP0_REGNUM) - { - store_inferior_register (regno, (FP_REGISTER_ADDR_DIFF (u, regno))); - return; - } - - ar0_offset = (INFERIOR_AR0 (u)); - if (regno >= 0) - { - store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); - return; - } - - for (regno = 0; (regno < FP0_REGNUM); regno++) - store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); - for (; (regno < NUM_REGS); regno++) - store_inferior_register (regno, (FP_REGISTER_ADDR_DIFF (u, regno))); - return; -} - -#else /* not HP9K320 */ - -void -fetch_inferior_registers () -{ - register int regno; - register unsigned int regaddr; - char buf[MAX_REGISTER_RAW_SIZE]; - register int i; - -#ifdef UMAX_PTRACE - unsigned int offset = 0; -#else - struct user u; - unsigned int offset = (char *) &u.u_ar0 - (char *) &u; - offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; -#endif - - 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]; - extern char registers[]; - int i; - -#ifdef UMAX_PTRACE - unsigned int offset = 0; -#else - struct user u; - unsigned int offset = (char *) &u.u_ar0 - (char *) &u; - offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; -#endif - - if (regno >= 0) - { - regaddr = register_addr (regno, offset); - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) - { - errno = 0; - ptrace (6, inferior_pid, 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 (6, inferior_pid, 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); - } - } -} - -#endif /* not HP9K320 */ -#endif /* not NEW_SUN_PTRACE */ - -/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory - in the NEW_SUN_PTRACE case. - It ought to be straightforward. But it appears that writing did - not write the data that I specified. I cannot understand where - it got the data that it actually did write. */ - -/* Copy LEN bytes from inferior's memory starting at MEMADDR - to debugger memory starting at MYADDR. */ - -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)); - - /* Read all the longwords */ - for (i = 0; i < count; i++, addr += sizeof (int)) - { - if (remote_debugging) - buffer[i] = remote_fetch_word (addr); - else - buffer[i] = ptrace (1, inferior_pid, addr, 0); - } - - /* Copy appropriate bytes out of the buffer. */ - bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); -} - -/* 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; + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); } static void @@ -962,8 +464,8 @@ try_writing_regs_command () { QUIT; errno = 0; - value = ptrace (3, inferior_pid, i, 0); - ptrace (6, inferior_pid, i, value); + 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", @@ -974,8 +476,8 @@ try_writing_regs_command () } } -static -initialize () +void +_initialize_inflow () { add_com ("term-status", class_obscure, term_status_command, "Print info on inferior's saved terminal status."); @@ -992,11 +494,15 @@ Report which ones can be written."); ioctl (0, TIOCGETP, &sg_ours); fcntl (0, F_GETFL, tflags_ours); -#ifdef TIOCGLTC +#ifdef TIOCGETC ioctl (0, TIOCGETC, &tc_ours); +#endif +#ifdef TIOCGLTC ioctl (0, TIOCGLTC, <c_ours); +#endif +#ifdef TIOCLGET ioctl (0, TIOCLGET, &lmode_ours); -#endif /* TIOCGLTC */ +#endif #ifdef TIOCGPGRP ioctl (0, TIOCGPGRP, &pgrp_ours); @@ -1005,4 +511,3 @@ Report which ones can be written."); terminal_is_ours = 1; } -END_FILE diff --git a/gdb/infrun.c b/gdb/infrun.c index 67b0c17..d08a1bf 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -18,8 +18,106 @@ 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! */ +/* 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 "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "frame.h" @@ -28,12 +126,23 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include #include -#include + +/* unistd.h is needed to #define X_OK */ +#ifdef USG +#include +#else +#include +#endif + +/* The idiots at Apple only define X_OK if POSIX is defined. Fuck 'em. */ +#ifndef X_OK +#define X_OK 1 /* Execute permission for access() */ +#endif #ifdef UMAX_PTRACE #include #include -#endif UMAX_PTRACE +#endif /* UMAX_PTRACE */ extern char *sys_siglist[]; extern int errno; @@ -56,7 +165,7 @@ static struct symbol *step_start_function; static char break_insn[] = BREAKPOINT; -/* Nonzero => address for special breakpoint for resuming stepping. */ +/* Nonzero => address for special breakpoint for resuming stepping. */ static CORE_ADDR step_resume_break_address; @@ -85,11 +194,11 @@ static int trap_expected_after_continue; /* Nonzero means expecting a trace trap and should stop the inferior and return silently when it happens. */ -static int stop_after_trap; +int stop_after_trap; /* Nonzero means expecting a trace trap due to attaching to a process. */ -static int stop_after_attach; +int stop_after_attach; /* Nonzero if pc has been changed by the debugger since the inferior stopped. */ @@ -117,11 +226,8 @@ static int running_in_shell; static int stop_print_frame; #ifdef NO_SINGLE_STEP -/* Non-zero if we just simulated a single-step ptrace call. This is - needed because we cannot remove the breakpoints in the inferior - process until after the `wait' in `wait_for_inferior'. - Used for sun4. */ -int one_stepped; +extern int one_stepped; /* From machine dependent code */ +extern void single_step (); /* Same. */ #endif /* NO_SINGLE_STEP */ static void insert_step_breakpoint (); @@ -129,7 +235,6 @@ static void remove_step_breakpoint (); static void wait_for_inferior (); static void normal_stop (); -START_FILE /* Clear out all variables saying what to do when inferior is continued. First do this, then set the ones you want, then call `proceed'. */ @@ -140,7 +245,7 @@ clear_proceed_status () trap_expected = 0; step_range_start = 0; step_range_end = 0; - step_frame = 0; + step_frame_address = 0; step_over_calls = -1; step_resume_break_address = 0; stop_after_trap = 0; @@ -188,7 +293,7 @@ proceed (addr, signal, step) { write_register (PC_REGNUM, addr); #ifdef NPC_REGNUM - write_register (NPC_REGNUM, addr+4); + write_register (NPC_REGNUM, addr + 4); #endif } @@ -241,6 +346,7 @@ The same program may be running in another process."); /* 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; { @@ -253,12 +359,19 @@ writing_pc (val) 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; @@ -275,8 +388,9 @@ start_inferior () { trap_expected = 0; fetch_inferior_registers(); - set_current_frame (read_register(FP_REGNUM)); - stop_frame = get_current_frame(); + 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"); @@ -342,18 +456,28 @@ wait_for_inferior () int tem; int another_trap; int random_signal; - CORE_ADDR stop_sp; + CORE_ADDR stop_sp, prev_sp; + CORE_ADDR prev_func_start, stop_func_start; + CORE_ADDR prologue_pc; int stop_step_resume_break; + CORE_ADDR step_resume_break_sp; int newmisc; int newfun_pc; struct symbol *newfun; struct symtab_and_line sal; int prev_pc; + extern CORE_ADDR text_end; prev_pc = read_pc (); + prev_func_start = get_pc_function_start (prev_pc) + 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 @@ -363,36 +487,7 @@ wait_for_inferior () continue; } -#ifdef NO_SINGLE_STEP - if (one_stepped) - { - single_step (0); - } -#endif /* NO_SINGLE_STEP */ - - pc_changed = 0; - fetch_inferior_registers (); - stop_pc = read_pc (); - set_current_frame (read_register (FP_REGNUM)); - stop_frame = get_current_frame (); - stop_sp = read_register (SP_REGNUM); - 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; - 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. */ - + /* See if the process still exists; clean up if it doesn't. */ if (WIFEXITED (w)) { terminal_ours_for_output (); @@ -402,6 +497,9 @@ wait_for_inferior () printf ("\nProgram exited normally.\n"); fflush (stdout); inferior_died (); +#ifdef NO_SINGLE_STEP + one_stepped = 0; /* Clear single_step state since proc gone */ +#endif /* NO_SINGLE_STEP */ stop_print_frame = 0; break; } @@ -418,254 +516,377 @@ wait_for_inferior () : "(undocumented)"); printf ("The inferior process no longer exists.\n"); fflush (stdout); +#ifdef NO_SINGLE_STEP + one_stepped = 0; /* Clear single_step state since proc gone */ +#endif /* NO_SINGLE_STEP */ break; } - else + +#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 ())); +#ifdef CONVEX_PTRACE + /* pop frame stored by user-mode trap, if present */ + if (stop_pc == BREAK_TRAP_ADDR) + { + POP_FRAME; + stop_pc = read_pc () - 2; + write_register (PC_REGNUM, stop_pc); +#ifdef NPC_REGNUM + write_register (NPC_REGNUM, stop_pc + 4); +#endif + pc_changed = 0; + } + else if (stop_pc > STACK_END_ADDR) + { + POP_FRAME; + stop_pc = read_pc (); + } +#endif /* CONVEX_PTRACE */ + stop_frame_address = FRAME_FP (get_current_frame ()); + stop_sp = read_register (SP_REGNUM); + stop_func_start = + get_pc_function_start (stop_pc) + 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 +#ifndef CONVEX_PTRACE + || (breakpoints_inserted && + (stop_signal == SIGILL + || stop_signal == SIGEMT)) +#endif /* not CONVEX_PTRACE */ + || stop_after_attach) { - 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) { - 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. */ + 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)) + /* 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 */ - { - select_frame (stop_frame, 0); /* For condition exprs. */ - stop_breakpoint = breakpoint_stop_status (stop_pc, stop_frame); - /* 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); + { + /* For condition exprs. */ + select_frame (get_current_frame (), 0); + 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); + write_register (NPC_REGNUM, stop_pc + 4); #endif - pc_changed = 0; - } - } + pc_changed = 0; + } + } /* 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) + 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); -#ifdef NPC_REGNUM - write_register (PC_REGNUM, stop_pc + 4); -#endif pc_changed = 0; } } - - if (stop_signal == SIGTRAP) - random_signal - = !(stop_breakpoint || trap_expected - || stop_step_resume_break - || (stop_sp INNER_THAN stop_pc && stop_pc INNER_THAN stop_frame) - || (step_range_end && !step_resume_break_address)); - else - { - random_signal - = !(stop_breakpoint || stop_step_resume_break); - if (!random_signal) - stop_signal = SIGTRAP; - } } + + if (stop_signal == SIGTRAP) + random_signal + = !(stop_breakpoint || trap_expected + || stop_step_resume_break +#ifndef CONVEX_PTRACE + || (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 = 1; + { + random_signal + = !(stop_breakpoint + || stop_step_resume_break +#ifdef news800 + || (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. */ + /* 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; + if (random_signal + && !(running_in_shell && stop_signal == SIGSEGV)) + { + /* Signal not for debugging purposes. */ + int printed = 0; - 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 (); + 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. */ + /* Handle cases caused by hitting a breakpoint. */ - if (!random_signal - && (stop_breakpoint || stop_step_resume_break)) + 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) { - /* Does a breakpoint want us to stop? */ - if (stop_breakpoint && stop_breakpoint != -1) - { - /* 0x1000000 is set in stop_breakpoint as returned by - breakpoint_status_p to indicate a silent breakpoint. */ - if (stop_breakpoint > 0 && stop_breakpoint & 0x1000000) - { - stop_breakpoint &= ~0x1000000; - stop_print_frame = 0; - } - break; - } - /* But if we have hit the step-resumption breakpoint, - remove it. It has done its job getting us here. */ - if (stop_step_resume_break - && (step_frame == 0 || stop_frame == step_frame)) - { - remove_step_breakpoint (); - step_resume_break_address = 0; - } - /* Otherwise, must remove breakpoints and single-step - to get us past the one we hit. */ - else + /* 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) { - remove_breakpoints (); - remove_step_breakpoint (); - breakpoints_inserted = 0; - another_trap = 1; + stop_print_frame = 0; + if (stop_breakpoint > 0) + stop_breakpoint -= 0x1000000; + else + stop_breakpoint += 0x1000000; } - - /* 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. */ + break; } - - /* If this is the breakpoint at the end of a stack dummy, - just stop silently. */ - if (stop_sp INNER_THAN stop_pc && stop_pc INNER_THAN stop_frame) + /* 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 +#if 0 +#ifndef HAVE_REGISTER_WINDOWS + && step_resume_break_sp INNER_THAN stop_sp +#endif +#endif + ))) { - stop_print_frame = 0; - stop_stack_dummy = 1; + 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 CONVEX_PTRACE + if (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) +#else + /* "stack" dummy must be in text segment for Convex Unix */ + if (stop_pc == text_end - 2) +#endif + { + stop_print_frame = 0; + stop_stack_dummy = 1; #ifdef HP9K320 - trap_expected_after_continue = 1; + 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 != 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; } + } - 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) + /* 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) { - /* 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; - } + prologue_pc = stop_func_start; + SKIP_PROLOGUE (prologue_pc); } - /* 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) + /* ==> See comments at top of file on this algorithm. <==*/ + + if (stop_pc == stop_func_start + && (stop_func_start != prev_func_start + || prologue_pc != stop_func_start + || stop_sp != prev_sp)) { newfun = find_pc_function (stop_pc); - newmisc = -1; - if (newfun) - { - newfun_pc = BLOCK_START (SYMBOL_BLOCK_VALUE (newfun)) - + FUNCTION_START_OFFSET; - } - else - { - newmisc = find_pc_misc_function (stop_pc); - if (newmisc >= 0) - newfun_pc = misc_function_vector[newmisc].address - + FUNCTION_START_OFFSET; - else newfun_pc = 0; - } - if (stop_pc == newfun_pc - && (step_over_calls > 0 || (step_over_calls && newfun == 0))) + /* It's a subroutine call */ + if (step_over_calls > 0 || (step_over_calls && newfun == 0)) { /* A subroutine call has happened. */ /* Set a special breakpoint after the return */ - step_resume_break_address = SAVED_PC_AFTER_CALL (stop_frame); + 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 (stop_pc == newfun_pc && step_over_calls) + else if (step_over_calls) { - SKIP_PROLOGUE (newfun_pc); - sal = find_pc_line (newfun_pc, 0); + 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. */ - if (sal.end && sal.pc != newfun_pc) - newfun_pc = sal.end; - - if (newfun_pc == stop_pc) - /* We are already there: stop now. */ - stop_step = 1; +#ifdef convex + /* 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. */ + /* Put the step-breakpoint there and go until there. */ { - step_resume_break_address = newfun_pc; - + 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) @@ -673,22 +894,38 @@ wait_for_inferior () /* 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 = 0; + step_frame_address = 0; /* And make sure stepping stops right away then. */ step_range_end = step_range_start; } } - /* No subroutince call; stop now. */ 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 (); + 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_sp = stop_sp; /* If we did not do break;, it means we should keep running the inferior and not return to debugger. */ @@ -748,9 +985,19 @@ wait_for_inferior () BREAKPOINTS_FAILED nonzero means stop was due to error attempting to insert breakpoints. */ +/* FIXME, normal_stop is ALWAYS called immediately after wait_for_inferior. + They should probably be merged into a single function, since that + would avoid numerous tests (e.g. of inferior_pid). */ + 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 (); @@ -781,7 +1028,8 @@ Further execution is probably impossible.\n"); /* If an auto-display called a function and that got a signal, delete that auto-display to avoid an infinite recursion. */ - delete_current_display (); + if (stopped_by_random_signal) + delete_current_display (); if (step_multi && stop_step) return; @@ -791,7 +1039,13 @@ Further execution is probably impossible.\n"); if (running_in_shell) { if (stop_signal == SIGSEGV) - printf ("\ + { + 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 + 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\ @@ -803,6 +1057,7 @@ some variables whose values are large; then do \"run\" again.\n\ \n\ If that works, you might want to put those \"unset-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; } @@ -814,14 +1069,14 @@ into a \".gdbinit\" file in this directory so they will happen every time.\n"); or if the program has exited. */ if (!stop_stack_dummy) { - select_frame (stop_frame, 0); + 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 == stop_frame + && step_frame_address == stop_frame_address && step_start_function == find_pc_function (stop_pc)); /* Display the auto-display expressions. */ do_displays (); @@ -834,9 +1089,11 @@ into a \".gdbinit\" file in this directory so they will happen every time.\n"); if (stop_stack_dummy) { - /* Pop the empty frame that contains the stack dummy. */ + /* Pop the empty frame that contains the stack dummy. + POP_FRAME ends with a setting of the current frame, so we + can use that next. */ POP_FRAME; - select_frame (read_register (FP_REGNUM), 0); + select_frame (get_current_frame (), 0); } } @@ -868,7 +1125,7 @@ handle_command (args, from_tty) int from_tty; { register char *p = args; - int signum; + int signum = 0; register int digits, wordlen; if (!args) @@ -885,6 +1142,11 @@ handle_command (args, from_tty) 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)) @@ -970,7 +1232,7 @@ signals_info (signum_exp) { printf ("[Type Return to see more]"); fflush (stdout); - read_line (); + gdb_read_line (0, 0); } printf ("%d\t", i); printf ("%s\t", signal_stop[i] ? "Yes" : "No"); @@ -982,8 +1244,91 @@ signals_info (signum_exp) printf ("\nUse the \"handle\" command to change these tables.\n"); } -static -initialize () +/* 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; + + bcopy (stop_registers, inf_status->stop_registers, REGISTER_BYTES); + + record_selected_frame (&(inf_status->selected_frame_address), + &(inf_status->selected_level)); + return; +} + +void +restore_inferior_status (inf_status) + struct inferior_status *inf_status; +{ + FRAME fid; + int level = inf_status->selected_level; + + pc_changed = inf_status->pc_changed; + stop_signal = inf_status->stop_signal; + stop_pc = inf_status->stop_pc; + stop_frame_address = inf_status->stop_frame_address; + stop_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); + + bcopy (inf_status->stop_registers, stop_registers, REGISTER_BYTES); + + if (inf_status->restore_stack_info) + { + fid = find_relative_frame (get_current_frame (), + &level); + + if (FRAME_FP (fid) != inf_status->selected_frame_address || + level != 0) + { + 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; @@ -1044,148 +1389,3 @@ Pass and Stop may be combined."); #endif /* SIGURG */ } -#ifdef NO_SINGLE_STEP -/* This code was written by Gary Beihl (beihl@mcc.com). - It was modified by Michael Tiemann (tiemann@corto.inria.fr). */ - -/* Simulate single-step ptrace call for sun4. */ - -typedef enum -{ - b_error, not_branch, bicc, bicca, ba, baa, ticc, ta, -} branch_type; - -static CORE_ADDR next_pc, pc8, target; -static int brkpc8, brktrg; -typedef char binsn_quantum[sizeof break_insn]; -static binsn_quantum break_mem[3]; - -int -single_step (signal) - int signal; -{ - branch_type br, isabranch(); - - next_pc = read_register (NPC_REGNUM); - pc8 = read_register (PC_REGNUM) + 8; /* branch not taken */ - - if (!one_stepped) - { - /* Always set breakpoint for NPC. */ - read_memory (next_pc, break_mem[0], sizeof break_insn); - write_memory (next_pc, break_insn, sizeof break_insn); - - /* printf ("set break at %x\n",next_pc); */ - br = isabranch (pc8 - 8, &target); - brkpc8 = brktrg = 0; - - if (br == bicca && pc8 != next_pc) - { - /* Handle branches with care */ - brkpc8 = 1; - read_memory (pc8, break_mem[1], sizeof break_insn); - write_memory (pc8, break_insn, sizeof break_insn); - } - else if (br == baa && target != next_pc) - { - brktrg = 1; - read_memory (target, break_mem[2], sizeof break_insn); - write_memory (target, break_insn, sizeof break_insn); - } - - /* Let it go */ - ptrace (7, inferior_pid, 1, signal); - one_stepped = 1; - return; - } - else - { - /* Remove breakpoints */ - write_memory (next_pc, break_mem[0], sizeof break_insn); - - if (brkpc8) - { - write_memory (pc8, break_mem[1], sizeof break_insn); - } - if (brktrg) - { - write_memory (target, break_mem[2], sizeof break_insn); - } - one_stepped = 0; - } -} - -#endif /* NO_SINGLE_STEP */ - -static int save_insn_opcodes[] = { 0x03000000, 0x82007ee0, 0x9de38001, 0x03000000, 0x82007ee0, 0x91d02001, 0x01000000 }; - -void -do_save_insn (size) - int size; -{ - int g1 = read_register (1); - CORE_ADDR sp = read_register (SP_REGNUM); - CORE_ADDR pc = read_register (PC_REGNUM); -#ifdef NPC_REGNUM - CORE_ADDR npc = read_register (NPC_REGNUM); -#endif - CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes); - save_insn_opcodes[0] = 0x03000000 | ((-size >> 12) & 0x3fffff); - save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff); - save_insn_opcodes[3] = 0x03000000 | ((g1 >> 12) & 0x3fffff); - save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff); - write_memory (fake_pc, save_insn_opcodes, sizeof (save_insn_opcodes)); - clear_proceed_status (); - stop_after_trap = 1; - - proceed (fake_pc, 0, 0); - - write_register (PC_REGNUM, pc); -#ifdef NPC_REGNUM - write_register (NPC_REGNUM, npc); -#endif -} - -static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 }; - -void -do_restore_insn (raw_buffer) - char raw_buffer[]; -{ - CORE_ADDR pc = read_memory_integer (*(int *)&raw_buffer[REGISTER_BYTE (PC_REGNUM)], 4); - CORE_ADDR sp = read_register (SP_REGNUM); -#ifdef NPC_REGNUM - CORE_ADDR npc = *(int *)&raw_buffer[REGISTER_BYTE (NPC_REGNUM)] != 0 - ? read_memory_integer (*(int *)&raw_buffer[REGISTER_BYTE (NPC_REGNUM)], 4) : pc + 4; -#endif - CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes); - int saved_stop_stack_dummy = stop_stack_dummy; - - if (*(int *)&raw_buffer[REGISTER_BYTE (PC_REGNUM)] == 0) - abort (); - - write_memory (fake_pc, restore_insn_opcodes, sizeof (restore_insn_opcodes)); - clear_proceed_status (); - stop_after_trap = 1; - - proceed (fake_pc, 0, 0); - - stop_stack_dummy = saved_stop_stack_dummy; - write_register (PC_REGNUM, pc); -#ifdef NPC_REGNUM - write_register (NPC_REGNUM, npc); -#endif - - /* Select innermost stack frame except on return from a stack dummy routine, - or if the program has exited. */ - if (!stop_stack_dummy) - { - select_frame (stop_frame, 0); - } - else - { - select_frame (read_register (FP_REGNUM), 0); - } -} - -END_FILE diff --git a/gdb/initialize.h b/gdb/initialize.h deleted file mode 100644 index 8037dd6..0000000 --- a/gdb/initialize.h +++ /dev/null @@ -1,134 +0,0 @@ -/* Macros to enable automatic execution of an initialization function - in each object file without having to include a list of all object files - anywhere in the source code. This goes with firstfile.c and lastfile.c. - - Copyright (C) 1986 Free Software Foundation, Inc. - - NO WARRANTY - - BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY -NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT -WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, -RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS 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. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. -STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY -WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE -LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR -OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR -DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR -A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS -PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. - - GENERAL PUBLIC LICENSE TO COPY - - 1. You may copy and distribute verbatim copies of this source file -as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy a valid copyright notice "Copyright -(C) 1986 Free Software Foundation, Inc."; and include following the -copyright notice a verbatim copy of the above disclaimer of warranty -and of this License. You may charge a distribution fee for the -physical act of transferring a copy. - - 2. You may modify your copy or copies of this source file 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 or is a derivative of this - program or any part thereof, to be licensed at no charge to all - third parties on terms identical to those contained in this - License Agreement (except that you may choose to grant more extensive - warranty protection to some or all third parties, at your option). - - c) You may charge a distribution 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 unrelated program with this program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other program under the scope of these terms. - - 3. You may copy and distribute this 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 - shipping charge) 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.) - -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. - - 4. You may not copy, sublicense, distribute or transfer this program -except as expressly provided under this License Agreement. Any attempt -otherwise to copy, sublicense, distribute or transfer this program is void and -your rights to use the program under this License agreement shall be -automatically terminated. However, parties who have received computer -software programs from you with this License Agreement will not have -their licenses terminated so long as such parties remain in full compliance. - - 5. If you wish to incorporate parts of this program into other free -programs whose distribution conditions are different, write to the Free -Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet -worked out a simple rule that can be stated here, but we will often permit -this. We 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. - - -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! */ - - -/* Here a machine-specific header file must be included to define - the macro FILEADDR_ROUND which we use to round up from the address - of the end of one object file's text to the start of the next - object file's text. */ - -#include "m-init.h" - -/* This is used to make a file's initialization function. - It calls another function named `initialize', which must - appear later in the file. */ - -#define START_FILE \ - static initialize (), initialize_next_file (); \ - static initialize_1 (offset) \ - { initialize (); initialize_next_file (offset); } - -/* The argument OFFSET is the size of this function. - By adding it to the address of this function, - we find the next function, which is the next file's - initialization function. */ - -#define END_FILE \ - static initialize_next_file (offset) \ - int offset; \ - { long addr = FILEADDR_ROUND ((int) initialize_next_file + offset); \ - (*(void (*) ()) addr) (offset); } diff --git a/gdb/lastfile.c b/gdb/lastfile.c deleted file mode 100644 index 2ac8cb7..0000000 --- a/gdb/lastfile.c +++ /dev/null @@ -1,6 +0,0 @@ -/* This ends the chain of files for the purpose of initialization, - because it does not attempt to find the start of the following file. */ - -initialize_last_file () -{ -} diff --git a/gdb/m-hp9k320bsd.h b/gdb/m-aux.h similarity index 79% rename from gdb/m-hp9k320bsd.h rename to gdb/m-aux.h index 221d3c5..fbc7ca0 100644 --- a/gdb/m-hp9k320bsd.h +++ b/gdb/m-aux.h @@ -1,5 +1,5 @@ -/* Parameters for execution on a Sun, for GDB, the GNU debugger. - Copyright (C) 1986, 1987 Free Software Foundation, Inc. +/* Parameters for execution on A/UX, for GDB, the GNU debugger. + Copyright (C) 1989 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 @@ -18,32 +18,36 @@ 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! */ -/* - * Configuration file for HP9000/300 series machine running - * University of Utah's 4.3bsd port. This is NOT for HP-UX. - * Problems to hpbsd-bugs@cs.utah.edu - */ - -#ifndef hp300 -#define hp300 +#ifndef aux +#define aux #endif -/* Watch out for NaNs */ - -#define IEEE_FLOAT +/* It's a USG system */ +#define USG -/* Get rid of any system-imposed stack limit if possible. */ +/* Assembler instructions in USG "SGS" (sw generation system) format */ +#define USG_SGS_ASM -#define SET_STACK_LIMIT_HUGE +/* Debugger information will be in COFF format. */ +#define COFF_FORMAT +#define COFF_NO_LONG_FILE_NAMES -/* Define this if the C compiler puts an underscore at the front - of external names before giving them to the linker. */ +/* Terminal interface via termio */ +#define HAVE_TERMIO -#define NAMES_HAVE_UNDERSCORE +/* Unisoft fucked up the include files */ +#define UNISOFT_ASSHOLES -/* Debugger information will be in DBX format. */ +/* Big or Little-Endian target machine + BITS: defined if bit #0 is the high-order bit of a byte. + BYTES:defined if byte#0 is the high-order byte of an int. + WORDS:defined if word#0 is the high-order word of a double. */ +#define BITS_BIG_ENDIAN +#define BYTES_BIG_ENDIAN +#define WORDS_BIG_ENDIAN -#define READ_DBX_FORMAT +/* Floating point is IEEE compatible */ +#define IEEE_FLOAT /* Offset from address of function to start of its code. Zero on most machines. */ @@ -69,36 +73,40 @@ anyone else from sharing it farther. Help stamp out software hoarding! #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 0x00917000 - /* Address of end of stack space. */ -#define STACK_END_ADDR 0xFFF00000 +#define STACK_END_ADDR 0x20000000 /* Stack grows downward. */ #define INNER_THAN < /* Sequence of bytes for breakpoint instruction. */ +/* A/UX uses "trap &1" */ -#define BREAKPOINT {0x4e, 0x42} +#define BREAKPOINT {0x4e, 0x41} /* 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 2 +#define DECR_PC_AFTER_BREAK 0 /* Nonzero if instruction at PC is a return instruction. */ #define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75) /* Return 1 if P points to an invalid floating point value. */ +/* FIXME, it's not clear what "invalid" means here. I take it to mean + "something that coredumps gdb if gdb tries to manipulate it" */ -#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ +#define INVALID_FLOAT(p, len) is_nan(p, len) + +/* 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. */ @@ -113,7 +121,7 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define REGISTER_NAMES \ {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ - "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ "ps", "pc", \ "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ "fpcontrol", "fpstatus", "fpiaddr" } @@ -131,11 +139,31 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define PC_REGNUM 17 /* Contains program counter */ #define FP0_REGNUM 18 /* Floating point register 0 */ #define FPC_REGNUM 26 /* 68881 control register */ -#define FPS_REGNUM 27 /* 68881 status register */ +/* This is a piece of magic that is given a register number REGNO + and as BLOCKEND the address in the system of the end of the user structure + and stores in ADDR the address in the kernel or core dump + of that register. */ + +#define REGISTER_U_ADDR(addr, blockend, regno) { \ + struct user u; \ + if (regno <= SP_REGNUM) \ + addr = blockend + regno * 4; \ + else if (regno == PS_REGNUM) \ + addr = blockend + RPS * 4; /* From reg.h */ \ + else if (regno == PC_REGNUM) \ + addr = blockend + PC * 4; /* From reg.h */ \ + else if (regno < FPC_REGNUM) \ + addr = (char *) u.u_fpdreg [regno-FP0_REGNUM] - (char *)&u; \ + else \ + addr = (char *)&u.u_fpsysreg[regno-FPC_REGNUM] - (char *)&u; \ +} + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ /* Total amount of space needed to store our copies of the machine's register state, the array `registers'. */ -#define REGISTER_BYTES (16*4+8*12+8+12) +#define REGISTER_BYTES (16*4+8*12+8+20) /* Index within `registers' of the first byte of the space for register N. */ @@ -148,6 +176,8 @@ read_memory_integer (read_register (SP_REGNUM), 4) /* Number of bytes of storage in the actual machine representation for register N. On the 68000, all regs are 4 bytes except the floating point regs which are 12 bytes. */ +/* Note that the unsigned cast here forces the result of the + subtractiion to very high positive values if N < FP0_REGNUM */ #define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) @@ -194,6 +224,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define REGISTER_VIRTUAL_TYPE(N) \ (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : 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) \ + { write_register (9, (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. */ @@ -213,37 +249,6 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) -/* Compensate for lack of `vprintf' function. */ -#define vprintf(format, ap) _doprnt (format, ap, stdout) - -/* This is a piece of magic that is given a register number REGNO - and as BLOCKEND the address in the system of the end of the user structure - and stores in ADDR the address in the kernel or core dump - of that register. */ - -#define REGISTER_U_ADDR(addr, blockend, regno) \ -{ \ - if (regno < PS_REGNUM) \ - addr = (int) &((struct frame *)(blockend))->f_regs[regno]; \ - else if (regno == PS_REGNUM) \ - addr = (int) &((struct frame *)(blockend))->f_stackadj; \ - else if (regno == PC_REGNUM) \ - addr = (int) &((struct frame *)(blockend))->f_pc; \ - else if (regno < FPC_REGNUM) \ - addr = (int) \ - &((struct user *)0)->u_pcb.pcb_fpregs.fpf_regs[((regno)-FP0_REGNUM)*3];\ - else if (regno == FPC_REGNUM) \ - addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpcr; \ - else if (regno == FPS_REGNUM) \ - addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpsr; \ - else \ - addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpiar; \ -} - -/* It is safe to look for symsegs on a Sun, because Sun's ld - does not screw up with random garbage at end of file. */ - -#define READ_GDB_SYMSEGS /* Describe the pointer in each stack frame to the previous stack frame (its caller). */ @@ -258,23 +263,23 @@ read_memory_integer (read_register (SP_REGNUM), 4) it means the given frame is the outermost one and has no caller. In that case, FRAME_CHAIN_COMBINE is not used. */ -/* In the case of the Sun, the frame's nominal address +/* In the case of the 68k, the frame's nominal address is the address of a 4-byte word containing the calling frame's address. */ -#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4)) +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) -#define FRAME_ARGS_ADDRESS(fi) (fi.frame) +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) -#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) /* Set VAL to the number of args passed to frame described by FI. Can set VAL to -1, meaning no way to tell. */ @@ -285,7 +290,7 @@ read_memory_integer (read_register (SP_REGNUM), 4) #if 0 #define FRAME_NUM_ARGS(val, fi) \ -{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ register int insn = 0177777 & read_memory_integer (pc, 2); \ val = 0; \ if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ @@ -315,19 +320,19 @@ read_memory_integer (read_register (SP_REGNUM), 4) register CORE_ADDR pc; \ int nextinsn; \ bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ - && (frame_info).pc <= (frame_info).frame) \ - { next_addr = (frame_info).frame; \ - pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ else \ - { pc = get_pc_function_start ((frame_info).pc); \ + { pc = get_pc_function_start ((frame_info)->pc); \ /* Verify we have a link a6 instruction next; \ if not we lose. If we win, find the address above the saved \ regs using the amount of storage from the link instruction. */\ if (044016 == read_memory_integer (pc, 2)) \ - next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \ else if (047126 == read_memory_integer (pc, 2)) \ - next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \ else goto lose; \ /* If have an addal #-n, sp next, adjust next_addr. */ \ if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ @@ -354,7 +359,7 @@ read_memory_integer (read_register (SP_REGNUM), 4) for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ if (regmask & 1) \ (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ - else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \ + else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) \ { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \ (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ /* fmovemx to index of sp may follow. */ \ @@ -371,9 +376,9 @@ read_memory_integer (read_register (SP_REGNUM), 4) if (0x426742e7 == read_memory_integer (pc, 4)) \ (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ lose: ; \ - (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ - (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ } /* Things needed for making the inferior call functions. */ @@ -399,13 +404,15 @@ read_memory_integer (read_register (SP_REGNUM), 4) restoring all saved registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ + struct frame_info *fi; \ char raw_buffer[12]; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ if (fsr.regs[regnum]) \ { read_memory (fsr.regs[regnum], raw_buffer, 12); \ @@ -418,7 +425,9 @@ read_memory_integer (read_register (SP_REGNUM), 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); \ - set_current_frame (read_register (FP_REGNUM)); } + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } /* This sequence of words is the instructions fmovem 0xff,-(sp) @@ -431,7 +440,7 @@ read_memory_integer (read_register (SP_REGNUM), 4) the following jsr instruction. *../ jsr @#32323232 addl #69696969,sp - trap #2 + trap #15 nop Note this is 28 bytes. We actually start executing at the jsr, since the pushing of the @@ -442,7 +451,7 @@ But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, and we cannot allow the moveml to push the registers again lest they be taken for the arguments. */ -#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e424e71} +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} #define CALL_DUMMY_LENGTH 28 @@ -451,7 +460,7 @@ taken for the arguments. */ /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { *(int *)((char *) dummyname + 20) = nargs * 4; \ *(int *)((char *) dummyname + 14) = fun; } diff --git a/gdb/m-hp9k320.h b/gdb/m-hp9k320.h index 20209ce..460e30d 100644 --- a/gdb/m-hp9k320.h +++ b/gdb/m-hp9k320.h @@ -25,15 +25,18 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* Set flag to indicate whether HP's assembler is in use. */ #ifdef __GNU__ #ifdef __HPUX_ASM__ -#define HPUX_ASM +#define USG_SGS_ASM #endif #else -#define HPUX_ASM +#define USG_SGS_ASM #endif /* Define this for versions of hp-ux older than 6.0 */ /* #define HPUX_VERSION_5 */ +/* define USG if you are using sys5 /usr/include's */ +#define USG + #define HAVE_TERMIO /* Get rid of any system-imposed stack limit if possible. */ @@ -108,6 +111,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ +/* 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 @@ -201,6 +210,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define REGISTER_VIRTUAL_TYPE(N) \ (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : 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) \ + { write_register (9, (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. */ @@ -228,9 +243,11 @@ read_memory_integer (read_register (SP_REGNUM), 4) : (&((struct exception_stack *) (u_ar0))->e_PC))) #define FP_REGISTER_ADDR(u, regno) \ - (((regno) < FPC_REGNUM) \ - ? (&u.u_pcb.pcb_mc68881[FMC68881_R0 + (((regno) - FP0_REGNUM) * 3)]) \ - : (&u.u_pcb.pcb_mc68881[FMC68881_C + ((regno) - FPC_REGNUM)])) + (((char *) \ + (((regno) < FPC_REGNUM) \ + ? (&u.u_pcb.pcb_mc68881[FMC68881_R0 + (((regno) - FP0_REGNUM) * 3)]) \ + : (&u.u_pcb.pcb_mc68881[FMC68881_C + ((regno) - FPC_REGNUM)]))) \ + - ((char *) (& u))) /* It is safe to look for symsegs on a Sun, because Sun's ld does not screw up with random garbage at end of file. */ @@ -253,20 +270,20 @@ read_memory_integer (read_register (SP_REGNUM), 4) /* In the case of the Sun, the frame's nominal address is the address of a 4-byte word containing the calling frame's address. */ -#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4)) +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) -#define FRAME_ARGS_ADDRESS(fi) (fi.frame) +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) -#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) /* Set VAL to the number of args passed to frame described by FI. Can set VAL to -1, meaning no way to tell. */ @@ -277,7 +294,7 @@ read_memory_integer (read_register (SP_REGNUM), 4) #if 0 #define FRAME_NUM_ARGS(val, fi) \ -{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ register int insn = 0177777 & read_memory_integer (pc, 2); \ val = 0; \ if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ @@ -307,19 +324,19 @@ read_memory_integer (read_register (SP_REGNUM), 4) register CORE_ADDR pc; \ int nextinsn; \ bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ - && (frame_info).pc <= (frame_info).frame) \ - { next_addr = (frame_info).frame; \ - pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ else \ - { pc = get_pc_function_start ((frame_info).pc); \ + { pc = get_pc_function_start ((frame_info)->pc); \ /* Verify we have a link a6 instruction next; \ if not we lose. If we win, find the address above the saved \ regs using the amount of storage from the link instruction. */\ if (044016 == read_memory_integer (pc, 2)) \ - next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \ else if (047126 == read_memory_integer (pc, 2)) \ - next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \ else goto lose; \ /* If have an addal #-n, sp next, adjust next_addr. */ \ if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ @@ -363,9 +380,9 @@ read_memory_integer (read_register (SP_REGNUM), 4) if (0x426742e7 == read_memory_integer (pc, 4)) \ (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ lose: ; \ - (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ - (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ } /* Things needed for making the inferior call functions. */ @@ -391,13 +408,15 @@ read_memory_integer (read_register (SP_REGNUM), 4) restoring all saved registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ + struct frame_info *fi; \ char raw_buffer[12]; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ if (fsr.regs[regnum]) \ { read_memory (fsr.regs[regnum], raw_buffer, 12); \ @@ -410,7 +429,9 @@ read_memory_integer (read_register (SP_REGNUM), 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); \ - set_current_frame (read_register (FP_REGNUM)); } + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ()));} /* This sequence of words is the instructions fmovem 0xff,-(sp) @@ -443,7 +464,7 @@ taken for the arguments. */ /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { *(int *)((char *) dummyname + 20) = nargs * 4; \ *(int *)((char *) dummyname + 14) = fun; } diff --git a/gdb/m-i386.h b/gdb/m-i386.h new file mode 100644 index 0000000..f7d9cd2 --- /dev/null +++ b/gdb/m-i386.h @@ -0,0 +1,394 @@ +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + */ + +/* + Copyright (C) 1986, 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! +*/ + +#ifndef i386 +#define i386 +#endif + +/* 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) (read_memory_integer ((thisframe)->frame, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#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. */ + +/* 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 + */ +#define FRAME_NUM_ARGS(numargs, fi) { \ + int retpc; \ + unsigned char op; \ + struct frame_info *pfi; \ + pfi = get_prev_frame_info ((fi)); \ + retpc = pfi->pc; \ + numargs = 0; \ + op = read_memory_integer (retpc, 1); \ + if (op == 0x59) \ + /* pop %ecx */ \ + (numargs) = 1; \ + else if (op == 0x83) { \ + op = read_memory_integer (retpc+1, 1); \ + if (op == 0xc4) \ + /* addl $, %esp */ \ + (numargs) = (read_memory_integer (retpc+2,1)&0xff)/4;\ + } else if (op == 0x81) { /* add with 32 bit immediate */\ + op = read_memory_integer (retpc+1, 1); \ + if (op == 0xc4) \ + /* addl $, %esp */ \ + (numargs) = read_memory_integer (retpc+2, 4) / 4;\ + } \ +} + +/* 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/gdb/m-i386gas.h b/gdb/m-i386gas.h new file mode 100644 index 0000000..79a7083 --- /dev/null +++ b/gdb/m-i386gas.h @@ -0,0 +1,37 @@ +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * + * i386gnu: COFF_ENCAPSULATE + */ + +/* + Copyright (C) 1986, 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! +*/ + +#define COFF_ENCAPSULATE + +#include "m-i386.h" + + +#define NAMES_HAVE_UNDERSCORE + +#undef COFF_FORMAT +#define READ_DBX_FORMAT + diff --git a/gdb/m-init.h b/gdb/m-init.h deleted file mode 100644 index a1edc20..0000000 --- a/gdb/m-init.h +++ /dev/null @@ -1,5 +0,0 @@ - -/* This is how the size of an individual .o file's text segment - is rounded on a sun. */ - -#define FILEADDR_ROUND(addr) ((addr + 7) & -8) diff --git a/gdb/m-isi.h b/gdb/m-isi.h new file mode 100644 index 0000000..a78cc43 --- /dev/null +++ b/gdb/m-isi.h @@ -0,0 +1,549 @@ +/* +Date: Thu, 2 Apr 87 00:02:42 EST +From: crl@maxwell.physics.purdue.edu (Charles R. LaBrec) +Message-Id: <8704020502.AA01744@maxwell.physics.purdue.edu> +To: bug-gdb@prep.ai.mit.edu +Subject: gdb for ISI Optimum V + +Here is an m-isi-ov.h file for gdb version 2.1. It supports the 68881 +registers, and tracks down the function prologue (since the ISI cc +puts it at the end of the function and branches to it if not +optimizing). Also included are diffs to core.c, findvar.c, and +inflow.c, since the original code assumed that registers are an int in +the user struct, which isn't the case for 68020's with 68881's (and +not using the NEW_SUN_PTRACE). I have not fixed the bugs associated +with the other direction (writing registers back to the user struct). +I have also included a diff that turns m68k-pinsn.c into isi-pinsn.c, +which is needed since the 3.05 release of as does not understand +floating point ops, and it compiles incorrectly under "cc -20" + +I have used gdb for a while now, and it seems to work relatively well, +but I do not guarantee that it is perfect. The more that use it, the +faster the bugs will get shaken out. One bug I know of is not in gdb, +but in the assembler. It seems to screw up the .stabs of variables. +For externs, this is not important since gdb uses the global symbol +value, but for statics, this makes gdb unable to find them. I am +currently trying to track it down. + +As an aside, I notice that only global functions are used as symbols +to print as relative addresses, i.e. "", and not +static functions, which end up printing as large offsets from the last +global one. Would there be a problem if static functions were also +recorded as misc functions in read_dbx_symtab? + +Charles LaBrec +crl @ maxwell.physics.purdue.edu + + Definitions to make GDB run on a ISI Optimum V (3.05) under 4.2bsd. + + 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! +*/ + + +/* Identify this machine */ +#ifndef ISI68K +#define ISI68K +#endif + +/* 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 + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) \ +{ register int op = read_memory_integer (pc, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ + else if (op == 0060000) \ + pc += 4; /* Skip bra #word */ \ + else if (op == 00600377) \ + pc += 6; /* skip bra #long */ \ + else if ((op & 0177400) == 0060000) \ + pc += 2; /* skip bra #char */ \ +} + + +/* 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 0x10800000 + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x10000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x4f} + +/* Data segment starts at etext rounded up to DATAROUND in {N,Z}MAGIC files */ + +#define DATAROUND 0x20000 +#define N_DATADDR(hdr) (hdr.a_magic != OMAGIC ? \ + (hdr.a_text + DATAROUND) & ~(DATAROUND-1) : hdr.a_text) + +/* Text segment starts at sizeof (struct exec) in {N,Z}MAGIC files */ + +#define N_TXTADDR(hdr) (hdr.a_magic != OMAGIC ? sizeof (struct exec) : 0) + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. + On the ISI, the kernel resets the pc to the trap instr */ + +#define DECR_PC_AFTER_BREAK 0 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* 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 registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 29 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "ps", "pc", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr" } + +/* 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 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PS_REGNUM 16 /* Contains processor status */ +#define PC_REGNUM 17 /* Contains program counter */ +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ + +#ifdef BSD43_ISI40D +#define BLOCKFUDGE 0x400000 +#else +#define BLOCKFUDGE 0 +#endif +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ blockend -= BLOCKFUDGE; \ + if (regno < 2) addr = blockend - 0x18 + regno * 4; \ + else if (regno < 8) addr = blockend - 0x54 + regno * 4; \ + else if (regno < 10) addr = blockend - 0x30 + regno * 4;\ + else if (regno < 15) addr = blockend - 0x5c + regno * 4;\ + else if (regno < 16) addr = blockend - 0x1c; \ + else if (regno < 18) addr = blockend - 0x44 + regno * 4;\ + else if (regno < 26) addr = (int) ((struct user *)0)->u_68881_regs \ + + (regno - 18) * 12; \ + else if (regno < 29) addr = (int) ((struct user *)0)->u_68881_regs \ + + 8 * 12 + (regno - 26) * 4; \ +} + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8*12+8+20) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 12 bytes. */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 8-byte doubles. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 12 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_from_68881 ((FROM), (TO)); \ + else \ + 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) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_to_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : 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) \ + { write_register (9, (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. */ + +/* In the case of the ISI, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#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(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + register int insn; \ + register int offset; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info)->pc); \ + /* Verify we have a link a6 instruction next, \ + or a branch followed by a link a6 instruction; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ +retry: \ + insn = read_memory_integer (pc, 2); \ + if (insn == 044016) \ + next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 4), pc+=4; \ + else if (insn == 047126) \ + next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 2), pc+=2; \ + else if ((insn & 0177400) == 060000) /* bra insn */ \ + { offset = insn & 0377; \ + pc += 2; /* advance past bra */ \ + if (offset == 0) /* bra #word */ \ + offset = read_memory_integer (pc, 2), pc += 2; \ + else if (offset == 0377) /* bra #long */ \ + offset = read_memory_integer (pc, 4), pc += 4; \ + pc += offset; \ + goto retry; \ + } else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + insn = read_memory_integer (pc, 2), pc += 2; \ + regmask = read_memory_integer (pc, 2); \ + if ((insn & 0177760) == 022700) /* movl rn, (sp) */ \ + (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr; \ + else if ((insn & 0177760) == 024700) /* movl rn, -(sp) */ \ + (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr-=4; \ + else if (insn == 0044327) /* moveml mask, (sp) */ \ + { pc += 2; \ + /* Regmask's low bit is for register 0, the first written */ \ + next_addr -= 4; \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4); \ + } else if (insn == 0044347) /* moveml mask, -(sp) */ \ + { pc += 2; \ + /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (read_memory_integer (pc, 2) == 041147 \ + && read_memory_integer (pc+2, 2) == 042347) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ +} + +/* Compensate for lack of `vprintf' function. */ +#define vprintf(format, ap) _doprnt (format, ap, stdout) + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 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 sequence of words is the instructions + fmovem #,-(sp) + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @#32323232 + addl #69696969,sp + bpt + nop +Note this is 24 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* 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 *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } + +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movl $ end, sp"); \ + asm ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } + +/* 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 \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } diff --git a/gdb/m-isiinit.h b/gdb/m-isiinit.h deleted file mode 100644 index 3b5532a..0000000 --- a/gdb/m-isiinit.h +++ /dev/null @@ -1,11 +0,0 @@ -/* Customize initialize.h for Integrated Solutions machines. */ - -/* Define this if you are using system version 4; undefine it for - version 3. This alters the action of m-isi-ov.h as well as this file. */ -#define BSD43_ISI40D - -#ifdef BSD43_ISI40D -#define FILEADDR_ROUND(addr) (addr) -#else -#define FILEADDR_ROUND(addr) ((addr + 3) & -4) -#endif diff --git a/gdb/m-merlin.h b/gdb/m-merlin.h index ec06135..196d734 100644 --- a/gdb/m-merlin.h +++ b/gdb/m-merlin.h @@ -94,6 +94,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define NS32K_SVC_IMMED_OPERANDS +/* 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 @@ -216,6 +222,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! : builtin_type_float) \ : builtin_type_int) +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. + + On this machine this is a no-op, as gcc doesn't run on it yet. + This calling convention is not used. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) + /* 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. */ @@ -251,21 +265,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* In the case of the Merlin, the frame's nominal address is the FP value, and at that address is saved previous FP value as a 4-byte word. */ -#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4)) +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) /* compute base of arguments */ -#define FRAME_ARGS_ADDRESS(fi) ((fi).frame) +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) -#define FRAME_LOCALS_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. */ @@ -276,7 +290,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! int addr_mode; \ int width; \ \ - pc = FRAME_SAVED_PC (fi.frame,0); \ + pc = FRAME_SAVED_PC (fi); \ insn = read_memory_integer (pc,2); \ addr_mode = (insn >> 11) & 0x1f; \ insn = insn & 0x7ff; \ @@ -311,17 +325,17 @@ anyone else from sharing it farther. Help stamp out software hoarding! CORE_ADDR enter_addr; \ CORE_ADDR next_addr; \ \ - enter_addr = get_pc_function_start ((frame_info).pc); \ + enter_addr = get_pc_function_start ((frame_info)->pc); \ regmask = read_memory_integer (enter_addr+1, 1); \ localcount = ns32k_localcount (enter_addr); \ - next_addr = (frame_info).frame + localcount; \ + next_addr = (frame_info)->frame + localcount; \ for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \ (frame_saved_regs).regs[regnum] \ = (regmask & 1) ? (next_addr -= 4) : 0; \ - (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 4; \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 4; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ (frame_saved_regs).regs[FP_REGNUM] \ - = read_memory_integer ((frame_info).frame, 4); } + = read_memory_integer ((frame_info)->frame, 4); } /* Compensate for lack of `vprintf' function. */ #define vprintf(format, ap) _doprnt (format, ap, stdout) @@ -344,18 +358,23 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* Discard from the stack the innermost frame, restoring all registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = 0; regnum < 8; regnum++) \ if (fsr.regs[regnum]) \ write_register (regnum, read_memory_integer (fsr.regs[regnum], 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 sequence of words is the instructions @@ -375,7 +394,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { int flipped = fun | 0xc0000000; \ flip_bytes (&flipped, 4); \ *((int *) (((char *) dummyname)+CALL_DUMMY_ADDR)) = flipped; \ diff --git a/gdb/m-news.h b/gdb/m-news.h index 9a0f114..4edf594 100644 --- a/gdb/m-news.h +++ b/gdb/m-news.h @@ -1,14 +1,17 @@ /* Parameters for execution on a Sony/NEWS, for GDB, the GNU debugger. + Probably ths parameters is match as news800, news700 and news900. -Here is an m-news800.h file for gdb version 2.1. It supports the reading -the 68881 registers, but the kernel doesn't know how to write them -and probably cannot write the frame pointer register either. +Here is an m-news800.h file for gdb version 2.6. It supports the 68881 +registers. -Now(9/2 '87) NEWS's printf has a bug. -And support Sun assembly format instead of Motorola one. -Probably not well support floating registers from core file rarely that +(hikichi@srava.sra.junet or hikichi%srava.sra.junet%kddlabs@uunet.uu.net + and now hikichi@wheaties.ai.mit.edu) +* Now(9/2 '87) NEWS's printf has a bug. +* And support Sun assembly format instead of Motorola one. +* Probably not well support floating registers from core file rarely that I do not know detail. -(hikichi@srava.sra.junet or hikichi%srava.sra.junet%kddlabs%seismo.CSS.GOV) +* Ptrace for handling floating register has a bug(7/3 '87), but not fixed +yet. We cannot write floating register. Copyright (C) 1987 Free Software Foundation, Inc. @@ -34,6 +37,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define news800 #endif +/* Use GNU assembler instead of standard assembler */ #define USE_GAS /* Motorola assembly format */ @@ -41,16 +45,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define MOTOROLA #endif -/* bug when printf special number; NAN */ -#define PRINTF_BUG - /* 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 -/* Debugger info will be in DBX format. */ - +/* Symbols on this machine are in DBX format. */ #define READ_DBX_FORMAT /* Offset from address of function to start of its code. @@ -109,6 +109,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ +/* 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 registers are. */ #define REGISTER_TYPE long @@ -215,27 +221,24 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define REGISTER_VIRTUAL_TYPE(N) \ (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : 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) \ + { write_register (9, (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) \ - { if (TYPE_CODE (TYPE) != TYPE_CODE_FLT) \ - bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)); \ - else \ - convert_from_68881 (REGBUF + REGISTER_BYTE (FP0_REGNUM), 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) \ - { if (TYPE_CODE (TYPE) != TYPE_CODE_FLT) \ - write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)); \ - else \ - { \ - char raw_buffer[12]; \ - convert_to_68881 (VALBUF, raw_buffer); \ - write_register_bytes (REGISTER_BYTE(FP0_REGNUM), raw_buffer, 12); }} + 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, @@ -262,26 +265,26 @@ read_memory_integer (read_register (SP_REGNUM), 4) /* In the case of the NEWS, the frame's nominal address is the address of a 4-byte word containing the calling frame's address. */ -#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4)) +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) -#define FRAME_ARGS_ADDRESS(fi) (fi.frame) +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) -#define FRAME_LOCALS_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(val, fi) \ -{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ register int insn = 0177777 & read_memory_integer (pc, 2); \ val = 0; \ if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ @@ -311,12 +314,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) register int insn; \ register int offset; \ bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ - && (frame_info).pc <= (frame_info).frame) \ - { next_addr = (frame_info).frame; \ - pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ else \ - { pc = get_pc_function_start ((frame_info).pc); \ + { pc = get_pc_function_start ((frame_info)->pc); \ /* Verify we have a link a6 instruction next, \ or a branch followed by a link a6 instruction; \ if not we lose. If we win, find the address above the saved \ @@ -324,9 +327,9 @@ read_memory_integer (read_register (SP_REGNUM), 4) retry: \ insn = read_memory_integer (pc, 2); \ if (insn == 044016) \ - next_addr = (frame_info).frame - read_memory_integer (pc += 2, 4), pc+=4; \ + next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 4), pc+=4; \ else if (insn == 047126) \ - next_addr = (frame_info).frame - read_memory_integer (pc += 2, 2), pc+=2; \ + next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 2), pc+=2; \ else if ((insn & 0177400) == 060000) /* bra insn */ \ { offset = insn & 0377; \ pc += 2; /* advance past bra */ \ @@ -366,15 +369,15 @@ retry: \ && read_memory_integer (pc+2, 2) == 042347) \ (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ lose: ; \ - (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ - (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ } /* Things needed for making the inferior call functions. */ /* Push an empty stack frame, to record the current PC, etc. */ - +#if 0 /* now these define is not used */ #define PUSH_DUMMY_FRAME \ { register CORE_ADDR sp = read_register (SP_REGNUM); \ register int regnum; \ @@ -393,13 +396,15 @@ retry: \ /* Discard from the stack the innermost frame, restoring all registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ + struct frame_info *fi; \ char raw_buffer[12]; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ if (fsr.regs[regnum]) \ { read_memory (fsr.regs[regnum], raw_buffer, 12); \ @@ -412,8 +417,44 @@ retry: \ 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 ())); } +#else /* now ptrace has a bug to write floating register */ +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register 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 = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register 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 = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 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 ())); } +#endif /* This sequence of words is the instructions fmove.m #,-(sp) movem.l 0xfffc,-(sp) @@ -445,7 +486,7 @@ taken for the arguments. */ /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { *(int *)((char *) dummyname + 20) = nargs * 4; \ *(int *)((char *) dummyname + 14) = fun; } diff --git a/gdb/m-newsinit.h b/gdb/m-newsinit.h deleted file mode 100644 index d902edf..0000000 --- a/gdb/m-newsinit.h +++ /dev/null @@ -1,4 +0,0 @@ -/* This is how the size of an individual .o file's text segment - is rounded on a SONY NEWS. */ - -#define FILEADDR_ROUND(addr) ((addr + 3) & -4) diff --git a/gdb/m-npl.h b/gdb/m-npl.h index 422b74a..d2ceef9 100644 --- a/gdb/m-npl.h +++ b/gdb/m-npl.h @@ -17,8 +17,8 @@ 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! */ -/* Read file headers properly in core.c */ -#define gould +/* This code appears in libraries on Gould machines. Ignore it. */ +#define IGNORE_SYMBOL(type) (type == N_ENTRY) /* Macro for text-offset and data info (in NPL a.out format). */ #define TEXTINFO \ @@ -169,7 +169,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ the new frame is not set up until the new function executes some instructions. True on NPL! Return address is in R1. The true return address is REALLY 4 past that location! */ -#define SAVED_PC_AFTER_CALL(frame) \ +`#define SAVED_PC_AFTER_CALL(frame) \ (read_register(R1_REGNUM) + 4) /* Address of U in kernel space */ @@ -195,6 +195,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ /* Return 1 if P points to an invalid floating point value. */ #define INVALID_FLOAT(p, len) ((*(short *)p & 0xff80) == 0x8000) +/* Largest integer type */ +#define LONGEST long + +/* Name of the builtin type for the LONGEST type above. */ +#define BUILTIN_TYPE_LONGEST builtin_type_long + /* Say how long (ordinary) registers are. */ #define REGISTER_TYPE long @@ -296,6 +302,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ 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. + + On this machine this is a no-op, because gcc isn't used on it + yet. So this calling convention is not used. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) + /* Extract from an arrary REGBUF containing the (raw) register state a function return value of type TYPE, and copy that, in virtual format, into VALBUF. */ @@ -335,21 +349,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #define FRAME_CHAIN(thisframe) (findframe(thisframe)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && chain != thisframe) + (chain != 0 && chain != (thisframe)->frame) #define FRAME_CHAIN_COMBINE(chain, thisframe) \ (chain) /* Define other aspects of the stack frame on NPL. */ -#define FRAME_SAVED_PC(frame,ignore) \ - (read_memory_integer (frame + 8, 4)) +#define FRAME_SAVED_PC(FRAME) \ + (read_memory_integer ((FRAME)->frame + 8, 4)) #define FRAME_ARGS_ADDRESS(fi) \ - ((fi).next_frame ? \ - read_memory_integer ((fi).frame + 12, 4) : \ + ((fi)->next_frame ? \ + read_memory_integer ((fi)->frame + 12, 4) : \ read_register (AP_REGNUM)) -#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame + 80) +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame + 80) /* Set VAL to the number of args passed to frame described by FI. Can set VAL to -1, meaning no way to tell. */ @@ -370,11 +384,11 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ { \ bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 8; \ - (frame_saved_regs).regs[R4_REGNUM] = (frame_info).frame + 0x30; \ - (frame_saved_regs).regs[R5_REGNUM] = (frame_info).frame + 0x34; \ - (frame_saved_regs).regs[R6_REGNUM] = (frame_info).frame + 0x38; \ - (frame_saved_regs).regs[R7_REGNUM] = (frame_info).frame + 0x3C; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[R4_REGNUM] = (frame_info)->frame + 0x30; \ + (frame_saved_regs).regs[R5_REGNUM] = (frame_info)->frame + 0x34; \ + (frame_saved_regs).regs[R6_REGNUM] = (frame_info)->frame + 0x38; \ + (frame_saved_regs).regs[R7_REGNUM] = (frame_info)->frame + 0x3C; \ } /* Things needed for making the inferior call functions. */ @@ -396,12 +410,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ restoring all saved registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ if (fsr.regs[regnum]) \ write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ @@ -410,7 +426,9 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ 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); \ - set_current_frame (read_register (FP_REGNUM)); } + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } /* This sequence of words is the instructions: halt @@ -443,7 +461,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { *(int *)((char *) dummyname + 20) = nargs * 4; \ *(int *)((char *) dummyname + 14) = fun; } diff --git a/gdb/m-nplinit.h b/gdb/m-nplinit.h deleted file mode 100644 index 840c2c7..0000000 --- a/gdb/m-nplinit.h +++ /dev/null @@ -1,4 +0,0 @@ -/* This is how the size of an individual .o file's text segment - is rounded on a NP1. See np1-pinsn.c for rounding function. */ - -#define FILEADDR_ROUND(addr) (((int)(addr) + 31) & ~0xf) diff --git a/gdb/m-pn.h b/gdb/m-pn.h index 3cfdb03..a5f7ea1 100644 --- a/gdb/m-pn.h +++ b/gdb/m-pn.h @@ -17,8 +17,8 @@ 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! */ -/* Read file headers properly in core.c */ -#define gould +/* This code appears in libraries on Gould machines. Ignore it. */ +#define IGNORE_SYMBOL(type) (type == N_ENTRY) /* Macro for text-offset and data info (in PN a.out format). */ #define TEXTINFO \ @@ -195,6 +195,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ /* Return 1 if P points to an invalid floating point value. */ #define INVALID_FLOAT(p, len) ((*(short *)p & 0xff80) == 0x8000) +/* Largest integer type */ +#define LONGEST long + +/* Name of the builtin type for the LONGEST type above. */ +#define BUILTIN_TYPE_LONGEST builtin_type_long + /* Say how long (ordinary) registers are. */ #define REGISTER_TYPE long @@ -280,6 +286,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ 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. + + On this machine this is a no-op, because gcc isn't used on it + yet. So this calling convention is not used. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) + /* Extract from an arrary REGBUF containing the (raw) register state a function return value of type TYPE, and copy that, in virtual format, into VALBUF. */ @@ -319,21 +333,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #define FRAME_CHAIN(thisframe) (findframe(thisframe)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && chain != thisframe) + (chain != 0 && chain != (thisframe)->frame) #define FRAME_CHAIN_COMBINE(chain, thisframe) \ (chain) /* Define other aspects of the stack frame on NPL. */ -#define FRAME_SAVED_PC(frame,ignore) \ - (read_memory_integer (frame + 8, 4)) +#define FRAME_SAVED_PC(frame) \ + (read_memory_integer ((frame)->frame + 8, 4)) #define FRAME_ARGS_ADDRESS(fi) \ - ((fi).next_frame ? \ - read_memory_integer ((fi).frame + 12, 4) : \ + ((fi)->next_frame ? \ + read_memory_integer ((fi)->frame + 12, 4) : \ read_register (AP_REGNUM)) -#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame + 80) +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame + 80) /* Set VAL to the number of args passed to frame described by FI. Can set VAL to -1, meaning no way to tell. */ @@ -354,11 +368,11 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ { \ bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 8; \ - (frame_saved_regs).regs[R4_REGNUM] = (frame_info).frame + 0x30; \ - (frame_saved_regs).regs[R5_REGNUM] = (frame_info).frame + 0x34; \ - (frame_saved_regs).regs[R6_REGNUM] = (frame_info).frame + 0x38; \ - (frame_saved_regs).regs[R7_REGNUM] = (frame_info).frame + 0x3C; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[R4_REGNUM] = (frame_info)->frame + 0x30; \ + (frame_saved_regs).regs[R5_REGNUM] = (frame_info)->frame + 0x34; \ + (frame_saved_regs).regs[R6_REGNUM] = (frame_info)->frame + 0x38; \ + (frame_saved_regs).regs[R7_REGNUM] = (frame_info)->frame + 0x3C; \ } /* Things needed for making the inferior call functions. */ @@ -380,12 +394,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ restoring all saved registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ if (fsr.regs[regnum]) \ write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ @@ -394,7 +410,9 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ 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); \ - set_current_frame (read_register (FP_REGNUM)); } + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } /* This sequence of words is the instructions: halt @@ -427,7 +445,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { *(int *)((char *) dummyname + 20) = nargs * 4; \ *(int *)((char *) dummyname + 14) = fun; } diff --git a/gdb/m-pninit.h b/gdb/m-pninit.h deleted file mode 100644 index 4f12eaa..0000000 --- a/gdb/m-pninit.h +++ /dev/null @@ -1,4 +0,0 @@ -/* This is how the size of an individual .o file's text segment - is rounded on a Concept. See pn-pinsn.c for rounding function. */ - -#define FILEADDR_ROUND(addr) (((int)(addr) + 7) & ~0x7) diff --git a/gdb/m-sun4.h b/gdb/m-sparc.h similarity index 53% rename from gdb/m-sun4.h rename to gdb/m-sparc.h index 255cb56..7cde3f1 100644 --- a/gdb/m-sun4.h +++ b/gdb/m-sparc.h @@ -36,6 +36,17 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define READ_DBX_FORMAT +/* Big or Little-Endian target machine + BITS: defined if bit #0 is the high-order bit of a byte. + BYTES:defined if byte#0 is the high-order byte of an int. + WORDS:defined if word#0 is the high-order word of a double. */ +#define BITS_BIG_ENDIAN +#define BYTES_BIG_ENDIAN +#define WORDS_BIG_ENDIAN + +/* Floating point is IEEE compatible. */ +#define IEEE_FLOAT + /* Offset from address of function to start of its code. Zero on most machines. */ @@ -56,13 +67,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! encodes the structure size being returned. If we detect such a fake insn, step past it. */ -#define PC_ADJUST(pc) ((read_memory_integer (pc + 8, 4) & 0xfffffe00) == 0 ? pc+12 : pc+8) +#define PC_ADJUST(pc) ((read_memory_integer (pc + 8, 4) & 0xfffffe00) == 0 ? \ + pc+12 : pc+8) #define SAVED_PC_AFTER_CALL(frame) PC_ADJUST (read_register (RP_REGNUM)) /* Address of end of stack space. */ -#define STACK_END_ADDR 0xf000000 +#define STACK_END_ADDR 0xf8000000 /* Stack grows downward. */ @@ -93,6 +105,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ +/* 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 @@ -146,6 +164,19 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* ?? */ #define REGISTER_BYTE(N) ((N)*4) +/* The SPARC processor has register windows. */ + +#define HAVE_REGISTER_WINDOWS + +/* Is this register part of the register window system? A yes answer + implies that 1) The name of this register will not be the same in + other frames, and 2) This register is automatically "saved" (out + registers shifting into ins counts) upon subroutine calls and thus + there is no need to search more than one stack frame for it. */ + +#define REGISTER_IN_WINDOW_P(regnum) \ + ((regnum) >= 8 && (regnum) < 32) + /* Number of bytes of storage in the actual machine representation for register N. */ @@ -189,14 +220,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! of data in register N. */ #define REGISTER_VIRTUAL_TYPE(N) \ - ((N) < 32 ? builtin_type_int : (N) < 64 ? builtin_type_float : builtin_type_int) + ((N) < 32 ? builtin_type_int : (N) < 64 ? builtin_type_float : \ + builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { write_memory ((SP)+(16*4), &(ADDR), 4); } /* 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 ((int *)REGBUF+8, VALBUF, TYPE_LENGTH (TYPE)) + bcopy (((int *)(REGBUF))+8, (VALBUF), TYPE_LENGTH (TYPE)) /* Write into appropriate registers a function return value of type TYPE, given in virtual format. */ @@ -208,7 +246,8 @@ anyone else from sharing it farther. Help stamp out software hoarding! 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) (read_memory_integer (((int *)(REGBUF))[SP_REGNUM]+(16*4), 4)) +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ + (read_memory_integer (((int *)(REGBUF))[SP_REGNUM]+(16*4), 4)) /* Enable use of alternate code to read and write registers. */ @@ -227,9 +266,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define READ_GDB_SYMSEGS -/* The SPARC processor has register windows. */ - -#define HAVE_REGISTER_WINDOWS /* Describe the pointer in each stack frame to the previous stack frame (its caller). */ @@ -253,26 +289,56 @@ anyone else from sharing it farther. Help stamp out software hoarding! On the Sun4, the frame (in %fp) is %sp for the previous frame. From the previous frame's %sp, we can find the previous frame's - %fp: it is in the save area just above the previous frame's %sp. */ + %fp: it is in the save area just above the previous frame's %sp. + + If we are setting up an arbitrary frame, we'll need to know where + it ends. Hence the following. This part of the frame cache + structure should be checked before it is assumed that this frame's + bottom is in the stack pointer. + + If there isn't a frame below this one, the bottom of this frame is + in the stack pointer. + + If there is a frame below this one, and the frame pointers are + identical, it's a leaf frame and the bottoms are the same also. + + Otherwise the bottom of this frame is the top of the next frame. */ + +#define EXTRA_FRAME_INFO FRAME_ADDR bottom; +#define INIT_EXTRA_FRAME_INFO(fci) \ + (fci)->bottom = \ + ((fci)->next ? \ + ((fci)->frame == (fci)->next_frame ? \ + (fci)->next->bottom : (fci)->next->frame) : \ + read_register (SP_REGNUM)); #define FRAME_CHAIN(thisframe) \ - GET_RWINDOW_REG (thisframe, rw_in[6]) + GET_RWINDOW_REG ((thisframe)->frame, rw_in[6]) +/* Avoid checking FRAME_SAVED_PC since that screws us due to + improperly set up saved PC on a signal trampoline call */ +#if 0 #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe, 0) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) +#else +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0) +#endif #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame, next_frame) frame_saved_pc (frame, next_frame) +/* Where is the PC for a specific frame */ + +#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME) /* If the argument is on the stack, it will be here. */ -#define FRAME_ARGS_ADDRESS(fi) (fi.frame) +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) -#define FRAME_STRUCT_ARGS_ADDRESS(fi) (fi.frame) +#define FRAME_STRUCT_ARGS_ADDRESS(fi) ((fi)->frame) -#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) /* Set VAL to the number of args passed to frame described by FI. Can set VAL to -1, meaning no way to tell. */ @@ -291,101 +357,216 @@ anyone else from sharing it farther. Help stamp out software hoarding! ways in the stack frame. sp is even more special: the address we return for it IS the sp for the next frame. + Note that on register window machines, we are currently making the + assumption that window registers are being saved somewhere in the + frame in which they are being used. If they are stored in an + inferior frame, find_saved_register will break. + On the Sun 4, the only time all registers are saved is when a dummy frame is involved. Otherwise, the only saved registers are the LOCAL and IN registers which are saved as a result of the "save/restore" opcodes. This condition is determined by address rather than by value. */ -#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \ +#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \ { register int regnum; \ register CORE_ADDR pc; \ - FRAME frame = (fi).frame; \ - FRAME next_frame = (fi).next_frame; \ - bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - if ((fi).pc >= frame - CALL_DUMMY_LENGTH - 0x140 \ - && (fi).pc <= frame) \ + FRAME_ADDR frame = read_register (FP_REGNUM); \ + FRAME fid = FRAME_INFO_ID (fi); \ + if (!fid) fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS"); \ + bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \ + if ((fi)->pc >= frame - CALL_DUMMY_LENGTH - 0x140 \ + && (fi)->pc <= frame) \ { \ - for (regnum = 0; regnum < 32; regnum++) \ - (frame_saved_regs).regs[regnum+FP0_REGNUM] = frame + regnum * 4 - 0x80;\ for (regnum = 1; regnum < 8; regnum++) \ - (frame_saved_regs).regs[regnum] = frame + regnum * 4 - 0xa0; \ - for (regnum = 0; regnum < 8; regnum++) \ - (frame_saved_regs).regs[regnum+24] = frame + regnum * 4 - 0xc0; \ - for (regnum = 0; regnum < 8; regnum++) \ - (frame_saved_regs).regs[regnum+64] = frame + regnum * 4 - 0xe0; \ - frame = (fi).next_frame ? \ - (fi).next_frame : read_register (SP_REGNUM); \ + (frame_saved_regs).regs[regnum] = \ + frame + regnum * 4 - 0xa0; \ + for (regnum = 24; regnum < 32; regnum++) \ + (frame_saved_regs).regs[regnum] = \ + frame + (regnum - 24) * 4 - 0xc0; \ + for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++) \ + (frame_saved_regs).regs[regnum] = \ + frame + (regnum - FP0_REGNUM) * 4 - 0x80; \ + for (regnum = 64; regnum < NUM_REGS; regnum++) \ + (frame_saved_regs).regs[regnum] = \ + frame + (regnum - 64) * 4 - 0xe0; \ + frame = (fi)->bottom ? \ + (fi)->bottom : read_register (SP_REGNUM); \ } \ else \ { \ - for (regnum = 0; regnum < 16; regnum++) \ - (frame_saved_regs).regs[regnum+16] = frame + regnum * 4; \ + frame = (fi)->bottom ? \ + (fi)->bottom : read_register (SP_REGNUM); \ + for (regnum = 16; regnum < 32; regnum++) \ + (frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \ } \ - if (next_frame == 0) next_frame = read_register (SP_REGNUM); \ - for (regnum = 0; regnum < 8; regnum++) \ - (frame_saved_regs).regs[regnum+8] = next_frame + regnum * 4; \ - (frame_saved_regs).regs[FP_REGNUM] = frame + 14*4; \ + if ((fi)->next) \ + { \ + /* Pull off either the next frame pointer or \ + the stack pointer */ \ + FRAME_ADDR next_next_frame = \ + ((fi)->next->bottom ? \ + (fi)->next->bottom : \ + read_register (SP_REGNUM)); \ + for (regnum = 8; regnum < 16; regnum++) \ + (frame_saved_regs).regs[regnum] = next_next_frame + regnum * 4; \ + } \ + /* Otherwise, whatever we would get from ptrace(GETREGS) */ \ + /* is accurate */ \ + for (regnum = 30; regnum < 32; regnum++) \ + (frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \ (frame_saved_regs).regs[SP_REGNUM] = frame; \ (frame_saved_regs).regs[PC_REGNUM] = frame + 15*4; \ } /* Things needed for making the inferior call functions. */ +/* + * First of all, let me give my opinion of what the DUMMY_FRAME + * actually looks like. + * + * | | + * | | + * + - - - - - - - - - - - - - - - - +<-- fp (level 0) + * | | + * | | + * | | + * | | + * | Frame of innermost program | + * | function | + * | | + * | | + * | | + * | | + * | | + * |---------------------------------|<-- sp (level 0), fp (c) + * | | + * DUMMY | fp0-31 | + * | | + * | ------ |<-- fp - 0x80 + * FRAME | g0-7 |<-- fp - 0xa0 + * | i0-7 |<-- fp - 0xc0 + * | other |<-- fp - 0xe0 + * | ? | + * | ? | + * |---------------------------------|<-- sp' = fp - 0x140 + * | | + * xcution start | | + * sp' + 0x94 -->| CALL_DUMMY (x code) | + * | | + * | | + * |---------------------------------|<-- sp'' = fp - 0x200 + * | align sp to 8 byte boundary | + * | ==> args to fn <== | + * Room for | | + * i & l's + agg | CALL_DUMMY_STACK_ADJUST = 0x0x44| + * |---------------------------------|<-- final sp (variable) + * | | + * | Where function called will | + * | build frame. | + * | | + * | | + * + * I understand everything in this picture except what the space + * between fp - 0xe0 and fp - 0x140 is used for. Oh, and I don't + * understand why there's a large chunk of CALL_DUMMY that never gets + * executed (its function is superceeded by PUSH_DUMMY_FRAME; they + * are designed to do the same thing). + * + * PUSH_DUMMY_FRAME saves the registers above sp' and pushes the + * register file stack down one. + * + * call_function then writes CALL_DUMMY, pushes the args onto the + * stack, and adjusts the stack pointer. + * + * run_stack_dummy then starts execution (in the middle of + * CALL_DUMMY, as directed by call_function). + */ /* Push an empty stack frame, to record the current PC, etc. */ -/* NOTE: to be perfectly correct, we will probably have to restore the +/* Note: to be perfectly correct, we have to restore the IN registers (which were the OUT registers of the calling frame). */ +/* Note that the write's are of registers in the context of the newly + pushed frame. Thus the the fp*'s, the g*'s, the i*'s, and + the others, of the new frame, are being saved. + The locals are new; they don't need to be saved. The i's and l's of + the last frame were saved by the do_save_insn in the register + file (ie. on the stack, since a context switch happended imm after) */ +/* We note that the return pointer register does not *need* to have + the pc saved into it (return from this frame will be accomplished + by a POP_FRAME), however, just in case it might be needed, we will + leave it. However, we will write the original value of RP into the + location on the stack for saving i7 (what rp turns into upon call); + this way we don't loose the value with our function call. */ +/* Note that the pc saved must be 8 less than the actual pc, since + both POP_FRAME and the normal return sequence on the sparc return + to 8 more than the value of RP_REGNUM */ #define PUSH_DUMMY_FRAME \ { extern char registers[]; \ register int regnum; \ CORE_ADDR fp = read_register (FP_REGNUM); \ - CORE_ADDR pc = read_register (PC_REGNUM); \ + CORE_ADDR pc = read_register (PC_REGNUM) - 8; \ + CORE_ADDR rp = read_register (RP_REGNUM); \ void do_save_insn (); \ supply_register (RP_REGNUM, &pc); \ do_save_insn (0x140); \ fp = read_register (FP_REGNUM); \ - write_memory (fp - 0x80, ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * 4); \ + write_memory (fp - 0x80, ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * 4);\ write_memory (fp - 0xa0, ®isters[REGISTER_BYTE (0)], 8 * 4); \ - write_memory (fp - 0xc0, ®isters[REGISTER_BYTE (24)], 8 * 4); \ + write_memory (fp - 0xc0, ®isters[REGISTER_BYTE (24)], 7 * 4); \ + write_memory (fp - 0xa4, &rp, 4); \ write_memory (fp - 0xe0, ®isters[REGISTER_BYTE (64)], 8 * 4); \ } -/* Discard from the stack the innermost frame, - restoring all saved registers. */ +/* Discard from the stack the innermost frame, + restoring all saved registers. + Note that the values stored in fsr by get_frame_saved_regs are *in + the context of the inferior frame*. What this means is that the i + regs of fsr must be restored into the o regs of the frame popped + into. We don't care about the output regs of the inferior frame. + + This is true for dummy frames. Is it true for normal frames? It + really does appear so. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ - register int regnum; \ - struct frame_saved_regs fsr; \ - struct frame_info fi; \ - char raw_buffer_fp[REGISTER_BYTES]; \ - char raw_buffer_globals[REGISTER_BYTES]; \ - char raw_buffer_outs[REGISTER_BYTES]; \ - char raw_buffer_xx[REGISTER_BYTES]; \ - void do_restore_insn (); \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ - if (fsr.regs[FP0_REGNUM]) \ - read_memory (fsr.regs[FP0_REGNUM], raw_buffer_fp, 32 * 4); \ - if (fsr.regs[1]) \ - read_memory (fsr.regs[1], raw_buffer_globals, 7 * 4); \ - if (fsr.regs[24]) \ - read_memory (fsr.regs[24], raw_buffer_outs, 8 * 4); \ - if (fsr.regs[64]) \ - read_memory (fsr.regs[64], raw_buffer_xx, 8 * 4); \ - do_restore_insn (fsr.regs); \ - if (fsr.regs[FP0_REGNUM]) \ - write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer_fp, 32 * 4); \ - if (fsr.regs[1]) \ - write_register_bytes (REGISTER_BYTE (1), raw_buffer_globals, 7 * 4);\ - if (fsr.regs[24]) \ - write_register_bytes (REGISTER_BYTE (8), raw_buffer_outs, 8 * 4); \ - if (fsr.regs[64]) \ - write_register_bytes (REGISTER_BYTE (64), raw_buffer_xx, 8 * 4); \ - set_current_frame (read_register (FP_REGNUM)); \ -} +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register CORE_ADDR pc; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + char raw_buffer[REGISTER_BYTES]; \ + void do_restore_insn (); \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + pc = read_memory_integer (fsr.regs[PC_REGNUM], 4); \ + do_restore_insn (PC_ADJUST (pc)); \ + if (fsr.regs[FP0_REGNUM]) \ + { \ + read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4); \ + write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer, 32 * 4); \ + } \ + if (fsr.regs[1]) \ + { \ + read_memory (fsr.regs[1], raw_buffer, 7 * 4); \ + write_register_bytes (REGISTER_BYTE (1), raw_buffer, 7 * 4); \ + } \ + if (fsr.regs[24]) \ + { \ + read_memory (fsr.regs[24], raw_buffer, 8 * 4); \ + write_register_bytes (REGISTER_BYTE (8), raw_buffer, 8 * 4); \ + } \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + if (fsr.regs[Y_REGNUM]) \ + write_register (Y_REGNUM, read_memory_integer (fsr.regs[Y_REGNUM], 4)); \ + if (fsr.regs[NPC_REGNUM]) \ + write_register (NPC_REGNUM, read_memory_integer (fsr.regs[NPC_REGNUM], 4)); \ + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM), \ + read_pc ())); } /* This sequence of words is the instructions @@ -429,15 +610,15 @@ anyone else from sharing it farther. Help stamp out software hoarding! /..* The arguments are pushed at this point by GDB; no code is needed in the dummy for this. - The CALL_DUMMY_START_OFFSET gives the position of - the following call instruction. *../ + The CALL_DUMMY_START_OFFSET gives the position of + the following ld instruction. *../ ld [%sp+0x58],%o5 - ld [%sp+0x44],%o4 + ld [%sp+0x54],%o4 ld [%sp+0x50],%o3 ld [%sp+0x4c],%o2 ld [%sp+0x48],%o1 - call 0x34343434 + call 0x00000000 ld [%sp+0x44],%o0 nop ta 1 @@ -466,7 +647,7 @@ arguments. */ 0xf03fbf40, 0x01000000, 0x01000000, 0x01000000, \ 0x01000000, 0x91580000, 0xd027bf50, 0x93500000, \ 0xd027bf4c, 0x91480000, 0xd027bf48, 0x91400000, \ - 0xd027bf44, 0xda03a058, 0xd803a044, 0xd603a050, \ + 0xd027bf44, 0xda03a058, 0xd803a054, 0xd603a050, \ 0xd403a04c, 0xd203a048, 0x40000000, 0xd003a044, \ 0x01000000, 0x91d02001, 0x01000000, 0x01000000} @@ -482,12 +663,29 @@ arguments. */ #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { \ *(int *)((char *) dummyname+168) = (0x40000000|((fun-(pc+168))>>2)); \ - if (TYPE_CODE (type) == TYPE_CODE_STRUCT || TYPE_CODE (type) == TYPE_CODE_UNION) \ + if (TYPE_CODE (type) == TYPE_CODE_STRUCT \ + || TYPE_CODE (type) == TYPE_CODE_UNION) \ *(int *)((char *) dummyname+176) = (TYPE_LENGTH (type) & 0x1fff); \ } + /* Sparc has no reliable single step ptrace call */ #define NO_SINGLE_STEP 1 +/* It does have a wait structure, and it might help things out . . . */ + +#define HAVE_WAIT_STRUCT + +/* Handle a feature in the sun4 compiler ("call .stret4" at the end of + functions returning structures). */ + +#define SUN4_COMPILER_FEATURE + +/* We need two arguments (in general) to the "info frame" command. + Note that the definition of this macro implies that there exists a + function "setup_arbitrary_frame" in mach-dep.c */ + +#define FRAME_SPECIFICATION_DYADIC + /* KDB stuff flushed for now. */ diff --git a/gdb/m-sun2.h b/gdb/m-sun2.h index 74181f8..e42bc57 100644 --- a/gdb/m-sun2.h +++ b/gdb/m-sun2.h @@ -86,6 +86,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ +/* 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 registers are. */ #define REGISTER_TYPE long @@ -162,6 +168,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) #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) \ + { write_register (9, (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. */ @@ -181,6 +193,18 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) +/* Enable use of alternate code to read and write registers. */ + +#define NEW_SUN_PTRACE + +/* Enable use of alternate code for Sun's format of core dump file. */ + +#define NEW_SUN_CORE + +/* Do implement the attach and detach commands. */ + +#define ATTACH_DETACH + /* This is a piece of magic that is given a register number REGNO and as BLOCKEND the address in the system of the end of the user structure and stores in ADDR the address in the kernel or core dump @@ -205,20 +229,20 @@ read_memory_integer (read_register (SP_REGNUM), 4) /* In the case of the Sun, the frame's nominal address is the address of a 4-byte word containing the calling frame's address. */ -#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4)) +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) -#define FRAME_ARGS_ADDRESS(fi) (fi.frame) +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) -#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) /* Set VAL to the number of args passed to frame described by FI. Can set VAL to -1, meaning no way to tell. */ @@ -229,7 +253,7 @@ read_memory_integer (read_register (SP_REGNUM), 4) #if 0 #define FRAME_NUM_ARGS(val, fi) \ -{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ register int insn = 0177777 & read_memory_integer (pc, 2); \ val = 0; \ if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ @@ -258,19 +282,19 @@ read_memory_integer (read_register (SP_REGNUM), 4) register CORE_ADDR next_addr; \ register CORE_ADDR pc; \ bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 4 \ - && (frame_info).pc <= (frame_info).frame) \ - { next_addr = (frame_info).frame; \ - pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4; }\ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4; }\ else \ - { pc = get_pc_function_start ((frame_info).pc); \ + { pc = get_pc_function_start ((frame_info)->pc); \ /* Verify we have a link a6 instruction next; \ if not we lose. If we win, find the address above the saved \ regs using the amount of storage from the link instruction. */\ if (044016 == read_memory_integer (pc, 2)) \ - next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \ else if (047126 == read_memory_integer (pc, 2)) \ - next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \ else goto lose; \ /* If have an addal #-n, sp next, adjust next_addr. */ \ if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ @@ -295,9 +319,9 @@ read_memory_integer (read_register (SP_REGNUM), 4) if (0x426742e7 == read_memory_integer (pc, 4)) \ (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ lose: ; \ - (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ - (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ } /* Things needed for making the inferior call functions. */ @@ -318,12 +342,14 @@ read_memory_integer (read_register (SP_REGNUM), 4) /* Discard from the stack the innermost frame, restoring all registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ if (fsr.regs[regnum]) \ write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ @@ -332,7 +358,9 @@ read_memory_integer (read_register (SP_REGNUM), 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 sequence of words is the instructions moveml 0xfffc,-(sp) @@ -364,7 +392,7 @@ taken for the arguments. */ /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { *(int *)((char *) dummyname + 16) = nargs * 4; \ *(int *)((char *) dummyname + 10) = fun; } diff --git a/gdb/m-sun2init.h b/gdb/m-sun2init.h deleted file mode 100644 index 2e2f08c..0000000 --- a/gdb/m-sun2init.h +++ /dev/null @@ -1,5 +0,0 @@ - -/* This is how the size of an individual .o file's text segment - is rounded on a sun. */ - -#define FILEADDR_ROUND(addr) (addr) diff --git a/gdb/m-sun2os4.h b/gdb/m-sun2os4.h new file mode 100644 index 0000000..9a56ce5 --- /dev/null +++ b/gdb/m-sun2os4.h @@ -0,0 +1,2 @@ +#include "m-sun2.h" +#define SUNOS4 diff --git a/gdb/m-sun3.h b/gdb/m-sun3.h index 9c4095e..1ac0ee1 100644 --- a/gdb/m-sun3.h +++ b/gdb/m-sun3.h @@ -85,6 +85,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ +/* 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 @@ -132,6 +138,8 @@ read_memory_integer (read_register (SP_REGNUM), 4) /* Number of bytes of storage in the actual machine representation for register N. On the 68000, all regs are 4 bytes except the floating point regs which are 12 bytes. */ +/* Note that the unsigned cast here forces the result of the + subtractiion to very high positive values if N < FP0_REGNUM */ #define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) @@ -178,6 +186,12 @@ read_memory_integer (read_register (SP_REGNUM), 4) #define REGISTER_VIRTUAL_TYPE(N) \ (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : 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) \ + { write_register (9, (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. */ @@ -230,20 +244,20 @@ read_memory_integer (read_register (SP_REGNUM), 4) /* In the case of the Sun, the frame's nominal address is the address of a 4-byte word containing the calling frame's address. */ -#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4)) +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) -#define FRAME_ARGS_ADDRESS(fi) (fi.frame) +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) -#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) /* Set VAL to the number of args passed to frame described by FI. Can set VAL to -1, meaning no way to tell. */ @@ -254,7 +268,7 @@ read_memory_integer (read_register (SP_REGNUM), 4) #if 0 #define FRAME_NUM_ARGS(val, fi) \ -{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ register int insn = 0177777 & read_memory_integer (pc, 2); \ val = 0; \ if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ @@ -284,19 +298,19 @@ read_memory_integer (read_register (SP_REGNUM), 4) register CORE_ADDR pc; \ int nextinsn; \ bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ - && (frame_info).pc <= (frame_info).frame) \ - { next_addr = (frame_info).frame; \ - pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ else \ - { pc = get_pc_function_start ((frame_info).pc); \ + { pc = get_pc_function_start ((frame_info)->pc); \ /* Verify we have a link a6 instruction next; \ if not we lose. If we win, find the address above the saved \ regs using the amount of storage from the link instruction. */\ if (044016 == read_memory_integer (pc, 2)) \ - next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \ else if (047126 == read_memory_integer (pc, 2)) \ - next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \ else goto lose; \ /* If have an addal #-n, sp next, adjust next_addr. */ \ if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ @@ -323,7 +337,7 @@ read_memory_integer (read_register (SP_REGNUM), 4) for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ if (regmask & 1) \ (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ - else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \ + else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) \ { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \ (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ /* fmovemx to index of sp may follow. */ \ @@ -340,9 +354,9 @@ read_memory_integer (read_register (SP_REGNUM), 4) if (0x426742e7 == read_memory_integer (pc, 4)) \ (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ lose: ; \ - (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ - (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ } /* Things needed for making the inferior call functions. */ @@ -368,13 +382,15 @@ read_memory_integer (read_register (SP_REGNUM), 4) restoring all saved registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ + struct frame_info *fi; \ char raw_buffer[12]; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ if (fsr.regs[regnum]) \ { read_memory (fsr.regs[regnum], raw_buffer, 12); \ @@ -387,7 +403,9 @@ read_memory_integer (read_register (SP_REGNUM), 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); \ - set_current_frame (read_register (FP_REGNUM)); } + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } /* This sequence of words is the instructions fmovem 0xff,-(sp) @@ -420,7 +438,7 @@ taken for the arguments. */ /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { *(int *)((char *) dummyname + 20) = nargs * 4; \ *(int *)((char *) dummyname + 14) = fun; } diff --git a/gdb/m-sun3init.h b/gdb/m-sun3init.h deleted file mode 100644 index 5f71ea1..0000000 --- a/gdb/m-sun3init.h +++ /dev/null @@ -1,5 +0,0 @@ - -/* This is how the size of an individual .o file's text segment - is rounded on a sun. */ - -#define FILEADDR_ROUND(addr) ((addr + 3) & -4) diff --git a/gdb/m-sun3os4.h b/gdb/m-sun3os4.h new file mode 100644 index 0000000..cd1821b --- /dev/null +++ b/gdb/m-sun3os4.h @@ -0,0 +1,3 @@ +#include "m-sun3.h" +#define SUNOS4 +#define FPU diff --git a/gdb/m-sun4init.h b/gdb/m-sun4init.h deleted file mode 100644 index a1edc20..0000000 --- a/gdb/m-sun4init.h +++ /dev/null @@ -1,5 +0,0 @@ - -/* This is how the size of an individual .o file's text segment - is rounded on a sun. */ - -#define FILEADDR_ROUND(addr) ((addr + 7) & -8) diff --git a/gdb/m-sun4os4.h b/gdb/m-sun4os4.h new file mode 100644 index 0000000..3bed867 --- /dev/null +++ b/gdb/m-sun4os4.h @@ -0,0 +1,3 @@ +#include "m-sparc.h" +#define SUNOS4 +#define FPU diff --git a/gdb/m-suninit.h b/gdb/m-suninit.h deleted file mode 100644 index 5f71ea1..0000000 --- a/gdb/m-suninit.h +++ /dev/null @@ -1,5 +0,0 @@ - -/* This is how the size of an individual .o file's text segment - is rounded on a sun. */ - -#define FILEADDR_ROUND(addr) ((addr + 3) & -4) diff --git a/gdb/m-umax.h b/gdb/m-umax.h index 1065728..2ef3965 100644 --- a/gdb/m-umax.h +++ b/gdb/m-umax.h @@ -103,6 +103,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! NaF (*(float *) p) : \ NaD (*(double *) p)) +/* 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 @@ -228,6 +234,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! builtin_type_int : \ builtin_type_double) +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. + + On this machine this is a no-op, because gcc isn't used on it + yet. So this calling convention is not used. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) + /* 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. */ @@ -263,24 +277,24 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* In the case of the ns32000 series, the frame's nominal address is the FP value, and at that address is saved previous FP value as a 4-byte word. */ -#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4)) +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) /* Compute base of arguments. */ #define FRAME_ARGS_ADDRESS(fi) \ - ((ns32k_get_enter_addr (fi.pc) > 1) ? \ - ((fi).frame) : (read_register (SP_REGNUM) - 4)) + ((ns32k_get_enter_addr ((fi)->pc) > 1) ? \ + ((fi)->frame) : (read_register (SP_REGNUM) - 4)) -#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame) +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) /* Get the address of the enter opcode for this function, if it is active. Returns positive address > 1 if pc is between enter/exit, @@ -306,12 +320,12 @@ extern CORE_ADDR ns32k_get_enter_addr (); int width; \ \ numargs = -1; \ - enter_addr = ns32k_get_enter_addr (fi.pc); \ + enter_addr = ns32k_get_enter_addr ((fi)->pc); \ if (enter_addr > 0) \ { \ pc = (enter_addr == 1) ? \ - SAVED_PC_AFTER_CALL () : \ - FRAME_SAVED_PC (fi.frame,0); \ + SAVED_PC_AFTER_CALL (fi) : \ + FRAME_SAVED_PC (fi); \ insn = read_memory_integer (pc,2); \ addr_mode = (insn >> 11) & 0x1f; \ insn = insn & 0x7ff; \ @@ -350,19 +364,19 @@ extern CORE_ADDR ns32k_get_enter_addr (); register CORE_ADDR next_addr; \ \ bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \ - enter_addr = ns32k_get_enter_addr ((frame_info).pc); \ + enter_addr = ns32k_get_enter_addr ((frame_info)->pc); \ if (enter_addr > 1) \ { \ regmask = read_memory_integer (enter_addr+1, 1) & 0xff; \ localcount = ns32k_localcount (enter_addr); \ - next_addr = (frame_info).frame + localcount; \ + next_addr = (frame_info)->frame + localcount; \ for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \ (frame_saved_regs).regs[regnum] = (regmask & 1) ? \ (next_addr -= 4) : 0; \ - (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 4;\ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4;\ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 4;\ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4;\ (frame_saved_regs).regs[FP_REGNUM] = \ - (read_memory_integer ((frame_info).frame, 4));\ + (read_memory_integer ((frame_info)->frame, 4));\ } \ else if (enter_addr == 1) \ { \ @@ -393,19 +407,23 @@ extern CORE_ADDR ns32k_get_enter_addr (); /* Discard from the stack the innermost frame, restoring all registers. */ #define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ register int regnum; \ struct frame_saved_regs fsr; \ - struct frame_info fi; \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ for (regnum = 0; regnum < 8; regnum++) \ if (fsr.regs[regnum]) \ write_register (regnum, read_memory_integer (fsr.regs[regnum], 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 sequence of words is the instructions enter 0xff,0 82 ff 00 @@ -424,7 +442,7 @@ extern CORE_ADDR ns32k_get_enter_addr (); /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { \ int flipped; \ flipped = fun | 0xc0000000; \ diff --git a/gdb/m-umaxinit.h b/gdb/m-umaxinit.h deleted file mode 100644 index 34cc75a..0000000 --- a/gdb/m-umaxinit.h +++ /dev/null @@ -1,4 +0,0 @@ -/* This is how the size of an individual .o file's text segment - is rounded on the multimax. */ - -#define FILEADDR_ROUND(addr) ((addr + 3) & -4) diff --git a/gdb/m-vax.h b/gdb/m-vax.h index 1d973bf..60595cf 100644 --- a/gdb/m-vax.h +++ b/gdb/m-vax.h @@ -43,10 +43,25 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* Advance PC across any function entry prologue instructions to reach some "real" code. */ -#define SKIP_PROLOGUE(pc) \ -{ register int op = read_memory_integer (pc, 1); \ - if (op == 0x11) pc += 2; /* skip brb */ \ - if (op == 0x31) pc += 3; /* skip brw */ \ +#define SKIP_PROLOGUE(pc) \ +{ register int op = (unsigned char) read_memory_integer (pc, 1); \ + if (op == 0x11) pc += 2; /* skip brb */ \ + if (op == 0x31) pc += 3; /* skip brw */ \ + if (op == 0xC2 && \ + ((unsigned char) read_memory_integer (pc+2, 1)) == 0x5E) \ + pc += 3; /* skip subl2 */ \ + if (op == 0x9E && \ + ((unsigned char) read_memory_integer (pc+1, 1)) == 0xAE && \ + ((unsigned char) read_memory_integer(pc+3, 1)) == 0x5E) \ + pc += 4; /* skip movab */ \ + if (op == 0x9E && \ + ((unsigned char) read_memory_integer (pc+1, 1)) == 0xCE && \ + ((unsigned char) read_memory_integer(pc+4, 1)) == 0x5E) \ + pc += 5; /* skip movab */ \ + if (op == 0x9E && \ + ((unsigned char) read_memory_integer (pc+1, 1)) == 0xEE && \ + ((unsigned char) read_memory_integer(pc+6, 1)) == 0x5E) \ + pc += 7; /* skip movab */ \ } /* Immediately after a function call, return the saved pc. @@ -54,7 +69,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! the new frame is not set up until the new function executes some instructions. */ -#define SAVED_PC_AFTER_CALL(frame) FRAME_SAVED_PC(frame,0) +#define SAVED_PC_AFTER_CALL(frame) FRAME_SAVED_PC(frame) /* This is the amount to subtract from u.u_ar0 to get the offset in the core file of the register values. */ @@ -88,6 +103,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000) +/* Largest integer type */ +#define LONGEST long + +/* Name of the builtin type for the LONGEST type above. */ +#define BUILTIN_TYPE_LONGEST builtin_type_long + /* Say how long (ordinary) registers are. */ #define REGISTER_TYPE long @@ -171,6 +192,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! #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) \ + { write_register (1, (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. */ @@ -190,8 +217,8 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) -/* Compensate for lack of `vprintf' function. */ -#define vprintf(format, ap) _doprnt (format, ap, stdout) +/* Compensate for lack of `vprintf' function. */ +#define vprintf(format, ap) _doprnt (format, ap, stdout) /* Describe the pointer in each stack frame to the previous stack frame (its caller). */ @@ -209,26 +236,26 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* In the case of the Vax, the frame's nominal address is the FP value, and 12 bytes later comes the saved previous FP value as a 4-byte word. */ -#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe + 12, 4)) +#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame + 12, 4)) #define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe,ignore) >= first_object_file_end)) + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) /* Define other aspects of the stack frame. */ -#define FRAME_SAVED_PC(frame, ignore) (read_memory_integer (frame + 16, 4), 0) +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 16, 4)) /* Cannot find the AP register value directly from the FP value. Must find it saved in the frame called by this one, or in the AP register for the innermost frame. */ #define FRAME_ARGS_ADDRESS(fi) \ - (((fi).next_frame \ - ? read_memory_integer ((fi).next_frame + 8, 4) \ + (((fi)->next_frame \ + ? read_memory_integer ((fi)->next_frame + 8, 4) \ : read_register (AP_REGNUM))) -#define FRAME_LOCALS_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. */ @@ -248,21 +275,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ { register int regnum; \ - register int regmask = read_memory_integer ((frame_info).frame+4, 4) >> 16; \ + register int regmask = read_memory_integer ((frame_info)->frame+4, 4) >> 16; \ register CORE_ADDR next_addr; \ bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - next_addr = (frame_info).frame + 16; \ + next_addr = (frame_info)->frame + 16; \ /* Regmask's low bit is for register 0, \ which is the first one that would be pushed. */ \ for (regnum = 0; regnum < 12; regnum++, regmask >>= 1) \ (frame_saved_regs).regs[regnum] = (regmask & 1) ? (next_addr += 4) : 0; \ (frame_saved_regs).regs[SP_REGNUM] = next_addr + 4; \ - if (read_memory_integer ((frame_info).frame + 4, 4) & 0x20000000) \ + if (read_memory_integer ((frame_info)->frame + 4, 4) & 0x20000000) \ (frame_saved_regs).regs[SP_REGNUM] += 4 + 4 * read_memory_integer (next_addr + 4, 4); \ - (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 16; \ - (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame + 12; \ - (frame_saved_regs).regs[AP_REGNUM] = (frame_info).frame + 8; \ - (frame_saved_regs).regs[PS_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 16; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame + 12; \ + (frame_saved_regs).regs[AP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[PS_REGNUM] = (frame_info)->frame + 4; \ } /* Things needed for making the inferior call functions. */ @@ -306,7 +333,9 @@ anyone else from sharing it farther. Help stamp out software hoarding! { regnum = read_memory_integer (fp, 4); \ fp += (regnum + 1) * 4; } \ write_register (SP_REGNUM, fp); \ - set_current_frame (read_register (FP_REGNUM)); } + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } /* This sequence of words is the instructions calls #69, @#32323232 @@ -320,7 +349,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* 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, fun, nargs) \ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ { *((char *) dummyname + 1) = nargs; \ *(int *)((char *) dummyname + 3) = fun; } diff --git a/gdb/m-vaxinit.h b/gdb/m-vaxinit.h deleted file mode 100644 index 6044867..0000000 --- a/gdb/m-vaxinit.h +++ /dev/null @@ -1,5 +0,0 @@ - -/* This is how the size of an individual .o file's text segment - is rounded on a vax. */ - -#define FILEADDR_ROUND(addr) ((addr + 3) & -4) diff --git a/gdb/m68k-opcode.h b/gdb/m68k-opcode.h index acb9df9..8f7c30f 100644 --- a/gdb/m68k-opcode.h +++ b/gdb/m68k-opcode.h @@ -655,38 +655,38 @@ struct m68k_opcode m68k_opcodes[] = {"fatanhx", two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7"}, {"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt"}, -{"fbeq", one(0xF081), one(0xF1FF), "IdBc"}, -{"fbf", one(0xF080), one(0xF1FF), "IdBc"}, -{"fbge", one(0xF093), one(0xF1FF), "IdBc"}, -{"fbgl", one(0xF096), one(0xF1FF), "IdBc"}, -{"fbgle", one(0xF097), one(0xF1FF), "IdBc"}, -{"fbgt", one(0xF092), one(0xF1FF), "IdBc"}, -{"fble", one(0xF095), one(0xF1FF), "IdBc"}, -{"fblt", one(0xF094), one(0xF1FF), "IdBc"}, -{"fbne", one(0xF08E), one(0xF1FF), "IdBc"}, -{"fbnge", one(0xF09C), one(0xF1FF), "IdBc"}, -{"fbngl", one(0xF099), one(0xF1FF), "IdBc"}, -{"fbngle", one(0xF098), one(0xF1FF), "IdBc"}, -{"fbngt", one(0xF09D), one(0xF1FF), "IdBc"}, -{"fbnle", one(0xF09A), one(0xF1FF), "IdBc"}, -{"fbnlt", one(0xF09B), one(0xF1FF), "IdBc"}, -{"fboge", one(0xF083), one(0xF1FF), "IdBc"}, -{"fbogl", one(0xF086), one(0xF1FF), "IdBc"}, -{"fbogt", one(0xF082), one(0xF1FF), "IdBc"}, -{"fbole", one(0xF085), one(0xF1FF), "IdBc"}, -{"fbolt", one(0xF084), one(0xF1FF), "IdBc"}, -{"fbor", one(0xF087), one(0xF1FF), "IdBc"}, -{"fbseq", one(0xF091), one(0xF1FF), "IdBc"}, -{"fbsf", one(0xF090), one(0xF1FF), "IdBc"}, -{"fbsne", one(0xF09E), one(0xF1FF), "IdBc"}, -{"fbst", one(0xF09F), one(0xF1FF), "IdBc"}, -{"fbt", one(0xF08F), one(0xF1FF), "IdBc"}, -{"fbueq", one(0xF089), one(0xF1FF), "IdBc"}, -{"fbuge", one(0xF08B), one(0xF1FF), "IdBc"}, -{"fbugt", one(0xF08A), one(0xF1FF), "IdBc"}, -{"fbule", one(0xF08D), one(0xF1FF), "IdBc"}, -{"fbult", one(0xF08C), one(0xF1FF), "IdBc"}, -{"fbun", one(0xF088), one(0xF1FF), "IdBc"}, +{"fbeq", one(0xF081), one(0xF1BF), "IdBc"}, +{"fbf", one(0xF080), one(0xF1BF), "IdBc"}, +{"fbge", one(0xF093), one(0xF1BF), "IdBc"}, +{"fbgl", one(0xF096), one(0xF1BF), "IdBc"}, +{"fbgle", one(0xF097), one(0xF1BF), "IdBc"}, +{"fbgt", one(0xF092), one(0xF1BF), "IdBc"}, +{"fble", one(0xF095), one(0xF1BF), "IdBc"}, +{"fblt", one(0xF094), one(0xF1BF), "IdBc"}, +{"fbne", one(0xF08E), one(0xF1BF), "IdBc"}, +{"fbnge", one(0xF09C), one(0xF1BF), "IdBc"}, +{"fbngl", one(0xF099), one(0xF1BF), "IdBc"}, +{"fbngle", one(0xF098), one(0xF1BF), "IdBc"}, +{"fbngt", one(0xF09D), one(0xF1BF), "IdBc"}, +{"fbnle", one(0xF09A), one(0xF1BF), "IdBc"}, +{"fbnlt", one(0xF09B), one(0xF1BF), "IdBc"}, +{"fboge", one(0xF083), one(0xF1BF), "IdBc"}, +{"fbogl", one(0xF086), one(0xF1BF), "IdBc"}, +{"fbogt", one(0xF082), one(0xF1BF), "IdBc"}, +{"fbole", one(0xF085), one(0xF1BF), "IdBc"}, +{"fbolt", one(0xF084), one(0xF1BF), "IdBc"}, +{"fbor", one(0xF087), one(0xF1BF), "IdBc"}, +{"fbseq", one(0xF091), one(0xF1BF), "IdBc"}, +{"fbsf", one(0xF090), one(0xF1BF), "IdBc"}, +{"fbsne", one(0xF09E), one(0xF1BF), "IdBc"}, +{"fbst", one(0xF09F), one(0xF1BF), "IdBc"}, +{"fbt", one(0xF08F), one(0xF1BF), "IdBc"}, +{"fbueq", one(0xF089), one(0xF1BF), "IdBc"}, +{"fbuge", one(0xF08B), one(0xF1BF), "IdBc"}, +{"fbugt", one(0xF08A), one(0xF1BF), "IdBc"}, +{"fbule", one(0xF08D), one(0xF1BF), "IdBc"}, +{"fbult", one(0xF08C), one(0xF1BF), "IdBc"}, +{"fbun", one(0xF088), one(0xF1BF), "IdBc"}, {"fcmpb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7"}, {"fcmpd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7"}, @@ -905,11 +905,11 @@ struct m68k_opcode m68k_opcodes[] = {"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s"}, /* fmovem.x to control, static and dynamic: */ {"fmovemx", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s"}, /* fmovem.x to control, static and dynamic: */ -{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id#3+s"}, /* fmovem.x from autoincrement, static and dynamic: */ -{"fmovemx", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "IiDk+s"}, /* fmovem.x from autoincrement, static and dynamic: */ +{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3"}, /* fmovem.x from autoincrement, static and dynamic: */ +{"fmovemx", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk"}, /* fmovem.x from autoincrement, static and dynamic: */ -{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id#3&s"}, /* fmovem.x from control, static and dynamic: */ -{"fmovemx", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "IiDk&s"}, /* fmovem.x from control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3"}, /* fmovem.x from control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk"}, /* fmovem.x from control, static and dynamic: */ /* fmoveml and fmovel are the same instruction. This may cause some confusion in the assembler. */ @@ -936,6 +936,8 @@ struct m68k_opcode m68k_opcodes[] = {"fnegx", two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7"}, {"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt"}, +{"fnop", two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii"}, + {"fremb", two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7"}, {"fremd", two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7"}, {"freml", two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7"}, diff --git a/gdb/m68k-pinsn.c b/gdb/m68k-pinsn.c index 94ac7f7..c9e8af6 100644 --- a/gdb/m68k-pinsn.c +++ b/gdb/m68k-pinsn.c @@ -714,12 +714,12 @@ convert_from_68881 (from, to) char *from; double *to; { -#ifdef HPUX_ASM +#ifdef USG_SGS_ASM asm ("mov.l 8(%a6),%a0"); asm ("mov.l 12(%a6),%a1"); asm ("fmove.x (%a0),%fp0"); asm ("fmove.d %fp0,(%a1)"); -#else /* not HPUX_ASM */ +#else /* not USG_SGS_ASM */ #if 0 asm ("movl a6@(8),a0"); asm ("movl a6@(12),a1"); @@ -735,7 +735,7 @@ convert_from_68881 (from, to) asm (".long 0xf2104800"); asm (".long 0xf2117400"); #endif -#endif /* not HPUX_ASM */ +#endif /* not USG_SGS_ASM */ } /* The converse: convert the double *FROM to an extended float @@ -745,12 +745,12 @@ convert_to_68881 (from, to) double *from; char *to; { -#ifdef HPUX_ASM +#ifdef USG_SGS_ASM asm ("mov.l 8(%a6),%a0"); asm ("mov.l 12(%a6),%a1"); asm ("fmove.d (%a0),%fp0"); asm ("fmove.x %fp0,(%a1)"); -#else /* not HPUX_ASM */ +#else /* not USG_SGS_ASM */ #if 0 asm ("movl a6@(8),a0"); asm ("movl a6@(12),a1"); @@ -765,5 +765,5 @@ convert_to_68881 (from, to) asm (".long 0xf2105400"); asm (".long 0xf2116800"); #endif -#endif /* not HPUX_ASM */ +#endif /* not USG_SGS_ASM */ } diff --git a/gdb/main.c b/gdb/main.c index 1314155..5cd5e80 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -17,25 +17,36 @@ 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! */ +#include "defs.h" +#include "command.h" +#include "param.h" + +#ifdef USG +#include +#include +#endif #include #include #include #include #include -#include "defs.h" -#include "command.h" -#include "param.h" #ifdef SET_STACK_LIMIT_HUGE #include #include + +int original_stack_limit; #endif /* 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; @@ -44,6 +55,26 @@ struct cmd_list_element *cmdlist; 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; + /* stdio stream that command input is being read from. */ FILE *instream; @@ -59,12 +90,6 @@ static char dirbuf[MAXPATHLEN]; int inhibit_windows = 0; -/* Hook for window manager argument parsing. */ - -int *win_argc; -char **win_argv; -char *win_prgm; - /* Function to call before reading a command, if nonzero. The function receives two args: an input stream, and a prompt string. */ @@ -74,11 +99,12 @@ void (*window_hook) (); extern int frame_file_full_name; void free_command_lines (); -char *read_line (); -static void initialize_main (); +char *gdb_read_line (); +static void init_main (); +static void init_cmd_lists (); void command_loop (); static void source_command (); -void print_gdb_version (); +static void print_gdb_version (); /* gdb prints this when reading a command interactively */ static char *prompt; @@ -93,6 +119,7 @@ int linesize; jmp_buf to_top_level; +void return_to_top_level () { quit_flag = 0; @@ -117,6 +144,9 @@ catch_errors (func, arg, errstring) { jmp_buf saved; int val; + struct cleanup *saved_cleanup_chain; + + saved_cleanup_chain = save_cleanups (); bcopy (to_top_level, saved, sizeof (jmp_buf)); @@ -128,6 +158,8 @@ catch_errors (func, arg, errstring) val = 0; } + restore_cleanups (saved_cleanup_chain); + bcopy (saved, to_top_level, sizeof (jmp_buf)); return val; } @@ -142,6 +174,23 @@ disconnect () 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; +} + + +int main (argc, argv, envp) int argc; char **argv; @@ -162,10 +211,6 @@ main (argc, argv, envp) getwd (dirbuf); current_directory = dirbuf; - win_argc = &argc; - win_argv = argv; - win_prgm = argv[0]; - #ifdef SET_STACK_LIMIT_HUGE { struct rlimit rlim; @@ -173,6 +218,7 @@ main (argc, argv, envp) /* 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); } @@ -198,8 +244,9 @@ main (argc, argv, envp) /* Run the init function of each source file */ - initialize_all_files (); - initialize_main (); /* But that omits this file! Do it now */ + init_cmd_lists (); /* This needs to be done first */ + init_all_files (); + init_main (); /* But that omits this file! Do it now */ signal (SIGINT, request_quit); signal (SIGQUIT, SIG_IGN); @@ -351,17 +398,25 @@ execute_command (p, from_tty) error ("That is not a command, just a help topic."); else if (c->class == (int) class_user) { + struct cleanup *old_chain; + if (*p) error ("User-defined commands cannot take arguments."); cmdlines = (struct command_line *) c->function; if (cmdlines == (struct command_line *) 0) /* Null command */ return; + + /* Set the instream to 0, indicating execution of a + user-defined function. */ + old_chain = make_cleanup (source_cleanup, instream); + instream = (FILE *) 0; while (cmdlines) { execute_command (cmdlines->line, 0); cmdlines = cmdlines->next; } + do_cleanups (old_chain); } else /* Pass null arg rather than an empty one. */ @@ -382,16 +437,14 @@ command_loop () struct cleanup *old_chain; while (!feof (instream)) { - if (instream == stdin) - printf ("%s", prompt); - fflush (stdout); - if (window_hook && instream == stdin) (*window_hook) (instream, prompt); quit_flag = 0; old_chain = make_cleanup (do_nothing, 0); - execute_command (read_line (instream == stdin), instream == stdin); + execute_command (gdb_read_line (instream == stdin ? prompt : 0, + instream == stdin), + instream == stdin); /* Do any commands attached to breakpoint we stopped at. */ do_breakpoint_commands (); do_cleanups (old_chain); @@ -428,7 +481,8 @@ dont_repeat () Returns the address of the start of the line. */ char * -read_line (repeat) +gdb_read_line (prompt, repeat) + char *prompt; int repeat; { register char *p = line; @@ -443,6 +497,12 @@ read_line (repeat) signal (SIGTSTP, stop_sig); #endif + if (prompt) + { + printf (prompt); + fflush (stdout); + } + while (1) { c = fgetc (instream); @@ -504,7 +564,7 @@ read_command_lines () while (1) { dont_repeat (); - p = read_line (1); + p = gdb_read_line (0, 1); /* Remove leading and trailing blanks. */ while (*p == ' ' || *p == '\t') p++; p1 = p + strlen (p); @@ -568,7 +628,7 @@ add_info (name, fun, doc) void (*fun) (); char *doc; { - add_cmd (name, 0, fun, doc, &infolist); + add_cmd (name, no_class, fun, doc, &infolist); } /* Add an alias to the list of info subcommands. */ @@ -589,7 +649,7 @@ static void info_command () { printf ("\"info\" must be followed by the name of an info command.\n"); - help_cmd (0, infolist, "info ", -1, stdout); + help_list (infolist, "info ", -1, stdout); } /* Add an element to the list of commands. */ @@ -628,7 +688,7 @@ help_command (command, from_tty) char *command; int from_tty; /* Ignored */ { - help_cmd (command, cmdlist, "", -2, stdout); + help_cmd (command, stdout); } static void @@ -675,9 +735,11 @@ define_command (comname, from_tty) } if (from_tty) - printf ("Type commands for definition of \"%s\".\n\ + { + 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 (); @@ -760,7 +822,7 @@ if you want it, that you can change GDB or use pieces of it in new\n\ free programs, and that you know you can do these things.\n\ --Type Return to print more--"); fflush (stdout); - read_line (); + gdb_read_line (0, 0); printf ("\ To make sure that everyone has such rights, we have to forbid you to\n\ @@ -780,7 +842,7 @@ Inc.) make the following terms which say what you must do to be\n\ allowed to distribute or change GDB.\n\ --Type Return to print more--"); fflush (stdout); - read_line (); + gdb_read_line (0, 0); printf ("\ COPYING POLICIES\n\ @@ -803,7 +865,7 @@ Paragraph 1 above, provided that you also do the following:\n\ that you changed the files and the date of any change; and\n\ --Type Return to print more--"); fflush (stdout); - read_line (); + gdb_read_line (0, 0); printf ("\ b) cause the whole of any work that you distribute or publish,\n\ @@ -832,7 +894,7 @@ derivative) on a volume of a storage or distribution medium does not bring\n\ the other program under the scope of these terms.\n\ --Type Return to print more--"); fflush (stdout); - read_line (); + gdb_read_line (0, 0); printf ("\ 3. You may copy and distribute GDB (or a portion or derivative of it,\n\ @@ -861,7 +923,7 @@ source code for modules which are standard libraries that accompany the\n\ operating system on which the executable file runs.\n\ --Type Return to print more--"); fflush (stdout); - read_line (); + gdb_read_line (0, 0); printf ("\ 4. You may not copy, sublicense, distribute or transfer GDB\n\ @@ -872,6 +934,8 @@ automatically terminated. However, parties who have received computer\n\ software programs from you with this License Agreement will not have\n\ their licenses terminated so long as such parties remain in full compliance.\n\ \n\ +"); + printf ("\ 5. If you wish to incorporate parts of GDB into other free\n\ programs whose distribution conditions are different, write to the Free\n\ Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet\n\ @@ -1079,18 +1143,6 @@ cd_command (dir, from_tty) pwd_command ((char *) 0, 1); } -/* Clean up on error during a "source" command. - Close the file opened by the command - and restore the previous input stream. */ - -static void -source_cleanup (stream) - FILE *stream; -{ - fclose (instream); - instream = stream; -} - static void source_command (file) char *file; @@ -1151,9 +1203,21 @@ dump_me_command () } static void -initialize_main () +init_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; +} + +static void +init_main () { - prompt = savestring ("(gdb+) ", 7); + prompt = savestring ("(gdb) ", 6); /* Define the classes of commands. They will appear in the help list in the reverse of this order. */ @@ -1185,8 +1249,9 @@ The commands below can be used to select other frames by number or address.", The change does not take effect for the program being debugged\n\ until the next time it is started."); - add_com ("set-prompt", class_support, set_prompt_command, - "Change gdb's prompt from the default of \"(gdb)\""); + 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\ diff --git a/gdb/malloc.c b/gdb/malloc.c new file mode 100644 index 0000000..2099f0a --- /dev/null +++ b/gdb/malloc.c @@ -0,0 +1,869 @@ +/* dynamic memory allocation for GNU. + Copyright (C) 1985, 1987 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS 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. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1985 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file 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 or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution 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 unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute this 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 + shipping charge) 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.) + +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. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We 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. + + +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! */ + + +/* + * @(#)nmalloc.c 1 (Caltech) 2/21/82 + * + * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs + * + * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks + * that don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are (2^n)-4 (or -16) bytes long. + * This is designed for use in a program that uses vast quantities of + * memory, but bombs when it runs out. To make it a little better, it + * warns the user when he starts to get near the end. + * + * June 84, ACT: modified rcheck code to check the range given to malloc, + * rather than the range determined by the 2-power used. + * + * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. + * No longer Emacs-specific; can serve as all-purpose malloc for GNU. + * You should call malloc_init to reinitialize after loading dumped Emacs. + * Call malloc_stats to get info on memory stats if MSTATS turned on. + * realloc knows how to return same block given, just changing its size, + * if the power of 2 is correct. + */ + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information will + * go in the first int of the block, and the returned pointer will point + * to the second. + * +#ifdef MSTATS + * nmalloc[i] is the difference between the number of mallocs and frees + * for a given block size. +#endif MSTATS + */ + +#ifdef emacs +#include "config.h" +#endif /* emacs */ + +/* Determine which kind of system this is. */ +#include +#ifndef SIGTSTP +#ifndef VMS +#ifndef USG +#define USG +#endif +#endif /* not VMS */ +#else /* SIGTSTP */ +#ifdef SIGIO +#define BSD42 +#endif /* SIGIO */ +#endif /* SIGTSTP */ + +/* Define getpagesize () if the system does not. */ +#include "getpagesize.h" + +#ifndef BSD42 +#ifndef USG +#include /* warn the user when near the end */ +#endif /* not USG */ +#else /* if BSD42 */ +#include +#include +#endif /* BSD42 */ + +extern char *start_of_data (); + +#ifdef BSD +#ifndef DATA_SEG_BITS +#define start_of_data() &etext +#endif +#endif + +#ifndef emacs +#define start_of_data() &etext +#endif + +#define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ +#define ISFREE ((char) 0x54) /* magic byte that implies free block */ + /* this is for error checking only */ +#define ISMEMALIGN ((char) 0xd6) /* Stored before the value returned by + memalign, with the rest of the word + being the distance to the true + beginning of the block. */ + +extern char etext; + +/* These two are for user programs to look at, when they are interested. */ + +unsigned int malloc_sbrk_used; /* amount of data space used now */ +unsigned int malloc_sbrk_unused; /* amount more we can have */ + +/* start of data space; can be changed by calling init_malloc */ +static char *data_space_start; + +#ifdef MSTATS +static int nmalloc[30]; +static int nmal, nfre; +#endif /* MSTATS */ + +/* If range checking is not turned on, all we have is a flag indicating + whether memory is allocated, an index in nextf[], and a size field; to + realloc() memory we copy either size bytes or 1<<(index+3) bytes depending + on whether the former can hold the exact size (given the value of + 'index'). If range checking is on, we always need to know how much space + is allocated, so the 'size' field is never used. */ + +struct mhead { + char mh_alloc; /* ISALLOC or ISFREE */ + char mh_index; /* index in nextf[] */ +/* Remainder are valid only when block is allocated */ + unsigned short mh_size; /* size, if < 0x10000 */ +#ifdef rcheck + unsigned mh_nbytes; /* number of bytes allocated */ + int mh_magic4; /* should be == MAGIC4 */ +#endif /* rcheck */ +}; + +/* Access free-list pointer of a block. + It is stored at block + 4. + This is not a field in the mhead structure + because we want sizeof (struct mhead) + to describe the overhead for when the block is in use, + and we do not want the free-list pointer to count in that. */ + +#define CHAIN(a) \ + (*(struct mhead **) (sizeof (char *) + (char *) (a))) + +#ifdef rcheck + +/* To implement range checking, we write magic values in at the beginning and + end of each allocated block, and make sure they are undisturbed whenever a + free or a realloc occurs. */ +/* Written in each of the 4 bytes following the block's real space */ +#define MAGIC1 0x55 +/* Written in the 4 bytes before the block's real space */ +#define MAGIC4 0x55555555 +#define ASSERT(p) if (!(p)) botch("p"); else +#define EXTRA 4 /* 4 bytes extra for MAGIC1s */ +#else +#define ASSERT(p) +#define EXTRA 0 +#endif /* rcheck */ + + +/* nextf[i] is free list of blocks of size 2**(i + 3) */ + +static struct mhead *nextf[30]; + +/* busy[i] is nonzero while allocation of block size i is in progress. */ + +static char busy[30]; + +/* Number of bytes of writable memory we can expect to be able to get */ +static unsigned int lim_data; + +/* Level number of warnings already issued. + 0 -- no warnings issued. + 1 -- 75% warning already issued. + 2 -- 85% warning already issued. +*/ +static int warnlevel; + +/* Function to call to issue a warning; + 0 means don't issue them. */ +static void (*warnfunction) (); + +/* nonzero once initial bunch of free blocks made */ +static int gotpool; + +char *_malloc_base; + +static void getpool (); + +/* Cause reinitialization based on job parameters; + also declare where the end of pure storage is. */ +void +malloc_init (start, warnfun) + char *start; + void (*warnfun) (); +{ + if (start) + data_space_start = start; + lim_data = 0; + warnlevel = 0; + warnfunction = warnfun; +} + +/* Return the maximum size to which MEM can be realloc'd + without actually requiring copying. */ + +int +malloc_usable_size (mem) + char *mem; +{ + int blocksize = 8 << (((struct mhead *) mem) - 1) -> mh_index; + + return blocksize - sizeof (struct mhead) - EXTRA; +} + +static void +morecore (nu) /* ask system for more memory */ + register int nu; /* size index to get more of */ +{ + char *sbrk (); + register char *cp; + register int nblks; + register unsigned int siz; + int oldmask; + +#ifdef BSD +#ifndef BSD4_1 + oldmask = sigsetmask (-1); +#endif +#endif + + if (!data_space_start) + { + data_space_start = start_of_data (); + } + + if (lim_data == 0) + get_lim_data (); + + /* On initial startup, get two blocks of each size up to 1k bytes */ + if (!gotpool) + { getpool (); getpool (); gotpool = 1; } + + /* Find current end of memory and issue warning if getting near max */ + +#ifndef VMS + /* Maximum virtual memory on VMS is difficult to calculate since it + * depends on several dynmacially changing things. Also, alignment + * isn't that important. That is why much of the code here is ifdef'ed + * out for VMS systems. + */ + cp = sbrk (0); + siz = cp - data_space_start; + malloc_sbrk_used = siz; + malloc_sbrk_unused = lim_data - siz; + + if (warnfunction) + switch (warnlevel) + { + case 0: + if (siz > (lim_data / 4) * 3) + { + warnlevel++; + (*warnfunction) ("Warning: past 75% of memory limit"); + } + break; + case 1: + if (siz > (lim_data / 20) * 17) + { + warnlevel++; + (*warnfunction) ("Warning: past 85% of memory limit"); + } + break; + case 2: + if (siz > (lim_data / 20) * 19) + { + warnlevel++; + (*warnfunction) ("Warning: past 95% of memory limit"); + } + break; + } + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); +#endif /* not VMS */ + + /* Take at least 2k, and figure out how many blocks of the desired size + we're about to get */ + nblks = 1; + if ((siz = nu) < 8) + nblks = 1 << ((siz = 8) - nu); + + if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) + return; /* no more room! */ +#ifndef VMS + if ((int) cp & 7) + { /* shouldn't happen, but just in case */ + cp = (char *) (((int) cp + 8) & ~7); + nblks--; + } +#endif /* not VMS */ + + /* save new header and link the nblks blocks together */ + nextf[nu] = (struct mhead *) cp; + siz = 1 << (nu + 3); + while (1) + { + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + if (--nblks <= 0) break; + CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); + cp += siz; + } + CHAIN ((struct mhead *) cp) = 0; + +#ifdef BSD +#ifndef BSD4_1 + sigsetmask (oldmask); +#endif +#endif +} + +static void +getpool () +{ + register int nu; + char * sbrk (); + register char *cp = sbrk (0); + + if ((int) cp & 0x3ff) /* land on 1K boundaries */ + sbrk (1024 - ((int) cp & 0x3ff)); + + /* Record address of start of space allocated by malloc. */ + if (_malloc_base == 0) + _malloc_base = cp; + + /* Get 2k of storage */ + + cp = sbrk (04000); + if (cp == (char *) -1) + return; + + /* Divide it into an initial 8-word block + plus one block of size 2**nu for nu = 3 ... 10. */ + + CHAIN (cp) = nextf[0]; + nextf[0] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = 0; + cp += 8; + + for (nu = 0; nu < 7; nu++) + { + CHAIN (cp) = nextf[nu]; + nextf[nu] = (struct mhead *) cp; + ((struct mhead *) cp) -> mh_alloc = ISFREE; + ((struct mhead *) cp) -> mh_index = nu; + cp += 8 << nu; + } +} + +char * +malloc (n) /* get a block */ + unsigned n; +{ + register struct mhead *p; + register unsigned int nbytes; + register int nunits = 0; + + /* Figure out how many bytes are required, rounding up to the nearest + multiple of 4, then figure out which nextf[] area to use */ + nbytes = (n + sizeof *p + EXTRA + 3) & ~3; + { + register unsigned int shiftr = (nbytes - 1) >> 2; + + while (shiftr >>= 1) + nunits++; + } + + /* In case this is reentrant use of malloc from signal handler, + pick a block size that no other malloc level is currently + trying to allocate. That's the easiest harmless way not to + interfere with the other level of execution. */ + while (busy[nunits]) nunits++; + busy[nunits] = 1; + + /* If there are no blocks of the appropriate size, go get some */ + /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ + if (nextf[nunits] == 0) + morecore (nunits); + + /* Get one block off the list, and set the new list head */ + if ((p = nextf[nunits]) == 0) + { + busy[nunits] = 0; + return 0; + } + nextf[nunits] = CHAIN (p); + busy[nunits] = 0; + + /* Check for free block clobbered */ + /* If not for this check, we would gobble a clobbered free chain ptr */ + /* and bomb out on the NEXT allocate of this size block */ + if (p -> mh_alloc != ISFREE || p -> mh_index != nunits) +#ifdef rcheck + botch ("block on free list clobbered"); +#else /* not rcheck */ + abort (); +#endif /* not rcheck */ + + /* Fill in the info, and if range checking, set up the magic numbers */ + p -> mh_alloc = ISALLOC; +#ifdef rcheck + p -> mh_nbytes = n; + p -> mh_magic4 = MAGIC4; + { + register char *m = (char *) (p + 1) + n; + + *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; + } +#else /* not rcheck */ + p -> mh_size = n; +#endif /* not rcheck */ +#ifdef MSTATS + nmalloc[nunits]++; + nmal++; +#endif /* MSTATS */ + return (char *) (p + 1); +} + +free (mem) + char *mem; +{ + register struct mhead *p; + { + register char *ap = mem; + + if (ap == 0) + return; + + p = (struct mhead *) ap - 1; + if (p -> mh_alloc == ISMEMALIGN) + { + ap -= p->mh_size; + p = (struct mhead *) ap - 1; + } + +#ifndef rcheck + if (p -> mh_alloc != ISALLOC) + abort (); + +#else rcheck + if (p -> mh_alloc != ISALLOC) + { + if (p -> mh_alloc == ISFREE) + botch ("free: Called with already freed block argument\n"); + else + botch ("free: Called with bad argument\n"); + } + + ASSERT (p -> mh_magic4 == MAGIC4); + ap += p -> mh_nbytes; + ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); + ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); +#endif /* rcheck */ + } + { + register int nunits = p -> mh_index; + + ASSERT (nunits <= 29); + p -> mh_alloc = ISFREE; + + /* Protect against signal handlers calling malloc. */ + busy[nunits] = 1; + /* Put this block on the free list. */ + CHAIN (p) = nextf[nunits]; + nextf[nunits] = p; + busy[nunits] = 0; + +#ifdef MSTATS + nmalloc[nunits]--; + nfre++; +#endif /* MSTATS */ + } +} + +char * +realloc (mem, n) + char *mem; + register unsigned n; +{ + register struct mhead *p; + register unsigned int tocopy; + register unsigned int nbytes; + register int nunits; + + if ((p = (struct mhead *) mem) == 0) + return malloc (n); + p--; + nunits = p -> mh_index; + ASSERT (p -> mh_alloc == ISALLOC); +#ifdef rcheck + ASSERT (p -> mh_magic4 == MAGIC4); + { + register char *m = mem + (tocopy = p -> mh_nbytes); + ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); + ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); + } +#else /* not rcheck */ + if (p -> mh_index >= 13) + tocopy = (1 << (p -> mh_index + 3)) - sizeof *p; + else + tocopy = p -> mh_size; +#endif /* not rcheck */ + + /* See if desired size rounds to same power of 2 as actual size. */ + nbytes = (n + sizeof *p + EXTRA + 7) & ~7; + + /* If ok, use the same block, just marking its size as changed. */ + if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) + { +#ifdef rcheck + register char *m = mem + tocopy; + *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; + p-> mh_nbytes = n; + m = mem + n; + *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; +#else /* not rcheck */ + p -> mh_size = n; +#endif /* not rcheck */ + return mem; + } + + if (n < tocopy) + tocopy = n; + { + register char *new; + + if ((new = malloc (n)) == 0) + return 0; + bcopy (mem, new, tocopy); + free (mem); + return new; + } +} + +#ifndef VMS + +char * +memalign (alignment, size) + unsigned alignment, size; +{ + register char *ptr = malloc (size + alignment); + register char *aligned; + register struct mhead *p; + + if (ptr == 0) + return 0; + /* If entire block has the desired alignment, just accept it. */ + if (((int) ptr & (alignment - 1)) == 0) + return ptr; + /* Otherwise, get address of byte in the block that has that alignment. */ + aligned = (char *) (((int) ptr + alignment - 1) & -alignment); + + /* Store a suitable indication of how to free the block, + so that free can find the true beginning of it. */ + p = (struct mhead *) aligned - 1; + p -> mh_size = aligned - ptr; + p -> mh_alloc = ISMEMALIGN; + return aligned; +} + +#ifndef HPUX +/* This runs into trouble with getpagesize on HPUX. + Patching out seems cleaner than the ugly fix needed. */ +char * +valloc (size) +{ + return memalign (getpagesize (), size); +} +#endif /* not HPUX */ +#endif /* not VMS */ + +#ifdef MSTATS +/* Return statistics describing allocation of blocks of size 2**n. */ + +struct mstats_value + { + int blocksize; + int nfree; + int nused; + }; + +struct mstats_value +malloc_stats (size) + int size; +{ + struct mstats_value v; + register int i; + register struct mhead *p; + + v.nfree = 0; + + if (size < 0 || size >= 30) + { + v.blocksize = 0; + v.nused = 0; + return v; + } + + v.blocksize = 1 << (size + 3); + v.nused = nmalloc[size]; + + for (p = nextf[size]; p; p = CHAIN (p)) + v.nfree++; + + return v; +} +int +malloc_mem_used () +{ + int i; + int size_used; + + size_used = 0; + + for (i = 0; i < 30; i++) + { + int allocation_size = 1 << (i + 3); + struct mhead *p; + + size_used += nmalloc[i] * allocation_size; + } + + return size_used; +} + +int +malloc_mem_free () +{ + int i; + int size_unused; + + size_unused = 0; + + for (i = 0; i < 30; i++) + { + int allocation_size = 1 << (i + 3); + struct mhead *p; + + for (p = nextf[i]; p ; p = CHAIN (p)) + size_unused += allocation_size; + } + + return size_unused; +} +#endif /* MSTATS */ + +/* + * This function returns the total number of bytes that the process + * will be allowed to allocate via the sbrk(2) system call. On + * BSD systems this is the total space allocatable to stack and + * data. On USG systems this is the data space only. + */ + +#ifdef USG + +get_lim_data () +{ + extern long ulimit (); + +#ifdef ULIMIT_BREAK_VALUE + lim_data = ULIMIT_BREAK_VALUE; +#else + lim_data = ulimit (3, 0); +#endif + + lim_data -= (long) data_space_start; +} + +#else /* not USG */ +#ifndef BSD42 + +get_lim_data () +{ + lim_data = vlimit (LIM_DATA, -1); +} + +#else /* BSD42 */ + +get_lim_data () +{ + struct rlimit XXrlimit; + + getrlimit (RLIMIT_DATA, &XXrlimit); +#ifdef RLIM_INFINITY + lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */ +#else + lim_data = XXrlimit.rlim_cur; /* soft limit */ +#endif +} + +#endif /* BSD42 */ +#endif /* not USG */ + +#ifdef VMS +/* There is a problem when dumping and restoring things on VMS. Calls + * to SBRK don't necessarily result in contiguous allocation. Dumping + * doesn't work when it isn't. Therefore, we make the initial + * allocation contiguous by allocating a big chunk, and do SBRKs from + * there. Once Emacs has dumped there is no reason to continue + * contiguous allocation, malloc doesn't depend on it. + * + * There is a further problem of using brk and sbrk while using VMS C + * run time library routines malloc, calloc, etc. The documentation + * says that this is a no-no, although I'm not sure why this would be + * a problem. In any case, we remove the necessity to call brk and + * sbrk, by calling calloc (to assure zero filled data) rather than + * sbrk. + * + * VMS_ALLOCATION_SIZE is the size of the allocation array. This + * should be larger than the malloc size before dumping. Making this + * too large will result in the startup procedure slowing down since + * it will require more space and time to map it in. + * + * The value for VMS_ALLOCATION_SIZE in the following define was determined + * by running emacs linked (and a large allocation) with the debugger and + * looking to see how much storage was used. The allocation was 201 pages, + * so I rounded it up to a power of two. + */ +#ifndef VMS_ALLOCATION_SIZE +#define VMS_ALLOCATION_SIZE (512*256) +#endif + +/* Use VMS RTL definitions */ +#undef sbrk +#undef brk +#undef malloc +int vms_out_initial = 0; +char vms_initial_buffer[VMS_ALLOCATION_SIZE]; +static char *vms_current_brk = &vms_initial_buffer; +static char *vms_end_brk = &vms_initial_buffer[VMS_ALLOCATION_SIZE-1]; + +#include + +char * +sys_sbrk (incr) + int incr; +{ + char *sbrk(), *temp, *ptr; + + if (vms_out_initial) + { + /* out of initial allocation... */ + if (!(temp = malloc (incr))) + temp = (char *) -1; + } + else + { + /* otherwise, go out of our area */ + ptr = vms_current_brk + incr; /* new current_brk */ + if (ptr <= vms_end_brk) + { + temp = vms_current_brk; + vms_current_brk = ptr; + } + else + { + vms_out_initial = 1; /* mark as out of initial allocation */ + if (!(temp = malloc (incr))) + temp = (char *) -1; + } + } + return temp; +} +#endif /* VMS */ diff --git a/gdb/munch b/gdb/munch new file mode 100755 index 0000000..daecee4 --- /dev/null +++ b/gdb/munch @@ -0,0 +1,14 @@ +#! /bin/sh + +# create an initialization procedure from a list of .o files +# Look in object files, find symbols including the string _initialize_, +# and call each one as a function. + +echo '/* Do not modify this file. It is created automatically by "munch". */' +echo 'void init_all_files () {' + +nm $* | egrep '_initialize_' | \ + sed -e 's/^.*\(initialize_[a-zA-Z_0-9]*\).*$/ _\1 ();/' | \ + sort -u + +echo '}' diff --git a/gdb/news-dep.c b/gdb/news-dep.c new file mode 100644 index 0000000..fabaeae --- /dev/null +++ b/gdb/news-dep.c @@ -0,0 +1,547 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include +#if 0 +#include +#endif /* I don't think that I need this file. */ + +#include +#include +#include + +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); + } + } + /* Ptrace News OS cannot write floating register now(7/2/88), so + avoid the writing them. */ + else for (regno = 0; regno < FP0_REGNUM; 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); + } + } +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes 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. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#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; + +#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) + { + 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. */ + core_aouthdr.a_magic = 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) + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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; + + 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); +} diff --git a/gdb/ns32k-opcode.h b/gdb/ns32k-opcode.h index 2d5ff30..f72d013 100644 --- a/gdb/ns32k-opcode.h +++ b/gdb/ns32k-opcode.h @@ -40,6 +40,8 @@ notstrs[] = { "absw", 14,24, 0x314e, "1W2W" }, { "absd", 14,24, 0x334e, "1D2D" }, { "acbb", 7,16, 0x4c, "2B1q3p" }, + { "acbw", 7,16, 0x4d, "2W1q3p" }, + { "acbd", 7,16, 0x4f, "2D1q3p" }, { "addf", 14,24, 0x01be, "1F2F" }, { "addl", 14,24, 0x00be, "1L2L" }, { "addb", 6,16, 0x00, "1B2B" }, diff --git a/gdb/obstack.c b/gdb/obstack.c index 3b5bdef..4379911 100644 --- a/gdb/obstack.c +++ b/gdb/obstack.c @@ -212,6 +212,27 @@ _obstack_newchunk (h, length) 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. */ diff --git a/gdb/obstack.h b/gdb/obstack.h index f80f2b1..7ebb19c 100644 --- a/gdb/obstack.h +++ b/gdb/obstack.h @@ -290,9 +290,10 @@ int obstack_chunk_size (struct obstack *obstack); #define obstack_blank_fast(h,n) ((h)->next_free += (n)) -#ifdef __GNUC__ +#if defined (__GNUC__) && defined (__STDC__) -/* For GNU C we can define these macros to compute all args only once +/* 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. */ @@ -372,7 +373,7 @@ int obstack_chunk_size (struct obstack *obstack); __o->next_free = __o->object_base = __obj; \ else (obstack_free) (__o, __obj); }) -#else /* not __GNUC__ */ +#else /* not __GNUC__ or not __STDC__ */ /* The non-GNU macros copy the obstack-pointer into this global variable to avoid multiple evaluation. */ @@ -447,7 +448,7 @@ extern struct obstack *_obstack; : (int) _obstack_free ((h), (h)->temp + (char *) (h)->chunk))) #endif -#endif /* not __GNUC__ */ +#endif /* not __GNUC__ or not __STDC__ */ #endif /* not __OBSTACKS__ */ diff --git a/gdb/opcode.h b/gdb/opcode.h deleted file mode 100644 index 1122142..0000000 --- a/gdb/opcode.h +++ /dev/null @@ -1 +0,0 @@ -/* This file is empty. */ diff --git a/gdb/opcode.h b/gdb/opcode.h new file mode 120000 index 0000000..0ec9873 --- /dev/null +++ b/gdb/opcode.h @@ -0,0 +1 @@ +sparc-opcode.h \ No newline at end of file diff --git a/gdb/param.h b/gdb/param.h deleted file mode 100644 index 255cb56..0000000 --- a/gdb/param.h +++ /dev/null @@ -1,493 +0,0 @@ -/* Parameters for execution on a Sun 4, for GDB, the GNU debugger. - Copyright (C) 1986, 1987 Free Software Foundation, Inc. - Contributed by Michael Tiemann (tiemann@mcc.com) - -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! -*/ - -#ifndef sun4 -#define sun4 -#endif - -/* 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 - -/* Debugger information will be in DBX format. */ - -#define READ_DBX_FORMAT - -/* Offset from address of function to start of its code. - Zero on most machines. */ - -#define FUNCTION_START_OFFSET 0 - -/* Advance PC across any function entry prologue instructions - to reach some "real" code. */ - -#define SKIP_PROLOGUE(pc) \ - { pc = skip_prologue (pc); } - -/* Immediately after a function call, return the saved pc. - Can't go through the frames for this because on some machines - the new frame is not set up until the new function executes - some instructions. */ - -/* On the Sun 4 under SunOS, the compile will leave a fake insn which - encodes the structure size being returned. If we detect such - a fake insn, step past it. */ - -#define PC_ADJUST(pc) ((read_memory_integer (pc + 8, 4) & 0xfffffe00) == 0 ? pc+12 : pc+8) - -#define SAVED_PC_AFTER_CALL(frame) PC_ADJUST (read_register (RP_REGNUM)) - -/* Address of end of stack space. */ - -#define STACK_END_ADDR 0xf000000 - -/* Stack grows downward. */ - -#define INNER_THAN < - -/* Stack has strict alignment. */ - -#define STACK_ALIGN(ADDR) (((ADDR)+7)&-8) - -/* Sequence of bytes for breakpoint instruction. */ - -#define BREAKPOINT {0x91, 0xd0, 0x20, 0x01} - -/* Amount PC must be decremented by after a breakpoint. - This is often the number of bytes in BREAKPOINT - but not always. */ - -#define DECR_PC_AFTER_BREAK 0 - -/* Nonzero if instruction at PC is a return instruction. */ -/* For SPARC, this is either a "jmpl %o7+8,%g0" or "jmpl %i7+8,%g0". - - Note: this does not work for functions returning structures under SunOS. */ -#define ABOUT_TO_RETURN(pc) \ - ((read_memory_integer (pc, 4)|0x00040000) == 0x81c7e008) - -/* Return 1 if P points to an invalid floating point value. */ - -#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ - -/* Say how long (ordinary) registers are. */ - -#define REGISTER_TYPE long - -/* Number of machine registers */ - -#define NUM_REGS 72 - -/* Initializer for an array of names of registers. - There should be NUM_REGS strings in this initializer. */ - -#define REGISTER_NAMES \ -{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", \ - "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", \ - "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", \ - "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", \ - \ - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \ - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \ - \ - "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" }; - -/* 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 30 /* Contains address of executing stack frame */ -#define RP_REGNUM 15 /* Contains return address value, *before* \ - any windows get switched. */ -#define SP_REGNUM 14 /* Contains address of top of stack, \ - which is also the bottom of the frame. */ -#define Y_REGNUM 64 /* Temp register for multiplication, etc. */ -#define PS_REGNUM 65 /* Contains processor status */ -#define PC_REGNUM 68 /* Contains program counter */ -#define NPC_REGNUM 69 /* Contains next PC */ -#define FP0_REGNUM 32 /* Floating point register 0 */ -#define FPS_REGNUM 70 /* Floating point status register */ -#define CPS_REGNUM 71 /* Coprocessor status register */ - -/* Total amount of space needed to store our copies of the machine's - register state, the array `registers'. */ -#define REGISTER_BYTES (32*4+32*4+8*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. */ - -/* On the SPARC, all regs are 4 bytes. */ - -#define REGISTER_RAW_SIZE(N) (4) - -/* Number of bytes of storage in the program's representation - for register N. */ - -/* On the SPARC, all regs are 4 bytes. */ - -#define REGISTER_VIRTUAL_SIZE(N) (4) - -/* Largest value REGISTER_RAW_SIZE can have. */ - -#define MAX_REGISTER_RAW_SIZE 8 - -/* Largest value REGISTER_VIRTUAL_SIZE can have. */ - -#define MAX_REGISTER_VIRTUAL_SIZE 8 - -/* 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) \ - ((N) < 32 ? builtin_type_int : (N) < 64 ? builtin_type_float : builtin_type_int) - -/* 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 ((int *)REGBUF+8, VALBUF, TYPE_LENGTH (TYPE)) - -/* Write into appropriate registers a function return value - of type TYPE, given in virtual format. */ -/* On sparc, values are returned in register %o0. */ -#define STORE_RETURN_VALUE(TYPE,VALBUF) \ - write_register_bytes (REGISTER_BYTE (8), 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) (read_memory_integer (((int *)(REGBUF))[SP_REGNUM]+(16*4), 4)) - -/* Enable use of alternate code to read and write registers. */ - -#define NEW_SUN_PTRACE - -/* Enable use of alternate code for Sun's format of core dump file. */ - -#define NEW_SUN_CORE - -/* Do implement the attach and detach commands. */ - -#define ATTACH_DETACH - -/* It is safe to look for symsegs on a Sun, because Sun's ld - does not screw up with random garbage at end of file. */ - -#define READ_GDB_SYMSEGS - -/* The SPARC processor has register windows. */ - -#define HAVE_REGISTER_WINDOWS - -/* Describe the pointer in each stack frame to the previous stack frame - (its caller). */ -#include - -#define GET_RWINDOW_REG(FRAME, REG) \ - (read_memory_integer (&((struct rwindow *)FRAME)->REG, 4)) - -/* FRAME_CHAIN takes a frame's nominal address - and produces the frame's chain-pointer. - - FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address - and produces the nominal address of the caller frame. - - However, if FRAME_CHAIN_VALID returns zero, - it means the given frame is the outermost one and has no caller. - In that case, FRAME_CHAIN_COMBINE is not used. */ - -/* In the case of the Sun 4, the frame-chain's nominal address - is held in the frame pointer register. - - On the Sun4, the frame (in %fp) is %sp for the previous frame. - From the previous frame's %sp, we can find the previous frame's - %fp: it is in the save area just above the previous frame's %sp. */ - -#define FRAME_CHAIN(thisframe) \ - GET_RWINDOW_REG (thisframe, rw_in[6]) - -#define FRAME_CHAIN_VALID(chain, thisframe) \ - (chain != 0 && (FRAME_SAVED_PC (thisframe, 0) >= first_object_file_end)) - -#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) - -/* Define other aspects of the stack frame. */ - -#define FRAME_SAVED_PC(frame, next_frame) frame_saved_pc (frame, next_frame) - -/* If the argument is on the stack, it will be here. */ -#define FRAME_ARGS_ADDRESS(fi) (fi.frame) - -#define FRAME_STRUCT_ARGS_ADDRESS(fi) (fi.frame) - -#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) - -/* Set VAL to the number of args passed to frame described by FI. - Can set VAL to -1, meaning no way to tell. */ - -/* We can't tell how many args there are - now that the C compiler delays popping them. */ -#define FRAME_NUM_ARGS(val,fi) (val = -1) - -/* Return number of bytes at start of arglist that are not really args. */ - -#define FRAME_ARGS_SKIP 68 - -/* 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. - - On the Sun 4, the only time all registers are saved is when - a dummy frame is involved. Otherwise, the only saved registers - are the LOCAL and IN registers which are saved as a result - of the "save/restore" opcodes. This condition is determined - by address rather than by value. */ - -#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \ -{ register int regnum; \ - register CORE_ADDR pc; \ - FRAME frame = (fi).frame; \ - FRAME next_frame = (fi).next_frame; \ - bzero (&frame_saved_regs, sizeof frame_saved_regs); \ - if ((fi).pc >= frame - CALL_DUMMY_LENGTH - 0x140 \ - && (fi).pc <= frame) \ - { \ - for (regnum = 0; regnum < 32; regnum++) \ - (frame_saved_regs).regs[regnum+FP0_REGNUM] = frame + regnum * 4 - 0x80;\ - for (regnum = 1; regnum < 8; regnum++) \ - (frame_saved_regs).regs[regnum] = frame + regnum * 4 - 0xa0; \ - for (regnum = 0; regnum < 8; regnum++) \ - (frame_saved_regs).regs[regnum+24] = frame + regnum * 4 - 0xc0; \ - for (regnum = 0; regnum < 8; regnum++) \ - (frame_saved_regs).regs[regnum+64] = frame + regnum * 4 - 0xe0; \ - frame = (fi).next_frame ? \ - (fi).next_frame : read_register (SP_REGNUM); \ - } \ - else \ - { \ - for (regnum = 0; regnum < 16; regnum++) \ - (frame_saved_regs).regs[regnum+16] = frame + regnum * 4; \ - } \ - if (next_frame == 0) next_frame = read_register (SP_REGNUM); \ - for (regnum = 0; regnum < 8; regnum++) \ - (frame_saved_regs).regs[regnum+8] = next_frame + regnum * 4; \ - (frame_saved_regs).regs[FP_REGNUM] = frame + 14*4; \ - (frame_saved_regs).regs[SP_REGNUM] = frame; \ - (frame_saved_regs).regs[PC_REGNUM] = frame + 15*4; \ -} - -/* Things needed for making the inferior call functions. */ - -/* Push an empty stack frame, to record the current PC, etc. */ - -/* NOTE: to be perfectly correct, we will probably have to restore the - IN registers (which were the OUT registers of the calling frame). */ - -#define PUSH_DUMMY_FRAME \ -{ extern char registers[]; \ - register int regnum; \ - CORE_ADDR fp = read_register (FP_REGNUM); \ - CORE_ADDR pc = read_register (PC_REGNUM); \ - void do_save_insn (); \ - supply_register (RP_REGNUM, &pc); \ - do_save_insn (0x140); \ - fp = read_register (FP_REGNUM); \ - write_memory (fp - 0x80, ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * 4); \ - write_memory (fp - 0xa0, ®isters[REGISTER_BYTE (0)], 8 * 4); \ - write_memory (fp - 0xc0, ®isters[REGISTER_BYTE (24)], 8 * 4); \ - write_memory (fp - 0xe0, ®isters[REGISTER_BYTE (64)], 8 * 4); \ -} - -/* Discard from the stack the innermost frame, - restoring all saved registers. */ - -#define POP_FRAME \ -{ register CORE_ADDR fp = read_register (FP_REGNUM); \ - register int regnum; \ - struct frame_saved_regs fsr; \ - struct frame_info fi; \ - char raw_buffer_fp[REGISTER_BYTES]; \ - char raw_buffer_globals[REGISTER_BYTES]; \ - char raw_buffer_outs[REGISTER_BYTES]; \ - char raw_buffer_xx[REGISTER_BYTES]; \ - void do_restore_insn (); \ - fi = get_frame_info (fp); \ - get_frame_saved_regs (&fi, &fsr); \ - if (fsr.regs[FP0_REGNUM]) \ - read_memory (fsr.regs[FP0_REGNUM], raw_buffer_fp, 32 * 4); \ - if (fsr.regs[1]) \ - read_memory (fsr.regs[1], raw_buffer_globals, 7 * 4); \ - if (fsr.regs[24]) \ - read_memory (fsr.regs[24], raw_buffer_outs, 8 * 4); \ - if (fsr.regs[64]) \ - read_memory (fsr.regs[64], raw_buffer_xx, 8 * 4); \ - do_restore_insn (fsr.regs); \ - if (fsr.regs[FP0_REGNUM]) \ - write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer_fp, 32 * 4); \ - if (fsr.regs[1]) \ - write_register_bytes (REGISTER_BYTE (1), raw_buffer_globals, 7 * 4);\ - if (fsr.regs[24]) \ - write_register_bytes (REGISTER_BYTE (8), raw_buffer_outs, 8 * 4); \ - if (fsr.regs[64]) \ - write_register_bytes (REGISTER_BYTE (64), raw_buffer_xx, 8 * 4); \ - set_current_frame (read_register (FP_REGNUM)); \ -} - -/* This sequence of words is the instructions - - save %sp,-0x140,%sp - std %f30,[%fp-0x08] - std %f28,[%fp-0x10] - std %f26,[%fp-0x18] - std %f24,[%fp-0x20] - std %f22,[%fp-0x28] - std %f20,[%fp-0x30] - std %f18,[%fp-0x38] - std %f16,[%fp-0x40] - std %f14,[%fp-0x48] - std %f12,[%fp-0x50] - std %f10,[%fp-0x58] - std %f8,[%fp-0x60] - std %f6,[%fp-0x68] - std %f4,[%fp-0x70] - std %f2,[%fp-0x78] - std %f0,[%fp-0x80] - std %g6,[%fp-0x88] - std %g4,[%fp-0x90] - std %g2,[%fp-0x98] - std %g0,[%fp-0xa0] - std %i6,[%fp-0xa8] - std %i4,[%fp-0xb0] - std %i2,[%fp-0xb8] - std %i0,[%fp-0xc0] - nop ! stcsr [%fp-0xc4] - nop ! stfsr [%fp-0xc8] - nop ! wr %npc,[%fp-0xcc] - nop ! wr %pc,[%fp-0xd0] - rd %tbr,%o0 - st %o0,[%fp-0xd4] - rd %wim,%o1 - st %o0,[%fp-0xd8] - rd %psr,%o0 - st %o0,[%fp-0xdc] - rd %y,%o0 - st %o0,[%fp-0xe0] - - /..* The arguments are pushed at this point by GDB; - no code is needed in the dummy for this. - The CALL_DUMMY_START_OFFSET gives the position of - the following call instruction. *../ - - ld [%sp+0x58],%o5 - ld [%sp+0x44],%o4 - ld [%sp+0x50],%o3 - ld [%sp+0x4c],%o2 - ld [%sp+0x48],%o1 - call 0x34343434 - ld [%sp+0x44],%o0 - nop - ta 1 - nop - - note that this is 192 bytes, which is a multiple of 8 (not only 4) bytes. - note that the `call' insn is a relative, not an absolute call. - note that the `nop' at the end is needed to keep the trap from - clobbering things (if NPC pointed to garbage instead). - -We actually start executing at the `sethi', since the pushing of the -registers (as arguments) is done by PUSH_DUMMY_FRAME. If this were -real code, the arguments for the function called by the CALL would be -pushed between the list of ST insns and the CALL, and we could allow -it to execute through. But the arguments have to be pushed by GDB -after the PUSH_DUMMY_FRAME is done, and we cannot allow these ST -insns to be performed again, lest the registers saved be taken for -arguments. */ - -#define CALL_DUMMY { 0x9de3bee0, 0xfd3fbff8, 0xf93fbff0, 0xf53fbfe8, \ - 0xf13fbfe0, 0xed3fbfd8, 0xe93fbfd0, 0xe53fbfc8, \ - 0xe13fbfc0, 0xdd3fbfb8, 0xd93fbfb0, 0xd53fbfa8, \ - 0xd13fbfa0, 0xcd3fbf98, 0xc93fbf90, 0xc53fbf88, \ - 0xc13fbf80, 0xcc3fbf78, 0xc83fbf70, 0xc43fbf68, \ - 0xc03fbf60, 0xfc3fbf58, 0xf83fbf50, 0xf43fbf48, \ - 0xf03fbf40, 0x01000000, 0x01000000, 0x01000000, \ - 0x01000000, 0x91580000, 0xd027bf50, 0x93500000, \ - 0xd027bf4c, 0x91480000, 0xd027bf48, 0x91400000, \ - 0xd027bf44, 0xda03a058, 0xd803a044, 0xd603a050, \ - 0xd403a04c, 0xd203a048, 0x40000000, 0xd003a044, \ - 0x01000000, 0x91d02001, 0x01000000, 0x01000000} - -#define CALL_DUMMY_LENGTH 192 - -#define CALL_DUMMY_START_OFFSET 148 - -#define CALL_DUMMY_STACK_ADJUST 68 - -/* 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 *)((char *) dummyname+168) = (0x40000000|((fun-(pc+168))>>2)); \ - if (TYPE_CODE (type) == TYPE_CODE_STRUCT || TYPE_CODE (type) == TYPE_CODE_UNION) \ - *(int *)((char *) dummyname+176) = (TYPE_LENGTH (type) & 0x1fff); \ -} - -/* Sparc has no reliable single step ptrace call */ - -#define NO_SINGLE_STEP 1 - -/* KDB stuff flushed for now. */ diff --git a/gdb/param.h b/gdb/param.h new file mode 120000 index 0000000..4b050eb --- /dev/null +++ b/gdb/param.h @@ -0,0 +1 @@ +m-sparc.h \ No newline at end of file diff --git a/gdb/pinsn.c b/gdb/pinsn.c deleted file mode 100644 index e7aba32..0000000 --- a/gdb/pinsn.c +++ /dev/null @@ -1,811 +0,0 @@ -/* Print sparc instructions for GDB, the GNU debugger. - Copyright (C) 1986, 1987 Free Software Foundation, Inc. - Contributed by Michael Tiemann (tiemann@mcc.com) - -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! -*/ - -#include - -#include "defs.h" -#include "param.h" -#include "symtab.h" -#include "sparc-opcode.h" - -/* sparc instructions are never longer than this many bytes. */ -#define MAXLEN 4 - -/* Print the sparc instruction at address MEMADDR in debugged memory, - on STREAM. Returns length of the instruction, in bytes, which - is always 4. */ - -struct op1_fmt -{ - unsigned op1 : 2; - unsigned dummy : 30; -}; - -struct op2_fmt -{ - unsigned dummy1 : 7; - unsigned op2 : 3; - unsigned dummy2 : 22; -}; - -struct op3_fmt -{ - unsigned dummy1 : 7; - unsigned op3 : 6; - unsigned dummy2 : 19; -}; - -struct call_fmt -{ - unsigned op : 2; - unsigned disp : 30; -}; - -struct sethi_fmt -{ - unsigned op : 2; - unsigned rd : 5; - unsigned op2 : 3; - unsigned imm : 22; -}; - -struct branch_fmt -{ - unsigned op : 2; - unsigned a : 1; - unsigned cond : 4; - unsigned op2 : 3; - unsigned disp : 22; /* this should really be signed. */ -}; - -struct ldst_fmt -{ - unsigned op : 2; - unsigned rd : 5; - unsigned op3 : 6; - unsigned rs1 : 5; - unsigned i : 1; - unsigned asi : 8; - unsigned rs2 : 5; -}; - -struct arith_imm_fmt -{ - unsigned op : 2; - unsigned rd : 5; - unsigned op3 : 6; - unsigned rs1 : 5; - unsigned i : 1; - unsigned simm : 13; -}; - -struct arith_fmt -{ - unsigned op : 2; - unsigned rd : 5; - unsigned op3 : 6; - unsigned rs1 : 5; - unsigned i : 1; - unsigned opf : 8; - unsigned rs2 : 5; -}; - -union insn_fmt -{ - struct op1_fmt op1; - struct op2_fmt op2; - struct op3_fmt op3; - struct call_fmt call; - struct sethi_fmt sethi; - struct branch_fmt branch; - struct ldst_fmt ldst; - struct arith_imm_fmt arith_imm; - struct arith_fmt arith; - int intval; - float floatval; /* ?? */ -}; - -typedef enum -{ - Error, not_branch, bicc, bicca, ba, baa, ticc, ta, -} branch_type; - -static char *icc_name[] = -{ "~", "eq", "le", "lt", "leu", "ltu", "neg", "vs", - "", "ne", "gt", "ge", "gtu", "geu", "pos", "vc"}; - -static char *fcc_name[] = -{ "~fb", "fbne", "fblg", "fbul", "fbl", "fbug", "fbg", "fbu", - "fb", "fbe", "fbue", "fbge", "fbuge", "fble", "fbule", "fbo"}; - -static char *ccc_name[] = -{ "~cb", "cb123", "cb12", "cb13", "cb1", "cb23", "cb2", "cb3", - "cb", "cb0", "cb03", "cb02", "cb023", "cb01", "cb013", "cb012"}; - -static char *arith_name[] = -{ "add", "and", "or", "xor", "sub", "andn", "orn", "xnor", - "addx", 0, 0, 0, "subx", 0, 0, 0}; - -static char *xarith_name[] = -{ "taddcc", "tsubcc", "taddcctv", "tsubcctv", "mulscc", "sll", "srl", "sra"}; - -static char *state_reg_name[] = -{ "%y", "%psr", "%wim", "%tbr", 0, 0, 0, 0}; - -static char *ldst_i_name[] = -{ "ld", "ldub", "lduh", "ldd", "st", "stb", "sth", "std", - 0, "ldsb", "ldsh", 0, 0, "ldstub", 0, "swap", - "lda", "lduba", "lduha", "ldda", "sta", "stba", "stha", "stda", - 0, "ldsba", "ldsha", 0, 0, "ldstuba", 0, "swapa"}; - -static char *ldst_f_name[] = -{ "ldf", "ldfsr", 0, "lddf", "stf", "stfsr", "stdfq", "stdf"}; - -static char *ldst_c_name[] = -{ "ldc", "ldcsr", 0, "lddc", "stc", "stcsr", "stdcq", "stdc"}; - -static int this_sethi_target = -1; -static int last_sethi_target = -1; -static int sethi_value = 0; - -static void fprint_addr1 (); -static void fprint_ldst (); -static void fprint_f_ldst (); -static void fprint_c_ldst (); -static void fprint_fpop (); - -int -print_insn (memaddr, stream) - CORE_ADDR memaddr; - FILE *stream; -{ - union insn_fmt insn; - int disp22; - - read_memory (memaddr, &insn, MAXLEN); - - this_sethi_target = -1; - switch (insn.op1.op1) - { - case 1: - /* CALL format. */ - fprintf (stream, "call "); - print_address (memaddr + (insn.call.disp << 2), stream); - break; - case 0: - /* Bicc, FBfcc, CBccc, SETHI format. */ - switch (insn.op2.op2) - { - case 0: - fprintf (stream, "unimp"); - break; - case 2: - /* Bicc. */ - fprintf (stream, "b%s", icc_name[insn.branch.cond]); - if (insn.branch.a) fprintf (stream, ",a "); - else fprintf (stream, " "); - disp22 = insn.branch.disp; - disp22 = ((disp22 << 10) >> 10); - print_address (memaddr + (disp22 << 2), stream); - break; - case 4: - /* SETHI. */ - fprintf (stream, "sethi %%hi(0x%x),%s", - insn.sethi.imm << 10, reg_names[insn.sethi.rd]); - this_sethi_target = insn.sethi.rd; - sethi_value = insn.sethi.imm << 12; - break; - case 6: - /* FBdfcc. */ - fprintf (stream, "fb%s", fcc_name[insn.branch.cond]); - if (insn.branch.a) fprintf (stream, ",a "); - else fprintf (stream, " "); - disp22 = insn.branch.disp; - disp22 = ((disp22 << 10) >> 10); - print_address (memaddr + (disp22 << 2), stream); - break; - case 7: - /* CBccc. */ - fprintf (stream, "cb%s", ccc_name[insn.branch.cond]); - if (insn.branch.a) fprintf (stream, ",a "); - else fprintf (stream, " "); - disp22 = insn.branch.disp; - disp22 = ((disp22 << 10) >> 10); - print_address (memaddr + (disp22 << 2), stream); - break; - default: - fprintf (stream, "0x%x (illegal op2 format)", insn.intval); - break; - } - break; - case 2: - { - /* vaguely arithmetic insns. */ - char *rd = reg_names[insn.arith.rd]; - char *rs1 = reg_names[insn.arith.rs1]; - - if (insn.op3.op3 <= 28) - { - /* Arithmetic insns, with a few unimplemented. */ - register int affect_cc = insn.op3.op3 & 16; - char *name = arith_name[insn.op3.op3 ^ affect_cc]; - char *tmp = affect_cc ? "cc" : ""; - - if (name == 0) - { - fprintf (stream, "0x%08x (unimplemented arithmetic insn)", - insn.intval); - } - else if (insn.arith.i) - { - fprintf (stream, "%s%s %s,0x%x,%s", - name, tmp, rs1, insn.arith_imm.simm, rd); - if (last_sethi_target == insn.arith.rd) - { - fprintf (stream, "\t! "); - print_address (sethi_value + insn.arith_imm.simm); - } - } - else - { - fprintf (stream, "%s%s %s,%s,%s", - name, tmp, rs1, reg_names[insn.arith.rs2], rd); - } - break; - } - if (insn.op3.op3 < 32) - { - fprintf (stream, "0x%08x (unimplemented arithmetic insn)", - insn.intval); - break; - } - else - { - int op = insn.op3.op3 ^ 32; - - if (op < 8) - { - char *name = xarith_name[op]; - /* tagged add/sub insns and shift insns. */ - if (insn.arith.i) - { - int i = insn.arith_imm.simm; - if (op > 4) - /* Its a shift insn. */ - i &= 31; - - fprintf (stream, "%s %s,0x%x,%s", - name, rs1, i, rd); - } - else - { - fprintf (stream, "%s %s,%s,%s", - name, rs1, reg_names[insn.arith.rs2], rd); - } - break; - } - if (op < 20) - { - /* read/write state registers. */ - char *sr = state_reg_name[op & 7]; - if (sr == 0) - fprintf (stream, "0x%08x (unimplemented state register insn", - insn.intval); - else - fprintf (stream, "%s %s,%s", op & 16 ? "wr" : "rd", sr, rd); - break; - } - if (op < 22) - { - /* floating point insns. */ - int opcode = insn.arith.opf; - - fprint_fpop (stream, insn, op & 3, opcode); - break; - } - if (op < 24) - { - /* coprocessor insns. */ - char *rs2 = reg_names[insn.arith.rs2]; - int opcode = insn.arith.opf; - - fprintf (stream, "cpop%d rs1=%s,rs2=%s,op=0x%x,rd=%s", - op & 1, rs1, rs2, opcode, rd); - break; - } - - switch (op) - { - char *rndop_ptr; - - case 24: - fprint_addr1 (stream, "jumpl", insn); - break; - case 25: - fprint_addr1 (stream, "rett", insn); - break; - case 26: - { - char rndop_buf[32]; - sprintf (rndop_buf, "t%s", icc_name[insn.branch.cond]); - fprint_addr1 (stream, rndop_buf, insn); - } - break; - case 27: - fprint_addr1 (stream, "iflush", insn); - break; - - case 28: - rndop_ptr = "save"; - case 29: - if (op == 29) - rndop_ptr = "restore"; - - if (insn.arith.i) - { - fprintf (stream, "%s %s,0x%x,%s", - rndop_ptr, rs1, - ((insn.arith_imm.simm << 19) >> 19), rd); - } - else - { - fprintf (stream, "%s %s,%s,%s", - rndop_ptr, rs1, reg_names[insn.arith.rs2], rd); - } - break; - case 30: - case 31: - fprintf (stream, "0x%08x (unimplemented op3 insn)", - insn.intval); - break; - } - break; - } - } - case 3: - /* load and store insns. */ - { - char *rd = reg_names[insn.arith.rd]; - char *rs1 = reg_names[insn.arith.rs1]; - int op = insn.arith.op3; - - if ((op & 32) == 0) - { - /* Integer ops. */ - fprint_ldst (stream, insn, op); - break; - } - if ((op & 16) == 0) - { - /* Float ops. */ - op ^= 32; - if (op <= 7) - { - fprint_f_ldst (stream, insn, op); - } - else - fprintf (stream, "0x%08x (unimplemented float load/store insn)", - insn.intval); - } - else - { - /* Coprocessor ops. */ - op ^= (32+16); - if (op <= 7) - { - fprint_c_ldst (stream, insn, op); - } - else - fprintf (stream, "0x%08x (unimplemented coprocessor load/store insn)", - insn.intval); - } - break; - } - } - return 4; -} - -/* It would be nice if this routine could print out a symbolic address - when appropriate. */ -static void -fprint_addr1 (stream, name, insn) - FILE *stream; - char *name; - union insn_fmt insn; -{ - char *rs1 = reg_names[insn.arith.rs1]; - char *rd = reg_names[insn.arith.rd]; - - if (insn.arith.i) - { - fprintf (stream, "%s %s,0x%x,%s", - name, rs1, insn.arith_imm.simm, rd); - } - else - { - fprintf (stream, "%s %s,%s,%s", - name, rs1, reg_names[insn.arith.rs2], rd); - } -} - -static void -fprint_mem (stream, insn) - FILE *stream; - union insn_fmt insn; -{ - char *reg_name = reg_names[insn.arith.rs1]; - if (insn.arith.i) - { - if (insn.arith_imm.simm == 0) - fprintf (stream, "[%s]", reg_name); - else if (insn.arith_imm.simm & 0x1000) - fprintf (stream, "[%s-0x%x]", reg_name, - - (insn.arith_imm.simm | 0xffffe000)); - else - fprintf (stream, "[%s+0x%x]", reg_name, insn.arith_imm.simm); - } - else - { - if (insn.arith.rs2 == 0) - fprintf (stream, "[%s]", reg_name); - else - fprintf (stream, "[%s,%s]", reg_names[insn.arith.rs2], reg_name); - } -} - -static void -fprint_ldst (stream, insn, op) - FILE *stream; - union insn_fmt insn; - int op; -{ - char *name = ldst_i_name[op]; - char *rd = reg_names[insn.arith.rd]; - - if (name) - { - if (name[0] == 's') - { - fprintf (stream, "%s %s,", name, rd); - fprint_mem (stream, insn); - } - else - { - fprintf (stream, "%s ", name); - fprint_mem (stream, insn); - fprintf (stream, ",%s", rd); - } - } - else - fprintf (stream, "0x%08x (unimplemented load/store insn)", insn.intval); -} - -static void -fprint_f_ldst (stream, insn, op) - FILE *stream; - union insn_fmt insn; - int op; -{ - char *name = ldst_f_name[op]; - if (name) - { - char *rd = reg_names[insn.arith.rd + 32]; - - if (name[0] == 's') - { - fprintf (stream, "%s %s,", name, rd); - fprint_mem (stream, insn); - } - else - { - fprintf (stream, "%s ", name); - fprint_mem (stream, insn); - fprintf (stream, ",%s", rd); - } - } - else - fprintf (stream, "0x%08x (unimplemented float load/store insn)", insn.intval); -} - -static void -fprint_c_ldst (stream, insn, op) - FILE *stream; - union insn_fmt insn; - int op; -{ - char *name = ldst_c_name[op]; - if (name) - { - if (name[0] == 's') - { - fprintf (stream, "%s %%cpreg(%d),", name, insn.arith.rs1); - fprint_mem (stream, insn); - } - else - { - fprintf (stream, "%s "); - fprint_mem (stream, insn); - fprintf (stream, ",%%cpreg(%d)", insn.arith.rd); - } - } - else - fprintf (stream, "0x%08x (unimplemented coprocessor load/store insn)", - insn.intval); -} - -static void -fprint_fpop (stream, insn, op, opcode) - FILE *stream; - union insn_fmt insn; - int op, opcode; -{ - char *name; - char *rs1, *rs2, *rd; - - switch (op) - { - case 0: - rs2 = reg_names[insn.arith.rs2 + 32]; - rd = reg_names[insn.arith.rd + 32]; - if ((opcode ^ 0x2f) <= 0x2f) - { - switch (opcode) - { - case 0x1: - name = "fmovs"; - break; - case 0x5: - name = "fnegs"; - break; - case 0x9: - name = "fabss"; - break; - case 0x29: - name = "fsqrts"; - break; - case 0x2a: - name = "fsqrtd"; - break; - case 0x2b: - name = "fsqrtx"; - break; - } - fprintf (stream, "%s %s,%s", name, rs2, rd); - return; - } - if ((opcode ^ 0x5f) <= 0x5f) - { - rs1 = reg_names[insn.arith.rs1 + 32]; - switch (opcode) - { - case 0x41: - name = "fadds"; - break; - case 0x42: - name = "faddd"; - break; - case 0x43: - name = "faddx"; - break; - case 0x45: - name = "fsubs"; - break; - case 0x46: - name = "fsubd"; - break; - case 0x47: - name = "fsubx"; - break; - case 0x49: - name = "fmuls"; - break; - case 0x4a: - name = "fmuld"; - break; - case 0x4b: - name = "fmulx"; - break; - case 0x4d: - name = "fdivs"; - break; - case 0x4e: - name = "fdivd"; - break; - case 0x4f: - name = "fdivx"; - break; - default: - goto unimplemented; - } - if ((opcode & 0x10) == 0) - fprintf (stream, "%s %s,%s,%s", name, rs1, rs2, rd); - else - fprintf (stream, "%s %s,%s", name, rs1, rs2); - return; - } - if ((opcode ^ 0xdf) <= 0xdf) - { - switch (opcode) - { - case 0xc4: - name = "fitos"; - break; - case 0xc8: - name = "fitod"; - break; - case 0xcc: - name = "fitox"; - break; - case 0xd1: - name = "fstoi"; - break; - case 0xd2: - name = "fdtoi"; - break; - case 0xd3: - name = "fxtoi"; - break; - case 0xc9: - name = "fstod"; - break; - case 0xcd: - name = "fstox"; - break; - case 0xc6: - name = "fdtos"; - break; - case 0xce: - name = "fdtox"; - break; - case 0xc7: - name = "fxtos"; - break; - case 0xcb: - name = "fxtod"; - break; - default: - goto unimplemented; - } - fprintf (stream, "%s %s,%s", name, rs2, rd); - return; - } - goto unimplemented; - - case 1: - rs1 = reg_names[insn.arith.rs1 + 32]; - rs2 = reg_names[insn.arith.rs2 + 32]; - if ((opcode ^ 0x57) <= 0x57) - { - switch (opcode) - { - case 0x51: - name = "fcmps"; - break; - case 0x52: - name = "fcmpd"; - break; - case 0x53: - name = "fcmpx"; - break; - case 0x55: - name = "fcmpes"; - break; - case 0x56: - name = "fcmped"; - break; - case 0x57: - name = "fcmpex"; - break; - default: - goto unimplemented; - } - fprintf (stream, "%s %s,%s", name, rs1, rs2); - return; - } - else goto unimplemented; - - case 2: - case 3: - goto unimplemented; - } - unimplemented: - fprintf (stream, "0x%08x (unimplemented fpop insn)", insn.intval); -} - -/* Set *target if we find a branch */ -branch_type -isabranch (addr, target) - CORE_ADDR addr, *target; -{ - union insn_fmt instr; - branch_type val = not_branch; - long offset; /* Must be signed for sign-extend */ - - *target = 0; - instr.intval = read_memory_integer (addr, 4); - /* printf("intval = %x\n",instr.intval); */ - switch (instr.op1.op1) - { - case 0: /* Format 2 */ - switch(instr.op2.op2) - { - case 2: case 6: /* BICC & FBCC */ - if (instr.branch.cond == 8) - val = instr.branch.a ? baa : ba; - else - val = instr.branch.a ? bicca : bicc; - /* 22 bits, sign extended */ - offset = ((instr.branch.disp << 10) >> 10); - *target = addr + offset; - break; - } - break; - } - /*printf("isabranch ret: %d\n",val); */ - return val; -} - -CORE_ADDR skip_prologue (pc) - CORE_ADDR pc; -{ - union - { - struct insn_fmt insn; - int i; - } x; - int dest = -1; - - x.i = read_memory_integer (pc, 4); - if (x.insn.sethi.op == 0 && x.insn.sethi.op2 == 4) - { - dest = x.insn.sethi.rd; - pc += 4; - x.i = read_memory_integer (pc, 4); - } - if (x.insn.arith_imm.op == 2 && x.insn.arith_imm.i == 1 - && (x.insn.arith_imm.rd == 1 || x.insn.arith_imm.rd == dest)) - { - pc += 4; - x.i = read_memory_integer (pc, 4); - } - if (x.insn.arith.op == 2 && (x.insn.arith.op3 ^ 32) == 28) - { - pc += 4; - } - return pc; -} - -CORE_ADDR -frame_saved_pc (frame, next_frame) - CORE_ADDR frame; - CORE_ADDR next_frame; -{ - CORE_ADDR prev_pc; - - if (next_frame) - prev_pc = GET_RWINDOW_REG (next_frame, rw_in[7]); - else if (frame) - prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]); - else - error ("frame_saved_pc called without a frame"); - - return PC_ADJUST (prev_pc); -} diff --git a/gdb/pinsn.c b/gdb/pinsn.c new file mode 120000 index 0000000..b7ac88a --- /dev/null +++ b/gdb/pinsn.c @@ -0,0 +1 @@ +sparc-pinsn.c \ No newline at end of file diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 56278ee..67b93a8 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -20,8 +20,8 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include #include "defs.h" -#include "initialize.h" #include "param.h" +#include "frame.h" #include "symtab.h" #include "value.h" #include "expression.h" @@ -66,7 +66,6 @@ void do_displays (); void print_address (); void print_scalar_formatted (); -START_FILE /* Decode a format specification. *STRING_PTR should point to it. OFORMAT and OSIZE are used as defaults for the format and size @@ -98,15 +97,25 @@ decode_format (string_ptr, oformat, osize) { if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g') val.size = *p++; +#ifdef LONG_LONG + else if (*p == 'l') + { + val.size = 'g'; + p++; + } +#endif else if (*p >= 'a' && *p <= 'z') val.format = *p++; else break; } - /* Make sure 'g' size is not used on integer types. */ - if (val.size == 'g' && val.format != 'f') +#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; @@ -126,7 +135,6 @@ print_formatted (val, format, size) register char format; char size; { - register CORE_ADDR val_long; int len = TYPE_LENGTH (VALUE_TYPE (val)); if (VALUE_LVAL (val) == lval_memory) @@ -148,7 +156,8 @@ print_formatted (val, format, size) 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) + || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_UNION + || VALUE_REPEATED (val)) value_print (val, stdout, format); else print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val), @@ -171,9 +180,39 @@ print_scalar_formatted (valaddr, type, format, size, stream) int size; FILE *stream; { - long val_long; + 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 (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. */ @@ -183,48 +222,85 @@ print_scalar_formatted (valaddr, type, format, size, stream) 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 (stream, "0x%02llx", val_long); + break; + case 'h': + fprintf (stream, "0x%04llx", val_long); + break; + case 0: /* no size specified, like in print */ + case 'w': + fprintf (stream, "0x%08llx", val_long); + break; + case 'g': + fprintf (stream, "0x%16llx", val_long); + break; + default: + error ("Undefined output size \"%c\".", size); + } +#else switch (size) { case 'b': - printf ("0x%02x", val_long); + fprintf (stream, "0x%02x", val_long); break; case 'h': - printf ("0x%04x", val_long); + fprintf (stream, "0x%04x", val_long); break; case 0: /* no size specified, like in print */ case 'w': - printf ("0x%08x", val_long); + fprintf (stream, "0x%08x", val_long); break; case 'g': - printf ("0x%16x", val_long); + fprintf (stream, "0x%16x", val_long); break; default: error ("Undefined output size \"%c\".", size); } +#endif /* not LONG_LONG */ break; case 'd': - printf ("%d", val_long); +#ifdef LONG_LONG + fprintf (stream, "%lld", val_long); +#else + fprintf (stream, "%d", val_long); +#endif break; case 'u': - printf ("%u", val_long); +#ifdef LONG_LONG + fprintf (stream, "%llu", val_long); +#else + fprintf (stream, "%u", val_long); +#endif break; case 'o': if (val_long) - printf ("0%o", val_long); +#ifdef LONG_LONG + fprintf (stream, "0%llo", val_long); +#else + fprintf (stream, "0%o", val_long); +#endif else - printf ("0"); + fprintf (stream, "0"); break; case 'a': - print_address (val_long, stream); + print_address ((CORE_ADDR) val_long, stream); break; case 'c': @@ -234,16 +310,27 @@ print_scalar_formatted (valaddr, type, format, size, stream) case 'f': if (len == sizeof (float)) type = builtin_type_float; - if (len == sizeof (double)) + else if (len == sizeof (double)) type = builtin_type_double; + else abort(); + #ifdef IEEE_FLOAT - if (is_nan (unpack_double (type, valaddr))) + if (is_nan (valaddr, len)) { - printf ("Nan"); + fprintf (stream, "NaN"); break; } #endif - printf ("%g", unpack_double (type, valaddr)); + { + double doub; + int inv; + + doub = unpack_double (type, valaddr, &inv); + if (inv) + fprintf (stream, "Invalid float value"); + else + fprintf (stream, len > 4? "%.16g": "%.6g", doub); + } break; case 0: @@ -265,7 +352,7 @@ set_next_address (addr) /* Make address available to the user as $_. */ set_internalvar (lookup_internalvar ("_"), - value_from_long (builtin_type_int, addr)); + value_from_long (builtin_type_int, (LONGEST) addr)); } /* Print address ADDR symbolically on STREAM. @@ -278,18 +365,36 @@ print_address (addr, stream) FILE *stream; { register int i; + struct symbol *fs; + char *name; + int name_location; fprintf (stream, "0x%x", addr); - i = find_pc_misc_function (addr); - if (i >= 0) - if (misc_function_vector[i].address != addr) - fprintf (stream, " <%s+%d>", - misc_function_vector[i].name, - addr - misc_function_vector[i].address); - else - fprintf (stream, " <%s>", misc_function_vector[i].name); + fs = find_pc_function (addr); + + if (!fs) + { + i = find_pc_misc_function (addr); + + if (i < 0) return; /* If nothing comes through, don't + print anything symbolic */ + name = misc_function_vector[i].name; + name_location = misc_function_vector[i].address; + } + else + { + name = fs->name; + name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (fs)); + } + + if (addr - name_location) + fprintf (stream, " <%s+%d>", + name, + addr - name_location); + else + fprintf (stream, " <%s>", name); } /* Examine data at address ADDR in format FMT. @@ -324,7 +429,11 @@ do_examine (fmt, addr) 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') @@ -346,7 +455,8 @@ do_examine (fmt, addr) i--, count--) { fputc ('\t', stdout); - /* Note that this sets next_address for the next object. */ + /* 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); @@ -402,7 +512,7 @@ print_command (exp) val = access_value_history (0); histindex = record_latest_value (val); - printf ("$%d = ", histindex); + if (histindex >= 0) printf ("$%d = ", histindex); print_formatted (val, format, fmt.size); printf ("\n"); @@ -456,15 +566,24 @@ address_info (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); + 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; @@ -502,7 +621,7 @@ address_info (exp) case LOC_REGPARM: printf ("an argument in register %s", reg_names[val]); break; - + case LOC_ARG: printf ("an argument at offset %d", val); break; @@ -555,18 +674,23 @@ x_command (exp, from_tty) if (from_tty) *exp = 0; old_chain = make_cleanup (free_current_contents, &expr); - next_address = value_as_long (evaluate_expression (expr)); + next_address = (CORE_ADDR) value_as_long (evaluate_expression (expr)); do_cleanups (old_chain); } do_examine (fmt, next_address); - /* Make last address examined available to the user as $_. */ - set_internalvar (lookup_internalvar ("_"), - value_from_long (builtin_type_int, last_examine_address)); - - /* Make contents of last address examined available to the user as $__. */ - set_internalvar (lookup_internalvar ("__"), last_examine_value); + /* 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. */ @@ -626,7 +750,7 @@ ptype_command (typename) if (type == 0) { register struct symbol *sym - = lookup_symbol (typename, b, STRUCT_NAMESPACE); + = lookup_symbol (typename, b, STRUCT_NAMESPACE, 0); if (sym == 0) error ("No type named %s.", typename); printf ("No type named %s, but there is a ", @@ -653,6 +777,8 @@ ptype_command (typename) printf ("\n"); } +enum display_status {disabled, enabled}; + struct display { /* Chain link to next auto-display item. */ @@ -663,8 +789,10 @@ struct display int number; /* Display format specified. */ struct format_data format; - /* Block in which expression is to be evaluated. */ + /* 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 @@ -685,6 +813,7 @@ display_command (exp, from_tty) struct format_data fmt; register struct expression *expr; register struct display *new; + extern struct block *innermost_block; if (exp == 0) { @@ -708,17 +837,20 @@ display_command (exp, from_tty) 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) + if (from_tty && have_inferior_p ()) do_one_display (new); dont_repeat (); @@ -818,12 +950,26 @@ undisplay_command (args) dont_repeat (); } -/* Display a single auto-display. */ +/* 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 ("%d: ", d->number); @@ -842,7 +988,8 @@ do_one_display (d) else printf (" "); do_examine (d->format, - value_as_long (evaluate_expression (d->exp))); + (CORE_ADDR) value_as_long (evaluate_expression (d->exp))); + } else { @@ -859,7 +1006,8 @@ do_one_display (d) current_display_number = -1; } -/* Display all of the values on the auto-display chain. */ +/* Display all of the values on the auto-display chain which can be + evaluated in the current scope. */ void do_displays () @@ -893,20 +1041,103 @@ display_info () if (!display_chain) printf ("There are no auto-display expressions now.\n"); else - printf ("Auto-display expressions now in effect:\n"); + printf ("Auto-display expressions now in effect:\n\ +Num Enb Expression\n"); + for (d = display_chain; d; d = d->next) { - printf ("%d: ", d->number); + printf ("%d: %c ", d->number, "ny"[(int)d->status]); if (d->format.size) printf ("/%d%c%c ", d->format.count, d->format.size, d->format.format); else if (d->format.format) printf ("/%c ", d->format.format); print_expression (d->exp, stdout); + if (d->block && !contained_in (get_selected_block (), d->block)) + printf (" (cannot be evaluated in the current context)"); printf ("\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->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 (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->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); + + for (d = display_chain; d; d = d->next) + if (d->number == num) + { + d->status = disabled; + goto win; + } + printf ("No display number %d.\n", num); + win: + p = p1; + while (*p == ' ' || *p == '\t') + p++; + } +} + /* Print the value in stack frame FRAME of a variable specified by a struct symbol. */ @@ -922,14 +1153,15 @@ print_variable_value (var, frame, stream) } /* Print the arguments of a stack frame, given the function FUNC - running in that frame (as a symbol), the address of the arglist, + 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 (); -print_frame_args (func, addr, num, stream) +void +print_frame_args (func, fi, num, stream) struct symbol *func; - register CORE_ADDR addr; + struct frame_info *fi; int num; FILE *stream; { @@ -939,8 +1171,9 @@ print_frame_args (func, addr, num, stream) register int i; register int last_offset = FRAME_ARGS_SKIP; register int last_regparm = 0; - register struct symbol *sym, *nextsym; + register struct symbol *lastsym, *sym, *nextsym; register value val; + register CORE_ADDR addr = FRAME_ARGS_ADDRESS (fi); if (func) { @@ -948,6 +1181,7 @@ print_frame_args (func, addr, num, stream) nsyms = BLOCK_NSYMS (b); } + lastsym = 0; while (1) { /* Find first arg that is not before LAST_OFFSET. */ @@ -965,9 +1199,10 @@ print_frame_args (func, addr, num, stream) } else if (SYMBOL_CLASS (sym) == LOC_REGPARM) { - if (SYMBOL_VALUE (sym) >= last_regparm - && (nextsym == 0 - || SYMBOL_VALUE (sym) < SYMBOL_VALUE (nextsym))) + /* This shouldn't be sorted by number. Since we can't + find nameless args with register parameters, print + this out in order by .stabs. */ + if (sym > lastsym && nextsym == 0) nextsym = sym; } } @@ -985,29 +1220,9 @@ print_frame_args (func, addr, num, stream) } /* Print the next arg. */ if (SYMBOL_CLASS (sym) == LOC_REGPARM) - { - unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE]; - unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; - - read_relative_register_raw_bytes (SYMBOL_VALUE (sym), raw_buffer); - if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FLT) - val = value_from_double (SYMBOL_TYPE (sym), *(double *)raw_buffer); - else if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT - || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM) - val = value_from_long (SYMBOL_TYPE (sym), *(int *)raw_buffer); - else if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR) - { - if (sizeof (char *) == sizeof (int)) - val = value_from_long (builtin_type_int, *(int *)raw_buffer); - else if (sizeof (char *) == sizeof (long)) - val = value_from_long (builtin_type_long, *(long *)raw_buffer); - else - error ("pointer size not sizeof (int) or sizeof (long)"); - VALUE_TYPE (val) = SYMBOL_TYPE (sym); - } - else - error ("can't extract non-scalar from register"); - } + val = value_from_register (SYMBOL_TYPE (sym), + SYMBOL_VALUE (sym), + FRAME_INFO_ID (fi)); else val = value_at (SYMBOL_TYPE (sym), addr + SYMBOL_VALUE (sym)); @@ -1023,9 +1238,11 @@ print_frame_args (func, addr, num, stream) last_regparm = SYMBOL_VALUE (sym) + 1; last_offset += TYPE_LENGTH (SYMBOL_TYPE (sym)); } + /* Round up address of next arg to multiple of size of int. */ last_offset = ((last_offset + sizeof (int) - 1) / sizeof (int)) * sizeof (int); + lastsym = sym; } if (num >= 0 && num * sizeof (int) + FRAME_ARGS_SKIP > last_offset) print_frame_nameless_args (addr, last_offset, @@ -1132,7 +1349,8 @@ printf_command (arg) while (*s == ' ' || *s == '\t') s++; /* Now scan the string for %-specs and see what kinds of args they want. - argclass[I] is set to 1 if the Ith arg should be a string. */ + argclass[I] is set to 1 if the Ith arg should be a string. + It's set to 2 if the Ith arg should be floating point. */ argclass = (char *) alloca (strlen (s)); nargs_wanted = 0; @@ -1143,6 +1361,8 @@ printf_command (arg) while (index ("0123456789.hlL-+ #", *f)) f++; if (*f == 's') argclass[nargs_wanted++] = 1; + else if (*f == 'e' || *f == 'f' || *f == 'g') + argclass[nargs_wanted++] = 2; else if (*f != '%') argclass[nargs_wanted++] = 0; f++; @@ -1159,7 +1379,20 @@ printf_command (arg) (allocated_args *= 2) * sizeof (value)); s1 = s; - val_args[nargs++] = parse_to_comma_and_eval (&s1); + 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] == 2) + { + argclass[nargs] = 0; + 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++; @@ -1206,6 +1439,14 @@ printf_command (arg) argindex += sizeof (double); } else +#ifdef LONG_LONG + if (TYPE_LENGTH (VALUE_TYPE (val_args[i])) == sizeof (long long)) + { + *(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); @@ -1215,8 +1456,11 @@ printf_command (arg) vprintf (string, arg_bytes); } -static -initialize () +extern struct cmd_list_element *enablelist, *disablelist, *deletelist; +extern struct cmd_list_element *cmdlist, *setlist; + +void +_initialize_printcmd () { current_display_number = -1; @@ -1248,11 +1492,15 @@ The selected stack frame's lexical context is used to look up the name."); add_info ("display", display_info, "Expressions to display when program stops, with code numbers."); - add_com ("undisplay", class_vars, undisplay_command, - "Cancel some expressions to be displayed whenever program stops.\n\ + + add_abbrev_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\ -Do \"info display\" to see current list of code numbers."); +\"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\ @@ -1262,6 +1510,24 @@ 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, + "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."); @@ -1269,11 +1535,22 @@ This is useful for formatted output in user-defined commands."); "Like \"print\" but don't put in value history and don't print newline.\n\ This is useful in user-defined commands."); - add_com ("set", class_vars, set_command, - "Perform an assignment VAR = EXP. You must type the \"=\".\n\ -VAR may be a debugger \"convenience\" variables (names starting with $),\n\ -a register (a few standard names starting with $), or an actual variable\n\ -in the program being debugger. EXP is any expression."); + 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\ @@ -1300,4 +1577,3 @@ but no count or size letter (see \"x\" command).")); add_com_alias ("p", "print", class_vars, 1); } -END_FILE diff --git a/gdb/regex.c b/gdb/regex.c new file mode 100644 index 0000000..4011805 --- /dev/null +++ b/gdb/regex.c @@ -0,0 +1,1818 @@ +/* Extended regular expression matching and search. + Copyright (C) 1985 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS 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. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1985 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file 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 or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution 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 unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute this 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 + shipping charge) 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.) + +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. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We 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. + + +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 +#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 + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef sparc +#include +#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, \ turns into a `duplicate' command which + is followed by the numeric value of 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 + +/* 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/gdb/regex.h b/gdb/regex.h new file mode 100644 index 0000000..c9f082d --- /dev/null +++ b/gdb/regex.h @@ -0,0 +1,267 @@ +/* Definitions for data structures callers pass the regex library. + Copyright (C) 1985 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS 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. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1985 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file 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 or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution 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 unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute this 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 + shipping charge) 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.) + +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. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We 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. + + +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/gdb/remote.c b/gdb/remote.c index 27a7322..6abd8e2 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -62,18 +62,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! kill req k */ -#include -#include - #include "defs.h" -#include "initialize.h" #include "param.h" #include "frame.h" #include "inferior.h" #include "wait.h" + +#ifdef USG +#include +#include +#endif + +#include +#include #include -#include #include #ifdef HAVE_TERMIO @@ -97,14 +100,13 @@ int icache; /* Descriptor for I/O to remote machine. */ int remote_desc; -#define PBUFSIZ 300 +#define PBUFSIZ 400 static void remote_send (); static void putpkt (); static void getpkt (); static void dcache_flush (); -START_FILE /* Open a connection to a remote debugger. NAME is the filename used for communication. */ @@ -239,8 +241,8 @@ remote_store_registers (regs) p = buf + 1; for (i = 0; i < REGISTER_BYTES; i++) { - *p++ = (regs[i] > 4) & 0xf; - *p++ = regs[i] & 0xf; + *p++ = tohex ((regs[i] >> 4) & 0xf); + *p++ = tohex (regs[i] & 0xf); } remote_send (buf); @@ -305,8 +307,8 @@ remote_write_bytes (memaddr, myaddr, len) p = buf + strlen (buf); for (i = 0; i < len; i++) { - *p++ = (myaddr[i] > 4) & 0xf; - *p++ = myaddr[i] & 0xf; + *p++ = tohex ((myaddr[i] >> 4) & 0xf); + *p++ = tohex (myaddr[i] & 0xf); } remote_send (buf); @@ -338,7 +340,7 @@ remote_read_bytes (memaddr, myaddr, len) each byte encoded as two hex characters. */ p = buf; - for (i = 0; i < REGISTER_BYTES; i++) + for (i = 0; i < len; i++) { if (p[0] == 0 || p[1] == 0) error ("Remote reply is too short: %s", buf); @@ -440,12 +442,15 @@ getpkt (buf) char *buf; { char *bp; - char csum = 0; - int c, c1, c2; + unsigned char csum; + unsigned int c, c1, c2; extern kiodebug; while (1) { + /* Force csum to be zero here because of possible error retry. */ + csum = 0; + while ((c = readchar()) != '$'); bp = buf; @@ -616,8 +621,3 @@ dcache_init () insque (db, &dcache_free); } -static initialize () -{ -} - -END_FILE diff --git a/gdb/source.c b/gdb/source.c index 6126d5b..27e2139 100644 --- a/gdb/source.c +++ b/gdb/source.c @@ -18,13 +18,19 @@ 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! */ +#include "defs.h" +#include "symtab.h" +#include "param.h" + +#ifdef USG +#include +#include +#endif + #include #include #include #include -#include "defs.h" -#include "initialize.h" -#include "symtab.h" /* Path of directories to search for source files. Same format as the PATH environment variable's value. */ @@ -48,8 +54,9 @@ static int last_line_listed; static int first_line_listed; -START_FILE +struct symtab *psymtab_to_symtab (); + /* Set the source file default for the "list" command, specifying a symtab. */ @@ -57,26 +64,27 @@ 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; + + /* 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 = sal.line - 9; + return; + } + + /* If there is no `main', use the last symtab in the list, + which is actually the first found in the file's symbol table. + But ignore .h files. */ if (s) { - struct symtabs_and_lines sals; - struct symtab_and_line sal; - - /* Make the default place to list be the function `main' - if one exists. */ - if (lookup_symbol ("main", 0, VAR_NAMESPACE)) - { - sals = decode_line_spec ("main", 1); - sal = sals.sals[0]; - free (sals.sals); - current_source_symtab = sal.symtab; - current_source_line = sal.line - 9; - return; - } - - /* If there is no `main', use the last symtab in the list, - which is actually the first found in the file's symbol table. - But ignore .h files. */ do { char *name = s->filename; @@ -88,6 +96,23 @@ select_source_symtab (s) while (s); current_source_line = 1; } + else + { + 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) + current_source_symtab = psymtab_to_symtab (cs_pst); + else + current_source_symtab = 0; + current_source_line = 1; + } } static void @@ -488,6 +513,27 @@ print_source_lines (s, line, stopline, noerror) fclose (stream); } + + +/* + C++ + Print a list of files and line numbers which a user may choose from + in order to list a function which was specified ambiguously + (as with `list classname::overloadedfuncname', for example). + The vector in SALS provides the filenames and line numbers. + */ +static void +ambiguous_line_spec (sals) + struct symtabs_and_lines *sals; +{ + int i; + + for (i = 0; i < sals->nelts; ++i) + printf("file: \"%s\", line number: %d\n", + sals->sals[i].symtab->filename, sals->sals[i].line); +} + + static void list_command (arg, from_tty) char *arg; @@ -503,9 +549,14 @@ list_command (arg, from_tty) int linenum_beg = 0; char *p; - if (symtab_list == 0) + if (symtab_list == 0 && partial_symtab_list == 0) error ("Listing source lines requires symbols."); + /* Pull in a current source symtab if necessary */ + if (current_source_symtab == 0 && + (arg == 0 || arg[0] == '+' || arg[0] == '-')) + select_source_symtab (symtab_list); + /* "l" or "l +" lists next ten lines. */ if (arg == 0 || !strcmp (arg, "+")) @@ -542,9 +593,11 @@ list_command (arg, from_tty) sals = decode_line_1 (&arg1, 0, 0, 0); if (! sals.nelts) return; /* C++ */ - if (sals.nelts != 1) + if (sals.nelts > 1) { - error ("Unreasonable listing request"); + ambiguous_line_spec (&sals); + free (sals.sals); + return; } sal = sals.sals[0]; @@ -572,7 +625,14 @@ list_command (arg, from_tty) 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) return; /* C++ */ + 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); } @@ -628,7 +688,8 @@ list_command (arg, from_tty) 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); + dummy_end ? sal.line + 10 : sal_end.line + 1, + 0); } /* Print info on range of pc's in a specified line. */ @@ -641,49 +702,54 @@ line_info (arg, 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 (arg); - - if (sals.nelts == 0) - return; /* C++ */ - if (sals.nelts != 1) - error ("unreasonable line info request"); + sals = decode_line_spec_1 (arg, 0); - sal = sals.sals[0]; - free (sals.sals); /* If this command is repeated with RET, turn it into the no-arg variant. */ - if (from_tty) *arg = 0; } - 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)) + /* 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++) { - 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); + 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 %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; + printf ("Line number %d is out of range for \"%s\".\n", + sal.line, sal.symtab->filename); } - 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. */ @@ -835,8 +901,8 @@ reverse_search_command (regex, from_tty) return; } -static -initialize () +void +_initialize_source () { current_source_symtab = 0; init_source_path (); @@ -883,4 +949,3 @@ Lines can be specified in these ways:\n\ With two args if one is empty it stands for ten lines away from the other arg."); } -END_FILE diff --git a/gdb/sparc-dep.c b/gdb/sparc-dep.c new file mode 100644 index 0000000..2d53a04 --- /dev/null +++ b/gdb/sparc-dep.c @@ -0,0 +1,932 @@ +/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + This code is for the sparc cpu. + +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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "obstack.h" +#include "sparc-opcode.h" +#include "gdbcore.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +extern int errno; +extern int attach_flag; + +/* 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); +} + +void +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.*/ + +void +kill_inferior_fast () +{ + if (remote_debugging) + return; + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); +} + +/* Simulate single-step ptrace call for sun4. Code written by Gary + Beihl (beihl@mcc.com). */ + +/* + * Duplicated from breakpoint.c because (at least for now) this is a + * machine dependent routine. + */ +static char break_insn[] = BREAKPOINT; + +/* From infrun.c */ +extern int stop_after_trap, stop_after_attach; + +static CORE_ADDR next_pc, npc4, target; +static int brknpc4, brktrg; +typedef char binsn_quantum[sizeof break_insn]; +static binsn_quantum break_mem[3]; + +/* Non-zero if we just simulated a single-step ptrace call. This is + needed because we cannot remove the breakpoints in the inferior + process until after the `wait' in `wait_for_inferior'. Used for + sun4. */ + +int one_stepped; + +void +single_step (signal) + int signal; +{ + branch_type br, isannulled(); + CORE_ADDR pc; + + next_pc = read_register (NPC_REGNUM); + npc4 = next_pc + 4; /* branch not taken */ + + if (!one_stepped) + { + /* Always set breakpoint for NPC. */ + read_memory (next_pc, break_mem[0], sizeof break_insn); + write_memory (next_pc, break_insn, sizeof break_insn); + /* printf ("set break at %x\n",next_pc); */ + + pc = read_register (PC_REGNUM); + br = isannulled (pc, &target); + brknpc4 = brktrg = 0; + + if (br == bicca) + { + /* Conditional annulled branch will either end up at + npc (if taken) or at npc+4 (if not taken). Trap npc+4. */ + brknpc4 = 1; + read_memory (npc4, break_mem[1], sizeof break_insn); + write_memory (npc4, break_insn, sizeof break_insn); + } + else if (br == baa && target != next_pc) + { + /* Unconditional annulled branch will always end up at + the target. */ + brktrg = 1; + read_memory (target, break_mem[2], sizeof break_insn); + write_memory (target, break_insn, sizeof break_insn); + } + + /* Let it go */ + ptrace (7, inferior_pid, 1, signal); + one_stepped = 1; + return; + } + else + { + /* Remove breakpoints */ + write_memory (next_pc, break_mem[0], sizeof break_insn); + + if (brknpc4) + { + write_memory (npc4, break_mem[1], sizeof break_insn); + } + if (brktrg) + { + write_memory (target, break_mem[2], sizeof break_insn); + } + one_stepped = 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 + { + /* Sparc doesn't have single step on ptrace */ + if (step) + single_step (signal); + else + ptrace (7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + } +} + +#ifdef ATTACH_DETACH + +/* Start debugging the process whose number is PID. */ + +int +attach (pid) + int pid; +{ + errno = 0; + ptrace (PTRACE_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 (PTRACE_DETACH, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + int cwp; + struct rwindow local_and_ins; + + if (remote_debugging) + remote_fetch_registers (registers); + else + { + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); + + registers[REGISTER_BYTE (0)] = 0; + bcopy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (1)], 15 * 4); + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fpu_fr); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y; +/* *(int *)®isters[REGISTER_BYTE (RP_REGNUM)] = + inferior_registers.r_o7 + 8; + bcopy (&inferior_fp_registers.Fpu_fsr, + ®isters[REGISTER_BYTE (FPS_REGNUM)], + sizeof (FPU_FSR_TYPE)); */ + + read_inferior_memory (inferior_registers.r_sp, + ®isters[REGISTER_BYTE (16)], + 16*4); + } +} + +/* 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). */ + +void +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + if (remote_debugging) + remote_store_registers (registers); + else + { + int in_regs = 1, in_fpregs = 1, in_fparegs, in_cpregs = 1; + + if (regno >= 0) + if (FP0_REGNUM <= regno && regno <= FP0_REGNUM + 32) + in_regs = 0; + else + in_fpregs = 0; + + if (in_regs) + { + bcopy (®isters[REGISTER_BYTE (1)], + &inferior_registers.r_g1, 15 * 4); + + inferior_registers.r_ps = + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + inferior_registers.r_npc = + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)]; + inferior_registers.r_y = + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)]; + + write_inferior_memory (*(int *)®isters[REGISTER_BYTE (SP_REGNUM)], + ®isters[REGISTER_BYTE (16)], + 16*4); + } + if (in_fpregs) + { + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], + &inferior_fp_registers, + sizeof inferior_fp_registers.fpu_fr); + + /* bcopy (®isters[REGISTER_BYTE (FPS_REGNUM)], + &inferior_fp_registers.Fpu_fsr, + sizeof (FPU_FSR_TYPE)); + ****/ + } + + if (in_regs) + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + if (in_fpregs) + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); + } +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes 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; +} + + +/* Machine-dependent code which would otherwise be in core.c */ +/* Work with core dump and executable files, for GDB. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#define AOUTHDR struct exec +#endif + +extern char *sys_siglist[]; + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +#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 (); + +void +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) + { + 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); + + { + struct core corestr; + + val = myread (corechan, &corestr, sizeof corestr); + if (val < 0) + perror_with_name (filename); + if (corestr.c_magic != CORE_MAGIC) + error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", + filename, corestr.c_magic, (int) CORE_MAGIC); + else if (sizeof (struct core) != corestr.c_len) + error ("\"%s\" has an invalid struct core length (%d, expected %d)", + filename, corestr.c_len, (int) sizeof (struct core)); + + /* Note that data_start and data_end don't depend on the exec file */ + data_start = N_DATADDR (corestr.c_aouthdr); + data_end = data_start + corestr.c_dsize; + stack_start = stack_end - corestr.c_ssize; + data_offset = sizeof corestr; + stack_offset = sizeof corestr + corestr.c_dsize; + + /* G0 *always* holds 0. */ + *(int *)®isters[REGISTER_BYTE (0)] = 0; + /* The globals and output registers. */ + + bcopy (&corestr.c_regs.r_g1, ((int *) registers) + 1, 15 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = corestr.c_regs.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = corestr.c_regs.r_y; + + /* My best guess at where to get the locals and input + registers is exactly where they usually are, right above + the stack pointer. If the core dump was caused by a bus + writing off the stack pointer (as is possible) then this + won't work, but it's worth the try. */ + { + int sp; + + sp = *(int *)®isters[REGISTER_BYTE (SP_REGNUM)]; + lseek (corechan, sp - stack_start + stack_offset, L_SET); + if (16 * 4 != myread (corechan, + ®isters[REGISTER_BYTE (16)], + 16 * 4)) + /* fprintf so user can still use gdb */ + fprintf (stderr, "Couldn't read input and local registers from core file\n"); + } + + bcopy (corestr.c_fpu.fpu_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof corestr.c_fpu.fpu_regs); +#ifdef FPU + bcopy (&corestr.c_fpu.fpu_fsr, + ®isters[REGISTER_BYTE (FPS_REGNUM)], + sizeof (FPU_FSR_TYPE)); +#endif + + bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); + + printf ("Core file is from \"%s\".\n", corestr.c_cmdname); + if (corestr.c_signo > 0) + printf ("Program terminated with signal %d, %s.\n", + corestr.c_signo, + corestr.c_signo < NSIG + ? sys_siglist[corestr.c_signo] + : "(undocumented)"); + } + 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"); +} + +void +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + 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; + + 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); +} + +/* + * Find the pc saved in frame FRAME. + */ +CORE_ADDR +frame_saved_pc (frame) + FRAME frame; +{ + CORE_ADDR prev_pc; + + /* If it's at the bottom, the return value's stored in i7/rp */ + if (get_current_frame () == frame) + prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]); + else + /* Wouldn't this always work? This would allow this routine to + be completely a macro. */ + prev_pc = GET_RWINDOW_REG (frame->bottom, rw_in[7]); + + return PC_ADJUST (prev_pc); +} + +/* + * Since an individual frame in the frame cache is defined by two + * arguments (a frame pointer and a stack pointer), we need two + * arguments to get info for an arbitrary stack frame. This routine + * takes two arguments and makes the cached frames look as if these + * two arguments defined a frame on the cache. This allows the rest + * of info frame to extract the important arguments without + * difficulty. + */ +FRAME +setup_arbitrary_frame (frame, stack) + FRAME_ADDR frame, stack; +{ + struct frame_info *fci; + FRAME fid = create_new_frame (frame, 0); + + if (!fid) + fatal ("internal: create_new_frame returned invalid frame id"); + + fid->bottom = stack; + + return fid; +} + +/* This code was written by Gary Beihl (beihl@mcc.com). + It was modified by Michael Tiemann (tiemann@corto.inria.fr). */ + +struct command_line *get_breakpoint_commands (); + +/* + * This routine appears to be passed a size by which to increase the + * stack. It then executes a save instruction in the inferior to + * increase the stack by this amount. Only the register window system + * should be affected by this; the program counter & etc. will not be. + * + * This instructions used for this purpose are: + * + * sethi %hi(0x0),g1 * + * add g1,0x1ee0,g1 * + * save sp,g1,sp + * sethi %hi(0x0),g1 * + * add g1,0x1ee0,g1 * + * t g0,0x1,o0 + * sethi %hi(0x0),g0 (nop) + * + * I presume that these set g1 to be the negative of the size, do a + * save (putting the stack pointer at sp - size) and restore the + * original contents of g1. A * indicates that the actual value of + * the instruction is modified below. + */ +static int save_insn_opcodes[] = { + 0x03000000, 0x82007ee0, 0x9de38001, 0x03000000, + 0x82007ee0, 0x91d02001, 0x01000000 }; + +/* Neither do_save_insn or do_restore_insn save stack configuration + (since the stack is in an indeterminate state through the call to + each of them); that responsibility of the routine which calls them. */ + +void +do_save_insn (size) + int size; +{ + int g1 = read_register (1); + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR pc = read_register (PC_REGNUM); + CORE_ADDR npc = read_register (NPC_REGNUM); + CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes); + struct inferior_status inf_status; + + save_inferior_status (&inf_status, 0); /* Don't restore stack info */ + /* + * See above. + */ + save_insn_opcodes[0] = 0x03000000 | ((-size >> 10) & 0x3fffff); + save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff); + save_insn_opcodes[3] = 0x03000000 | ((g1 >> 10) & 0x3fffff); + save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff); + write_memory (fake_pc, save_insn_opcodes, sizeof (save_insn_opcodes)); + + clear_proceed_status (); + stop_after_trap = 1; + proceed (fake_pc, 0, 0); + + write_register (PC_REGNUM, pc); + write_register (NPC_REGNUM, npc); + restore_inferior_status (&inf_status); +} + +/* + * This routine takes a program counter value. It restores the + * register window system to the frame above the current one, and sets + * the pc and npc to the correct values. + */ + +/* The following insns translate to: + + restore + t g0,0x1,o0 + sethi %hi(0x0), g0 */ + +static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 }; + +void +do_restore_insn (pc) + CORE_ADDR pc; +{ + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR npc = pc + 4; + CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes); + struct inferior_status inf_status; + + save_inferior_status (&inf_status, 0); /* Don't restore stack info */ + + if (!pc) + abort(); + + write_memory (fake_pc, restore_insn_opcodes, sizeof (restore_insn_opcodes)); + + clear_proceed_status (); + stop_after_trap = 1; + proceed (fake_pc, 0, 0); + + write_register (PC_REGNUM, pc); + write_register (NPC_REGNUM, npc); + restore_inferior_status (&inf_status); +} + +/* + * This routine should be more specific in it's actions; making sure + * that it uses the same register in the initial prologue section. + */ +CORE_ADDR +skip_prologue (pc) + CORE_ADDR pc; +{ + union + { + union insn_fmt insn; + int i; + } x; + int dest = -1; + + x.i = read_memory_integer (pc, 4); + + /* Recognize sethi insn. Record destination. */ + if (x.insn.sethi.op == 0 + && x.insn.sethi.op2 == 4) + { + dest = x.insn.sethi.rd; + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* Recognizes an add immediate value to register to either %g1 or + the destination register recorded above. Actually, this might + well recognize several different arithmetic operations.*/ + if (x.insn.arith_imm.op == 2 + && x.insn.arith_imm.i == 1 + && (x.insn.arith_imm.rd == 1 + || x.insn.arith_imm.rd == dest)) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* This recognizes any SAVE insn. But why do the XOR and then + the compare? That's identical to comparing against 60 (as long + as there isn't any sign extension). */ + if (x.insn.arith.op == 2 + && (x.insn.arith.op3 ^ 32) == 28) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* Now we need to recognize stores into the frame from the input + registers. This recognizes all non alternate stores of input + register, into a location offset from the frame pointer. */ + while (x.insn.arith_imm.op == 3 + && (x.insn.arith_imm.op3 & 0x3c) == 4 /* Store, non-alt */ + && (x.insn.arith_imm.rd & 0x18) == 0x18 /* Input register */ + && x.insn.arith_imm.i == 1 /* Immediate mode */ + && x.insn.arith_imm.rs1 == 30 /* Off of frame pointer */ + && x.insn.arith_imm.simm >= 0x44 /* Into reserved */ + && x.insn.arith_imm.simm < 0x5b) /* stack space. */ + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + return pc; +} + +/* + * Check instruction at "addr" to see if it is an annulled branch. + * All other instructions will go to NPC or will trap. + * + * Set *target if we find a candidate branch; set to zero if not. + */ + +branch_type +isannulled (addr, target) + CORE_ADDR addr, *target; +{ + union insn_fmt instr; + branch_type val = not_branch; + long offset; /* Must be signed for sign-extend */ + + *target = 0; + instr.intval = read_memory_integer (addr, 4); + /* printf("intval = %x\n",instr.intval); */ + switch (instr.op1.op1) + { + case 0: /* Format 2 */ + switch(instr.op2.op2) + { + case 2: case 6: case 7: /* Bcc, FBcc, CBcc */ + if (instr.branch.cond == 8) + val = instr.branch.a ? baa : ba; + else + val = instr.branch.a ? bicca : bicc; + /* 22 bits, sign extended */ + offset = 4 * ((int) (instr.branch.disp << 10) >> 10); + *target = addr + offset; + break; + } + break; + } + /*printf("isannulled ret: %d\n",val); */ + return val; +} diff --git a/gdb/sparc-opcode.h b/gdb/sparc-opcode.h index 1122142..f20a209 100644 --- a/gdb/sparc-opcode.h +++ b/gdb/sparc-opcode.h @@ -1 +1,116 @@ -/* This file is empty. */ +/* Sparc opcde list for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + +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! +*/ + +struct op1_fmt +{ + unsigned op1 : 2; + unsigned dummy : 30; +}; + +struct op2_fmt +{ + unsigned dummy1 : 7; + unsigned op2 : 3; + unsigned dummy2 : 22; +}; + +struct op3_fmt +{ + unsigned dummy1 : 7; + unsigned op3 : 6; + unsigned dummy2 : 19; +}; + +struct call_fmt +{ + unsigned op : 2; + unsigned disp : 30; +}; + +struct sethi_fmt +{ + unsigned op : 2; + unsigned rd : 5; + unsigned op2 : 3; + unsigned imm : 22; +}; + +struct branch_fmt +{ + unsigned op : 2; + unsigned a : 1; + unsigned cond : 4; + unsigned op2 : 3; + unsigned disp : 22; /* this should really be signed. */ +}; + +struct ldst_fmt +{ + unsigned op : 2; + unsigned rd : 5; + unsigned op3 : 6; + unsigned rs1 : 5; + unsigned i : 1; + unsigned asi : 8; + unsigned rs2 : 5; +}; + +struct arith_imm_fmt +{ + unsigned op : 2; + unsigned rd : 5; + unsigned op3 : 6; + unsigned rs1 : 5; + unsigned i : 1; + int simm : 13; /* Hopefully signed, but . . . */ +}; + +struct arith_fmt +{ + unsigned op : 2; + unsigned rd : 5; + unsigned op3 : 6; + unsigned rs1 : 5; + unsigned i : 1; + unsigned opf : 8; + unsigned rs2 : 5; +}; + +union insn_fmt +{ + struct op1_fmt op1; + struct op2_fmt op2; + struct op3_fmt op3; + struct call_fmt call; + struct sethi_fmt sethi; + struct branch_fmt branch; + struct ldst_fmt ldst; + struct arith_imm_fmt arith_imm; + struct arith_fmt arith; + int intval; + float floatval; /* ?? */ +}; + +typedef enum +{ + Error, not_branch, bicc, bicca, ba, baa, ticc, ta, +} branch_type; + diff --git a/gdb/sparc-pinsn.c b/gdb/sparc-pinsn.c index e7aba32..f7ba376 100644 --- a/gdb/sparc-pinsn.c +++ b/gdb/sparc-pinsn.c @@ -33,101 +33,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! on STREAM. Returns length of the instruction, in bytes, which is always 4. */ -struct op1_fmt -{ - unsigned op1 : 2; - unsigned dummy : 30; -}; - -struct op2_fmt -{ - unsigned dummy1 : 7; - unsigned op2 : 3; - unsigned dummy2 : 22; -}; - -struct op3_fmt -{ - unsigned dummy1 : 7; - unsigned op3 : 6; - unsigned dummy2 : 19; -}; - -struct call_fmt -{ - unsigned op : 2; - unsigned disp : 30; -}; - -struct sethi_fmt -{ - unsigned op : 2; - unsigned rd : 5; - unsigned op2 : 3; - unsigned imm : 22; -}; - -struct branch_fmt -{ - unsigned op : 2; - unsigned a : 1; - unsigned cond : 4; - unsigned op2 : 3; - unsigned disp : 22; /* this should really be signed. */ -}; - -struct ldst_fmt -{ - unsigned op : 2; - unsigned rd : 5; - unsigned op3 : 6; - unsigned rs1 : 5; - unsigned i : 1; - unsigned asi : 8; - unsigned rs2 : 5; -}; - -struct arith_imm_fmt -{ - unsigned op : 2; - unsigned rd : 5; - unsigned op3 : 6; - unsigned rs1 : 5; - unsigned i : 1; - unsigned simm : 13; -}; - -struct arith_fmt -{ - unsigned op : 2; - unsigned rd : 5; - unsigned op3 : 6; - unsigned rs1 : 5; - unsigned i : 1; - unsigned opf : 8; - unsigned rs2 : 5; -}; - -union insn_fmt -{ - struct op1_fmt op1; - struct op2_fmt op2; - struct op3_fmt op3; - struct call_fmt call; - struct sethi_fmt sethi; - struct branch_fmt branch; - struct ldst_fmt ldst; - struct arith_imm_fmt arith_imm; - struct arith_fmt arith; - int intval; - float floatval; /* ?? */ -}; - -typedef enum -{ - Error, not_branch, bicc, bicca, ba, baa, ticc, ta, -} branch_type; - static char *icc_name[] = { "~", "eq", "le", "lt", "leu", "ltu", "neg", "vs", "", "ne", "gt", "ge", "gtu", "geu", "pos", "vc"}; @@ -256,12 +161,16 @@ print_insn (memaddr, stream) } else if (insn.arith.i) { + /* With explicit sign extension. */ fprintf (stream, "%s%s %s,0x%x,%s", - name, tmp, rs1, insn.arith_imm.simm, rd); + name, tmp, rs1, + (int) (insn.arith_imm.simm << 19) >> 19, + rd); if (last_sethi_target == insn.arith.rd) { fprintf (stream, "\t! "); - print_address (sethi_value + insn.arith_imm.simm); + print_address (sethi_value + + (int) (insn.arith_imm.simm << 19) >> 19); } } else @@ -287,7 +196,7 @@ print_insn (memaddr, stream) /* tagged add/sub insns and shift insns. */ if (insn.arith.i) { - int i = insn.arith_imm.simm; + int i = (int) (insn.arith_imm.simm << 19) >> 19; if (op > 4) /* Its a shift insn. */ i &= 31; @@ -363,7 +272,7 @@ print_insn (memaddr, stream) { fprintf (stream, "%s %s,0x%x,%s", rndop_ptr, rs1, - ((insn.arith_imm.simm << 19) >> 19), rd); + ((int) (insn.arith_imm.simm << 19) >> 19), rd); } else { @@ -437,7 +346,9 @@ fprint_addr1 (stream, name, insn) if (insn.arith.i) { fprintf (stream, "%s %s,0x%x,%s", - name, rs1, insn.arith_imm.simm, rd); + name, rs1, + (int) (insn.arith_imm.simm << 19) >> 19, + rd); } else { @@ -730,82 +641,3 @@ fprint_fpop (stream, insn, op, opcode) fprintf (stream, "0x%08x (unimplemented fpop insn)", insn.intval); } -/* Set *target if we find a branch */ -branch_type -isabranch (addr, target) - CORE_ADDR addr, *target; -{ - union insn_fmt instr; - branch_type val = not_branch; - long offset; /* Must be signed for sign-extend */ - - *target = 0; - instr.intval = read_memory_integer (addr, 4); - /* printf("intval = %x\n",instr.intval); */ - switch (instr.op1.op1) - { - case 0: /* Format 2 */ - switch(instr.op2.op2) - { - case 2: case 6: /* BICC & FBCC */ - if (instr.branch.cond == 8) - val = instr.branch.a ? baa : ba; - else - val = instr.branch.a ? bicca : bicc; - /* 22 bits, sign extended */ - offset = ((instr.branch.disp << 10) >> 10); - *target = addr + offset; - break; - } - break; - } - /*printf("isabranch ret: %d\n",val); */ - return val; -} - -CORE_ADDR skip_prologue (pc) - CORE_ADDR pc; -{ - union - { - struct insn_fmt insn; - int i; - } x; - int dest = -1; - - x.i = read_memory_integer (pc, 4); - if (x.insn.sethi.op == 0 && x.insn.sethi.op2 == 4) - { - dest = x.insn.sethi.rd; - pc += 4; - x.i = read_memory_integer (pc, 4); - } - if (x.insn.arith_imm.op == 2 && x.insn.arith_imm.i == 1 - && (x.insn.arith_imm.rd == 1 || x.insn.arith_imm.rd == dest)) - { - pc += 4; - x.i = read_memory_integer (pc, 4); - } - if (x.insn.arith.op == 2 && (x.insn.arith.op3 ^ 32) == 28) - { - pc += 4; - } - return pc; -} - -CORE_ADDR -frame_saved_pc (frame, next_frame) - CORE_ADDR frame; - CORE_ADDR next_frame; -{ - CORE_ADDR prev_pc; - - if (next_frame) - prev_pc = GET_RWINDOW_REG (next_frame, rw_in[7]); - else if (frame) - prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]); - else - error ("frame_saved_pc called without a frame"); - - return PC_ADJUST (prev_pc); -} diff --git a/gdb/firstfile.c b/gdb/stab.def similarity index 53% rename from gdb/firstfile.c rename to gdb/stab.def index b50ea9e..8657e6b 100644 --- a/gdb/firstfile.c +++ b/gdb/stab.def @@ -1,7 +1,5 @@ -/* Find the initialization functions of following files. - This goes with initialize.h and lastfile.c. - - Copyright (C) 1986 Free Software Foundation, Inc. +/* Table of DBX symbol codes for the GNU system. + Copyright (C) 1988 Free Software Foundation, Inc. NO WARRANTY @@ -32,7 +30,7 @@ DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. 1. You may copy and distribute verbatim copies of this source file as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy a valid copyright notice "Copyright -(C) 1986 Free Software Foundation, Inc."; and include following the + (C) 1988 Free Software Foundation, Inc."; and include following the copyright notice a verbatim copy of the above disclaimer of warranty and of this License. You may charge a distribution fee for the physical act of transferring a copy. @@ -59,9 +57,9 @@ Mere aggregation of another unrelated program with this program (or its derivative) on a volume of a storage or distribution medium does not bring the other program under the scope of these terms. - 3. You may copy and distribute this 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: + 3. You may copy and distribute this program or any portion of it in +compiled, executable or object code form under the terms of Paragraphs +1 and 2 above provided that you do the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of @@ -96,67 +94,108 @@ programs whose distribution conditions are different, write to the Free Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet worked out a simple rule that can be stated here, but we will often permit this. We 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 +all derivatives our free software and of promoting the sharing and reuse of software. 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! */ - - - -/* This is a magical hack for finding, automatically, - all the files that are linked together - and calling an initialization function in each one - without requiring the main file to know which other - files there are. - - Call initialize_all_files to run the initialization functions - of all the files. Each initialization function can enter - the commands of its file into a global data base so that the - contents of the file can be used. - - The files to be found must follow this file. Each of them - must start START_FILE, before any other functions, - and end with END_FILE, after any other functions. - These macros are defined in initialize.h. - In addition, each file must contain a function named - `initialize', which will be called with no arguments. - - After the files to be found must come the file `lastfile' - which ends the chain of calls. */ - -#include "initialize.h" - -static initialize_next_file (); -static initialize_dummy_1 (); -static initialize_dummy_2 (); - -initialize_all_files () -{ - initialize_next_file ((char *) initialize_dummy_2 - - (char *) initialize_dummy_1); -} - -/* The next two functions exist just so we can find - out how long the first of them is. - That tells us how long initialize_next_file is, - since that function has the same definition as this one. */ - -static -initialize_dummy_1 (offset) - int offset; -{ - long addr = FILEADDR_ROUND ((int) initialize_next_file + offset); - (*(void (*) ()) addr) (offset); -} - -static -initialize_dummy_2 () -{ -} - -/* This makes the function initialize_next_file. */ - -END_FILE + +/* 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. */ +__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/gdb/stab.gnu.h b/gdb/stab.gnu.h new file mode 100644 index 0000000..77f2d41 --- /dev/null +++ b/gdb/stab.gnu.h @@ -0,0 +1,16 @@ +#ifndef __GNU_STAB__ + +/* Indicate the GNU stab.h is in use. */ + +#define __GNU_STAB__ + +#define __define_stab(NAME, CODE, STRING) NAME=CODE, + +enum __stab_debug_code +{ +#include "stab.def" +}; + +#undef __define_stab + +#endif /* __GNU_STAB_ */ diff --git a/gdb/stack.c b/gdb/stack.c index 439a729..8a78b09 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1,5 +1,5 @@ /* Print and select stack frames for GDB, the GNU debugger. - Copyright (C) 1986, 1987 Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1989 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 @@ -21,12 +21,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "frame.h" +#include "inferior.h" +#include "gdbcore.h" -START_FILE /* Thie "selected" stack frame is used by default for local and arg access. May be zero, for no selected frame. */ @@ -39,6 +39,9 @@ FRAME selected_frame; int selected_frame_level; +/* Error message when selected_frame is zero when it's needed */ +char no_sel_frame[] = "There is no current stack frame."; + /* Nonzero means print the full filename and linenumber when a frame is printed, and do so in a format programs can parse. */ @@ -58,17 +61,23 @@ void print_frame_info (); If SOURCE is 1, print the source line as well. If SOURCE is -1, print ONLY the source line. */ +/* FIXME, the argument "frame" is always "selected_frame". This is why + we can say "No selected frame" if it == 0. Probably shouldn't be an + argument anymore... */ + static void print_stack_frame (frame, level, source) FRAME frame; int level; int source; { - struct frame_info fi; + struct frame_info *fi; + if (frame == 0) + error (no_sel_frame); fi = get_frame_info (frame); - print_frame_info (&fi, level, source, 1); + print_frame_info (fi, level, source, 1); } void @@ -78,14 +87,13 @@ print_frame_info (fi, level, source, args) int source; int args; { - register FRAME frame = fi->frame; struct symtab_and_line sal; struct symbol *func; register char *funname = 0; int numargs; sal = find_pc_line (fi->pc, fi->next_frame); - func = get_frame_function (frame); + func = find_pc_function (fi->pc); if (func) funname = SYMBOL_NAME (func); else @@ -97,10 +105,6 @@ print_frame_info (fi, level, source, args) if (source >= 0 || !sal.symtab) { - /* This avoids a bug in cc on the sun. */ - struct frame_info tem; - tem = *fi; - if (level >= 0) printf ("#%-2d ", level); if (fi->pc != sal.pc || !sal.symtab) @@ -108,8 +112,8 @@ print_frame_info (fi, level, source, args) printf ("%s (", funname ? funname : "??"); if (args) { - FRAME_NUM_ARGS (numargs, tem); - print_frame_args (func, FRAME_ARGS_ADDRESS (tem), numargs, stdout); + FRAME_NUM_ARGS (numargs, fi); + print_frame_args (func, fi, numargs, stdout); } printf (")"); if (sal.symtab) @@ -149,11 +153,112 @@ print_sel_frame (just_source) /* 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 (); /* FIXME, never called! */ + +#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: + if (selected_frame == 0) + error (no_sel_frame); + 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 */ +} + /* Print verbosely the selected frame or the frame at address ADDR. This means absolutely all information in the frame is printed. */ @@ -161,8 +266,8 @@ static void frame_info (addr_exp) char *addr_exp; { - FRAME frame = addr_exp ? parse_and_eval_address (addr_exp) : selected_frame; - struct frame_info fi; + FRAME frame; + struct frame_info *fi; struct frame_saved_regs fsr; struct symtab_and_line sal; struct symbol *func; @@ -171,15 +276,17 @@ frame_info (addr_exp) char *funname = 0; int numargs; + frame = parse_frame_specification (addr_exp); + fi = get_frame_info (frame); - get_frame_saved_regs (&fi, &fsr); - sal = find_pc_line (fi.pc, fi.next_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); + register int misc_index = find_pc_misc_function (fi->pc); if (misc_index >= 0) funname = misc_function_vector[misc_index].name; } @@ -187,23 +294,23 @@ frame_info (addr_exp) if (!addr_exp && selected_frame_level >= 0) printf ("Stack level %d, frame at 0x%x:\n pc = 0x%x", - selected_frame_level, frame, fi.pc); + selected_frame_level, FRAME_FP(frame), fi->pc); else printf ("Stack frame at 0x%x:\n pc = 0x%x", - frame, fi.pc); + 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, fi.next_frame)); + printf ("; saved pc 0x%x\n", FRAME_SAVED_PC (frame)); if (calling_frame) - printf (" called by frame at 0x%x", calling_frame); - if (fi.next_frame && 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) + if (fi->next_frame) + printf (" caller of frame at 0x%x", fi->next_frame); + if (fi->next_frame || calling_frame) printf ("\n"); printf (" Arglist at 0x%x,", FRAME_ARGS_ADDRESS (fi)); FRAME_NUM_ARGS (i, fi); @@ -217,7 +324,7 @@ frame_info (addr_exp) printf (" %d args: ", i); FRAME_NUM_ARGS (numargs, fi); - print_frame_args (func, FRAME_ARGS_ADDRESS (fi), numargs, stdout); + print_frame_args (func, fi, numargs, stdout); printf ("\n"); count = 0; for (i = 0; i < NUM_REGS; i++) @@ -238,29 +345,103 @@ frame_info (addr_exp) 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; + struct frame_info *fi; register int count; register FRAME frame; register int i; - + register FRAME trailing; + register int trailing_level; + + if (have_inferior_p () == 0 && corefile == 0) + error ("There is no running program or core file."); + + /* 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); + { + 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 +#if 0 + count = backtrace_limit; +#else count = -1; +#endif - for (i = 0, frame = get_current_frame (), fi = get_frame_info (frame); + for (i = 0, frame = trailing; frame && count--; - i++, fi = get_prev_frame_info (fi.frame), frame = fi.frame) + i++, frame = get_prev_frame (frame)) { QUIT; - print_frame_info (&fi, i, 0, 1); + 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 ("(More stack frames follow...)\n"); } /* Print the local variables of a block B active in FRAME. */ @@ -305,7 +486,9 @@ print_frame_local_vars (frame, stream) register FRAME frame; register FILE *stream; { - register struct block *block = get_frame_block (frame); + register struct block *block; + + block = get_frame_block (frame); if (block == 0) return 0; while (block != 0) @@ -324,6 +507,8 @@ print_frame_local_vars (frame, stream) static void locals_info () { + if (selected_frame == 0) + error(no_sel_frame); print_frame_local_vars (selected_frame, stdout); } @@ -332,12 +517,13 @@ print_frame_arg_vars (frame, stream) register FRAME frame; register FILE *stream; { - struct symbol *func = get_frame_function (frame); + struct symbol *func; register struct block *b; int nsyms; register int i; register struct symbol *sym; + func = get_frame_function (frame); if (func == 0) return 0; @@ -362,6 +548,8 @@ print_frame_arg_vars (frame, stream) static void args_info () { + if (selected_frame == 0) + error(no_sel_frame); print_frame_arg_vars (selected_frame, stdout); } @@ -380,11 +568,11 @@ select_frame (frame, level) /* Store the selected frame and its level into *FRAMEP and *LEVELP. */ void -record_selected_frame (framep, levelp) - FRAME *framep; +record_selected_frame (frameaddrp, levelp) + FRAME_ADDR *frameaddrp; int *levelp; { - *framep = selected_frame; + *frameaddrp = FRAME_FP (selected_frame); *levelp = selected_frame_level; } @@ -417,9 +605,10 @@ find_relative_frame (frame, level_offset_ptr) register int* level_offset_ptr; { register FRAME prev; - struct frame_info fi; register FRAME frame1, frame2; + if (frame == 0) + error (no_sel_frame); /* Going up is simple: just do get_prev_frame enough times or until initial frame is reached. */ while (*level_offset_ptr > 0) @@ -459,37 +648,33 @@ find_relative_frame (frame, level_offset_ptr) } /* The "frame" command. With no arg, print selected frame briefly. - With arg LEVEL, select the frame at level LEVEL and print it. - With arg larger than 100000, use it as address of frame to select. - If from command file or user-defined command, don't print anything - if we have an argument. */ + 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 int i; - register FRAME frame; - unsigned int level, level1; + register FRAME frame, frame1; + unsigned int level = 0; - if (level_exp) - { - level1 = level = parse_and_eval_address (level_exp); - if (level > 100000) - { - select_frame (level, -1); - frame_info (0); - return; - } + frame = parse_frame_specification (level_exp); - frame = find_relative_frame (get_current_frame (), &level1); - if (level1 != 0) - error ("Stack level %d is out of range.", level); - select_frame (frame, level); - if (! from_tty) - return; - } + for (frame1 = get_prev_frame (0); + frame1 && frame1 != frame; + frame1 = get_prev_frame (frame1)) + level++; + + if (!frame1) + level = 0; + + select_frame (frame, level); + + if (!from_tty) + return; print_stack_frame (selected_frame, selected_frame_level, 1); } @@ -578,9 +763,15 @@ return_command (retval_exp, from_tty) frame_command ("0", 1); } -static -initialize () +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\ @@ -607,7 +798,8 @@ 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."); + "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, @@ -620,6 +812,13 @@ a command file or a user-defined command."); "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 } -END_FILE diff --git a/gdb/standalone.c b/gdb/standalone.c index 45cca6a..eb456ff 100644 --- a/gdb/standalone.c +++ b/gdb/standalone.c @@ -31,14 +31,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! #endif /* SIGTSTP and SIGIO defined (must be 4.2) */ #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "frame.h" #include "inferior.h" #include "wait.h" -START_FILE /* Random system calls, mostly no-ops to prevent link problems */ @@ -582,8 +580,7 @@ char heap[HEAP_SIZE] = {0}; int kdb_stack_beg[STACK_SIZE / sizeof (int)]; int kdb_stack_end; -static -initialize () +_initialize_standalone () { register char *next; @@ -603,4 +600,3 @@ initialize () memory_limit = heap + sizeof heap; } -END_FILE diff --git a/gdb/sun3-dep.c b/gdb/sun3-dep.c new file mode 100644 index 0000000..9bab095 --- /dev/null +++ b/gdb/sun3-dep.c @@ -0,0 +1,586 @@ +/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. + Copyright (C) 1986, 1987 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +extern int errno; +extern int attach_flag; + +/* 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"); + } +} + +#ifdef ATTACH_DETACH + +/* Start debugging the process whose number is PID. */ + +attach (pid) + int pid; +{ + errno = 0; + ptrace (PTRACE_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 (PTRACE_DETACH, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; +#ifndef sun2 + struct fp_status inferior_fp_registers; +#endif sun2 + extern char registers[]; + + if (remote_debugging) + remote_fetch_registers (registers); + else + { + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); +#ifndef sun2 + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); +#endif sun2 + + bcopy (&inferior_registers, registers, 16 * 4); +#ifndef sun2 + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); +#endif sun2 + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; +#ifndef sun2 + bcopy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); +#endif sun2 + } +} + +/* 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; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + if (remote_debugging) + remote_store_registers (registers); + else + { + bcopy (registers, &inferior_registers, 16 * 4); + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); + } +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes 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; +} + + +/* Machine-dependent code which would otherwise be in core.c */ +/* Work with core dump and executable files, for GDB. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#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; + +#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) + { + 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); + + { + struct core corestr; + + val = myread (corechan, &corestr, sizeof corestr); + if (val < 0) + perror_with_name (filename); + if (corestr.c_magic != CORE_MAGIC) + error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", + filename, corestr.c_magic, (int) CORE_MAGIC); + else if (sizeof (struct core) != corestr.c_len) + error ("\"%s\" has an invalid struct core length (%d, expected %d)", + filename, corestr.c_len, (int) sizeof (struct core)); + + data_start = exec_data_start; + data_end = data_start + corestr.c_dsize; + stack_start = stack_end - corestr.c_ssize; + data_offset = sizeof corestr; + stack_offset = sizeof corestr + corestr.c_dsize; + + bcopy (&corestr.c_regs, registers, 16 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; +#ifdef FPU + bcopy (corestr.c_fpu.f_fpstatus.fps_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof corestr.c_fpu.f_fpstatus.fps_regs); + bcopy (&corestr.c_fpu.f_fpstatus.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof corestr.c_fpu.f_fpstatus - sizeof corestr.c_fpu.f_fpstatus.fps_regs); +#else + bcopy (corestr.c_fpstatus.fps_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof corestr.c_fpstatus.fps_regs); + bcopy (&corestr.c_fpstatus.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof corestr.c_fpstatus - sizeof corestr.c_fpstatus.fps_regs); +#endif + bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); + + printf ("Core file is from \"%s\".\n", corestr.c_cmdname); + if (corestr.c_signo > 0) + printf ("Program terminated with signal %d, %s.\n", + corestr.c_signo, + corestr.c_signo < NSIG + ? sys_siglist[corestr.c_signo] + : "(undocumented)"); + } + 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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; + 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); +} + diff --git a/gdb/symmisc.c b/gdb/symmisc.c index 5d50b0f..313f65d 100644 --- a/gdb/symmisc.c +++ b/gdb/symmisc.c @@ -20,7 +20,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include "defs.h" -#include "initialize.h" #include "symtab.h" #include @@ -28,7 +27,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! static void free_symtab (); -START_FILE /* Free all the symtabs that are currently installed, and all storage associated with them. @@ -329,8 +327,7 @@ relocate_source (sp) RELOCATE (sp->name); for (i = 0; i < nitems; i++) - if (sp->contents.item[i] > 0) - TEXT_RELOCATE (sp->contents.item[i]); + TEXT_RELOCATE (sp->contents.item[i].pc); } /* Read symsegs from file named NAME open on DESC, @@ -358,9 +355,12 @@ read_symsegs (desc, name) len = myread (desc, &root, sizeof root); if (len == 0 || root.format == 0) break; - if (root.format != 1 || + /* 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 ("Invalid symbol segment format code"); + error ("\nInvalid symbol segment format code"); data = (char *) xmalloc (root.length); bcopy (&root, data, sizeof root); len = myread (desc, data + sizeof root, @@ -380,6 +380,7 @@ static int block_depth (); static void print_spaces (); static void print_symbol (); +void print_symtabs (filename) char *filename; { @@ -411,12 +412,8 @@ print_symtabs (filename) l = LINETABLE (s); len = l->nitems; for (i = 0; i < len; i++) - { - if (l->item[i] < 0) - line = - l->item[i] - 1; - else - fprintf (outfile, " line %d at %x\n", ++line, l->item[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); @@ -522,7 +519,7 @@ print_symbol (symbol, depth, outfile) break; case LOC_REGPARM: - fprintf (outfile, "parmameter register %d,", SYMBOL_VALUE (symbol)); + fprintf (outfile, "parameter register %d,", SYMBOL_VALUE (symbol)); break; case LOC_LOCAL: @@ -557,11 +554,24 @@ block_depth (block) return i; } -static -initialize () +/* + * 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."); } -END_FILE diff --git a/gdb/symseg.h b/gdb/symseg.h index a04727e..a142e92 100644 --- a/gdb/symseg.h +++ b/gdb/symseg.h @@ -129,10 +129,10 @@ enum type_code /* Other flag bits are used with GDB. */ -#define TYPE_FLAG_HAS_CONSTRUCTOR 256 -#define TYPE_FLAG_HAS_DESTRUCTOR 512 -#define TYPE_FLAG_VIA_PUBLIC 1024 -#define TYPE_FLAG_VIA_VIRTUAL 2048 +#define TYPE_FLAG_HAS_CONSTRUCTOR 256 +#define TYPE_FLAG_HAS_DESTRUCTOR 512 +#define TYPE_FLAG_VIA_PUBLIC 1024 +#define TYPE_FLAG_VIA_VIRTUAL 2048 struct type { @@ -147,6 +147,7 @@ struct type /* For a pointer type, describes the type of object pointed to. For an array type, describes the type of the elements. For a function 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. @@ -163,12 +164,12 @@ struct type struct type *function_type; /* Handling of pointers to members: - MAIN_VARIANT is used for pointer and pointer + 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. */ + NEXT_VARIANT is the next element in the chain. */ struct type *main_variant, *next_variant; /* Flags about this type. */ @@ -214,7 +215,7 @@ struct type /* Number of methods described for this type */ short nfn_fields; - /* Number of base classes this type derives from. */ + /* Number of base classes this type derives from. */ short n_baseclasses; /* Number of methods described for this type plus all the @@ -254,6 +255,9 @@ struct type } *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. @@ -266,7 +270,10 @@ struct type int vptr_fieldno; - /* If this type has base classes, put them here. */ + /* 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. */ struct type **baseclasses; }; @@ -328,6 +335,12 @@ struct block 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. */ @@ -370,7 +383,7 @@ enum address_class LOC_STATIC, /* Value is at fixed address */ LOC_REGISTER, /* Value is in register */ LOC_ARG, /* Value is at spec'd position in arglist */ - LOC_REGPARM, /* Value is at spec'd position in register window */ + 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 @@ -406,6 +419,23 @@ struct symbol } value; }; + +struct partial_symbol +{ + /* Symbol name */ + char *name; + /* Name space code. */ + enum namespace namespace; + /* Address class (for info_symbols) */ + enum address_class class; +}; + +/* + * Vectors of all partial symbols read in from file; actually declared + * and used in dbxread.c. + */ +extern struct partial_symbol *global_psymbols, *static_psymbols; + /* Source-file information. This describes the relation between source files and line numbers @@ -417,21 +447,27 @@ struct sourcevector struct source *source[1]; /* Descriptions of the files */ }; -/* Each item is 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. +/* 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. */ - Consecutive lines can be recorded by program counter entries - with no line number entries between them. Line number entries - are used when there are lines to skip with no code on them. - This is to make the table shorter. */ +struct linetable_entry +{ + int line; + CORE_ADDR pc; +}; struct linetable - { - int nitems; - int item[1]; - }; +{ + int nitems; + struct linetable_entry item[1]; +}; /* All the information on one source file. */ diff --git a/gdb/symtab.c b/gdb/symtab.c index 19fa494..5b36c71 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -19,17 +19,13 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" -#include "initialize.h" #include "symtab.h" #include "param.h" #include #include +#include -START_FILE - -static int find_line_common(); -static int lookup_misc_func(); /* Allocate an obstack to hold objects that should be freed when we load a new symbol table. @@ -40,6 +36,15 @@ 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. */ @@ -48,20 +53,41 @@ 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; -/* Lookup the symbol table of a source file named NAME. */ +/* 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 (); +static int lookup_misc_func (); +struct partial_symtab *lookup_partial_symtab (); +struct symtab *psymtab_to_symtab (); +static struct partial_symbol *lookup_partial_symbol (); + +/* Lookup the symbol table of a source file named NAME. If there + isn't any symtab for it, lookup the psymtab and read in the + symbtab. */ struct symtab * lookup_symtab (name) char *name; { register struct symtab *s; + register struct partial_symtab *ps; register char *copy; for (s = symtab_list; s; s = s->next) @@ -77,6 +103,38 @@ lookup_symtab (name) if (!strcmp (copy, s->filename)) return s; + ps = lookup_partial_symtab (name); + if (ps) + { + s = psymtab_to_symtab (ps); + return s; + } + + return 0; +} + +/* Lookup the partial symbol table of a source file named NAME. */ + +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; + + /* If name not found as specified, see if adding ".c" helps. */ + + copy = (char *) alloca (strlen (name) + 3); + strcpy (copy, name); + strcat (copy, ".c"); + for (s = partial_symtab_list; s; s = s->next) + if (!strcmp (copy, s->filename)) + return s; + return 0; } @@ -90,7 +148,7 @@ lookup_typename (name, block, noerr) struct block *block; int noerr; { - register struct symbol *sym = lookup_symbol (name, block, VAR_NAMESPACE); + register struct symbol *sym = lookup_symbol (name, block, VAR_NAMESPACE, 0); if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF) { if (!strcmp (name, "int")) @@ -138,11 +196,13 @@ lookup_struct (name, block) char *name; struct block *block; { - register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + 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 union or enum %s, not a struct.", name); + error ("This context has class, union or enum %s, not a struct.", name); return SYMBOL_TYPE (sym); } @@ -154,11 +214,13 @@ lookup_union (name, block) char *name; struct block *block; { - register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + 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 struct or enum %s, not a union.", name); + error ("This context has class, struct or enum %s, not a union.", name); return SYMBOL_TYPE (sym); } @@ -170,11 +232,12 @@ lookup_enum (name, block) char *name; struct block *block; { - register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + 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 struct or union %s, not an enum.", name); + error ("This context has class, struct or union %s, not an enum.", name); return SYMBOL_TYPE (sym); } @@ -238,14 +301,15 @@ lookup_reference_type (type) 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 (domain, type) - struct type *domain, *type; +lookup_member_type (type, domain) + struct type *type, *domain; { register struct type *mtype = TYPE_MAIN_VARIANT (type); struct type *main_type; @@ -266,7 +330,8 @@ lookup_member_type (domain, type) sizeof (struct type)); bzero (mtype, sizeof (struct type)); - if (main_type == 0) main_type = mtype; + if (main_type == 0) + main_type = mtype; else { TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type); @@ -283,6 +348,16 @@ lookup_member_type (domain, type) 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; } @@ -352,9 +427,8 @@ lookup_basetype_type (type, offset, via_virtual, via_public) May need to construct such a type if this is the first use. */ struct type * -lookup_function_type (type, argtypes) +lookup_function_type (type) struct type *type; - struct type **argtypes; { register struct type *ptype = TYPE_FUNCTION_TYPE (type); if (ptype) return ptype; @@ -466,17 +540,24 @@ 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. */ + 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_1 (name, block, namespace) +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; struct blockvector *bv; /* Search specified block and its superiors. */ @@ -484,87 +565,147 @@ lookup_symbol_1 (name, block, namespace) while (block != 0) { sym = lookup_block_symbol (block, name, namespace); - if (sym) return sym; + if (sym) + { + block_found = block; + return sym; + } block = BLOCK_SUPERBLOCK (block); } - return 0; -} -struct symbol * -lookup_symbol_2 (name, block, namespace) - char *name; - register struct block *block; /* ignored as parameter */ - enum namespace namespace; -{ - register int i, n; - register struct symbol *sym; - register struct symtab *s; - struct blockvector *bv; + /* 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) + { + int v = (int) 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 symtabs' global blocks. */ + /* 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) return sym; + if (sym) + { + block_found = block; + return sym; + } } - /* Now search all symtabs' per-file blocks. - Not strictly correct, but more useful than an error. */ + for (ps = partial_symtab_list; ps; ps = ps->next) + if (lookup_partial_symbol (ps, name, 1, namespace)) + { + s = psymtab_to_symtab(ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, 0); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + fatal ("Internal: global symbol found in psymtab but not in symtab"); + 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) return sym; + if (sym) + { + block_found = block; + return sym; + } } + + for (ps = partial_symtab_list; ps; ps = ps->next) + if (lookup_partial_symbol (ps, name, 0, namespace)) + { + s = psymtab_to_symtab(ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, 1); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + fatal ("Internal: static symbol found in psymtab but not in symtab"); + return sym; + } + return 0; } -struct symbol * -lookup_symbol (name, block, namespace) +/* Look, in partial_symtab PST, for symbol NAME. Check the global + symbols if GLOBAL, the static symbols if not */ + +static struct partial_symbol * +lookup_partial_symbol (pst, name, global, namespace) + struct partial_symtab *pst; char *name; - register struct block *block; + int global; enum namespace namespace; { - register int i, n; - register struct symbol *sym; - register struct symtab *s; - struct blockvector *bv; + struct partial_symbol *start, *psym; + int length = (global ? pst->n_global_syms : pst->n_static_syms); - /* Search specified block and its superiors. */ + start = (global ? + global_psymbols + pst->globals_offset : + static_psymbols + pst->statics_offset ); - while (block != 0) + if (!length) + return (struct partial_symbol *) 0; + + if (global) /* This means we can use a binary */ + /* search. */ { - sym = lookup_block_symbol (block, name, namespace); - if (sym) return sym; - block = BLOCK_SUPERBLOCK (block); - } - - /* Now search all symtabs' global blocks. */ + struct partial_symbol *top, *bottom, *center; + + /* 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; - 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) return sym; + assert (center < top); + + if (strcmp (SYMBOL_NAME (center), name) >= 0) + top = center; + else + bottom = center + 1; + } + assert (top == bottom); + + while (!strcmp (SYMBOL_NAME (top), name)) + { + if (SYMBOL_NAMESPACE (top) == namespace) + return top; + top ++; + } } - - /* Now search all symtabs' per-file blocks. - Not strictly correct, but more useful than an error. */ - - for (s = symtab_list; s; s = s->next) + else { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, 1); - sym = lookup_block_symbol (block, name, namespace); - if (sym) return sym; + /* Can't use a binary search */ + for (psym = start; psym < start + length; psym++) + if (namespace == SYMBOL_NAMESPACE (psym) + && !strcmp (name, SYMBOL_NAME (psym))) + return psym; } - return 0; + + return (struct partial_symbol *) 0; } /* Look for a symbol in block BLOCK. */ @@ -576,7 +717,7 @@ lookup_block_symbol (block, name, namespace) enum namespace namespace; { register int bot, top, inc; - register struct symbol *sym; + register struct symbol *sym, *parameter_sym; top = BLOCK_NSYMS (block); bot = 0; @@ -631,8 +772,15 @@ lookup_block_symbol (block, name, namespace) /* Here if block isn't sorted. This loop is equivalent to the loop above, - but hacked greatly for speed. */ + 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) @@ -641,10 +789,16 @@ lookup_block_symbol (block, name, namespace) if (SYMBOL_NAME (sym)[0] == inc && !strcmp (SYMBOL_NAME (sym), name) && SYMBOL_NAMESPACE (sym) == namespace) - return sym; + { + if (SYMBOL_CLASS (sym) == LOC_ARG || + SYMBOL_CLASS (sym) == LOC_REGPARM) + parameter_sym = sym; + else + return sym; + } bot++; } - return 0; + return parameter_sym; /* Will be 0 if not found. */ } /* Return the symbol for the function which contains a specified @@ -669,6 +823,7 @@ find_pc_symtab (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 */ @@ -681,6 +836,14 @@ find_pc_symtab (pc) break; } + if (!s) + for (ps = partial_symtab_list; ps; ps = ps->next) + if (pc >= ps->textlow && pc < ps->texthigh) + { + s = psymtab_to_symtab (ps); + break; + } + return s; } @@ -700,8 +863,8 @@ find_pc_line (pc, notcurrent) struct symtab *s; register struct linetable *l; register int len; - register int i, item; - int line; + register int i; + register struct linetable_entry *item; struct symtab_and_line value; struct blockvector *bv; @@ -745,6 +908,7 @@ find_pc_line (pc, notcurrent) value.symtab = 0; value.line = 0; value.pc = pc; + value.end = 0; return value; } @@ -763,26 +927,21 @@ find_pc_line (pc, notcurrent) first_line = -1; for (i = 0; i < len; i++) { - item = l->item[i]; - if (item < 0) - line = - item - 1; - else + item = &(l->item[i]); + + if (first_line < 0) { - line++; - if (first_line < 0) - { - first_line = line; - first_pc = item; - } - /* Return the last line that did not start after PC. */ - if (pc >= item) - { - prev_line = line; - prev_pc = item; - } - else - break; + 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? @@ -793,7 +952,7 @@ find_pc_line (pc, notcurrent) best_line = prev_line; best_symtab = s; if (i < len) - best_end = item; + best_end = item->pc; else best_end = 0; } @@ -843,7 +1002,7 @@ find_line_pc (symtab, line) return 0; l = LINETABLE (symtab); index = find_line_common(l, line, &dummy); - return index ? l->item[index] : 0; + return index ? l->item[index].pc : 0; } /* Find the range of pc values in a line. @@ -871,7 +1030,7 @@ find_line_pc_range (symtab, thisline, startptr, endptr) index = find_line_common (l, thisline, &exact_match); if (index) { - *startptr = l->item[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) @@ -879,8 +1038,8 @@ find_line_pc_range (symtab, thisline, startptr, endptr) else /* Perhaps the following entry is for the following line. It's worth a try. */ - if (l->item[index+1] > 0) - *endptr = l->item[index+1]; + if (l->item[index+1].line == thisline + 1) + *endptr = l->item[index+1].pc; else *endptr = find_line_pc (symtab, thisline+1); return 1; @@ -919,24 +1078,18 @@ find_line_common (l, lineno, exact_match) len = l->nitems; for (i = 0; i < len; i++) { - register int item = l->item[i]; + register struct linetable_entry *item = &(l->item[i]); - if (item < 0) - nextline = - item - 1; - else + if (item->line == lineno) { - nextline++; - if (nextline == lineno) - { - *exact_match = 1; - return i; - } + *exact_match = 1; + return i; + } - if (nextline > lineno && (best == 0 || nextline < best)) - { - best = lineno; - best_index = i; - } + if (item->line > lineno && (best == 0 || item->line < best)) + { + best = item->line; + best_index = i; } } @@ -1008,7 +1161,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) struct symbol **sym_arr; struct type *t, *field; char **physnames; - + /* Defaults have defaults. */ if (default_symtab == 0) @@ -1043,6 +1196,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) if (p[0] == ':') { + /* C++ */ if (p[1] ==':') { @@ -1058,7 +1212,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) while (*p == ' ' || *p == '\t') p++; *argptr = p; - sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE); + sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0); if (sym_class && (TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_STRUCT @@ -1090,7 +1244,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) 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); + sym_arr[i1] = lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), VAR_NAMESPACE, 0); if (sym_arr[i1]) i1++; } else while (t) @@ -1098,7 +1252,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) class_name = TYPE_NAME (t); while (*class_name++ != ' '); - sym_class = lookup_symbol (class_name, 0, STRUCT_NAMESPACE); + 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) @@ -1116,13 +1270,14 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) 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); + 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; + else + break; } if (i1 == 1) @@ -1148,7 +1303,8 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) } if (i1 > 0) { - return decode_line_2 (argptr, sym_arr, physnames, i1, funfirstline); + return decode_line_2 (argptr, sym_arr, physnames, + i1, funfirstline); } else error ("that class does not have any method named %s",copy); @@ -1158,6 +1314,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) } /* end of C++ */ + /* Extract the file name. */ p1 = p; while (p != *argptr && p[-1] == ' ') --p; @@ -1169,7 +1326,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) s = lookup_symtab (copy); if (s == 0) { - if (symtab_list == 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); } @@ -1195,6 +1352,20 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) /* 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 (symtab_list); + default_symtab = current_source_symtab; + default_line = current_source_line; + } + if (**argptr == '+') sign = plus, (*argptr)++; else if (**argptr == '-') @@ -1244,7 +1415,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) If file specified, use that file's per-file block to start with. */ sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0, - VAR_NAMESPACE); + VAR_NAMESPACE, 0); if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) { @@ -1253,7 +1424,12 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) if (funfirstline) SKIP_PROLOGUE (pc); value = find_pc_line (pc, 0); +#ifdef convex + /* 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; @@ -1278,7 +1454,7 @@ decode_line_1 (argptr, funfirstline, default_symtab, default_line) return values; } - if (symtab_list == 0) + if (symtab_list == 0 && partial_symtab_list == 0) error ("No symbol table is loaded. Use the \"symbol-file\" command."); error ("Function %s not defined.", copy); } @@ -1309,7 +1485,7 @@ decode_line_2 (argptr, sym_arr, physnames, nelts, funfirstline) char *getenv(); struct symtabs_and_lines values, return_values; register CORE_ADDR pc; - char *args, *arg1, *read_line (); + char *args, *arg1, *gdb_read_line (); int i; char *prompt; @@ -1342,7 +1518,7 @@ decode_line_2 (argptr, sym_arr, physnames, nelts, funfirstline) printf("%s ",prompt); fflush(stdout); - args = read_line (0); + args = gdb_read_line (0, 0); if (args == 0) error_no_arg ("one or more choice numbers"); @@ -1395,7 +1571,7 @@ decode_line_2 (argptr, sym_arr, physnames, nelts, funfirstline) /* Return the index of misc function named NAME. */ -static +static int lookup_misc_func (name) register char *name; { @@ -1407,38 +1583,69 @@ lookup_misc_func (name) return -1; /* not found */ } +/* + * Slave routine for sources_info + */ +static int rows_output; + +static void +output_source_filename (name, next) +char *name; +int next; +{ + static int column = 0; + + if (column != 0 && column + strlen (name) >= 70) + { + printf ("\n"); + column = 0; + if (++rows_output >= 21) + { + printf ("--Type Return to print more--"); + fflush (stdout); + gdb_read_line (0, 0); + rows_output = 0; + } + } + else if (column != 0) + { + printf (" "); + column++; + } + printf ("%s", name); + column += strlen (name); + if (next) + { + printf (","); + 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) + if (symtab_list == 0 && partial_symtab_list == 0) { printf ("No symbol table is loaded.\n"); return; } - printf ("Source files for which symbol table is known:\n"); + + printf ("Source files for which symbols have been read in:\n\n"); + rows_output = 2; for (s = symtab_list; s; s = s->next) - { - if (column != 0 && column + strlen (s->filename) >= 70) - { - printf ("\n"); - column = 0; - } - else if (column != 0) - { - printf (" "); - column++; - } - printf ("%s", s->filename); - column += strlen (s->filename); - if (s->next) - { - printf (","); - column++; - } - } + output_source_filename (s->filename, s->next); + printf ("\n\n"); + + printf ("Source files for which symbols will be read in on demand:\n\n"); + rows_output += 2; + for (ps = partial_symtab_list; ps; ps = ps->next) + output_source_filename (ps->filename, ps->next); printf ("\n"); } @@ -1453,7 +1660,7 @@ sources_info () { printf ("--Type Return to print more--"); \ print_count = 0; \ fflush (stdout); \ - read_line (); } } + gdb_read_line (0, 0); } } static void sort_block_syms (); @@ -1463,16 +1670,18 @@ list_symbols (regexp, class) 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; char *val; - int found_in_file; static char *classnames[] = {"variable", "function", "type", "method"}; int print_count = 0; + int found_in_file = 0; if (regexp) if (val = (char *) re_comp (regexp)) @@ -1484,6 +1693,54 @@ list_symbols (regexp, class) classnames[class], regexp); + /* Search through the partial_symtab_list *first* for all symbols + matching the regexp. That way we don't have to reproduce all of + the machinery below. */ + for (ps = partial_symtab_list; ps; ps = ps->next) + { + struct partial_symbol *bound, *gbound, *sbound; + int keep_going = 1; + + gbound = global_psymbols + ps->globals_offset + ps->n_global_syms; + sbound = static_psymbols + ps->statics_offset + ps->n_static_syms; + bound = gbound; + + /* Go through all of the symbols stored in a partial + symtab in one loop. */ + psym = global_psymbols + ps->globals_offset; + while (keep_going) + { + if (psym >= bound) + { + if (bound == gbound && ps->n_static_syms != 0) + { + psym = static_psymbols + ps->statics_offset; + bound = sbound; + } + else + keep_going = 0; + } + else + { + QUIT; + + /* If it would match (logic taken from loop below) + load the file and go on to the next one */ + if ((regexp == 0 || re_exec (SYMBOL_NAME (psym))) + && ((class == 0 && SYMBOL_CLASS (psym) != LOC_TYPEDEF + && SYMBOL_CLASS (psym) != LOC_BLOCK) + || (class == 1 && SYMBOL_CLASS (psym) == LOC_BLOCK) + || (class == 2 && SYMBOL_CLASS (psym) == LOC_TYPEDEF) + || (class == 3 && SYMBOL_CLASS (psym) == LOC_BLOCK))) + { + psymtab_to_symtab(ps); + keep_going = 0; + } + } + psym++; + } + } + for (s = symtab_list; s; s = s->next) { found_in_file = 0; @@ -1517,7 +1774,20 @@ list_symbols (regexp, class) print_count += 2; } found_in_file = 1; +#if 0 MORE; +#else + { + print_count++; + if (print_count >= 21) + { + printf ("--Type Return to print more--"); + print_count = 0; + fflush (stdout); + gdb_read_line (0, 0); + } + } +#endif if (class != 2 && i == 1) printf ("static "); if (class == 2 @@ -1633,8 +1903,20 @@ init_type (code, length, uns, name) return type; } -static -initialize () +/* 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; +} + +void +_initialize_symtab () { add_info ("variables", variables_info, "All global and static variable names, or those matching REGEXP."); @@ -1651,6 +1933,7 @@ are listed."); "Source files in the program."); obstack_init (symbol_obstack); + obstack_init (psymbol_obstack); builtin_type_void = init_type (TYPE_CODE_VOID, 0, 0, "void"); @@ -1666,6 +1949,11 @@ are listed."); 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 } -END_FILE diff --git a/gdb/symtab.h b/gdb/symtab.h index 10c3392..ef03c20 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -18,12 +18,15 @@ 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! */ +#include + /* An obstack to hold objects that should be freed when we load a new symbol table. This includes the symbols made by dbxread and the types that are not permanent. */ extern struct obstack *symbol_obstack; +extern struct obstack *psymbol_obstack; /* Some definitions and declarations to go with use of obstacks. */ #define obstack_chunk_alloc xmalloc @@ -38,12 +41,15 @@ extern void free (); /* 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. */ + the _'s are removed from the names stored in this table. The type is + used when sorting so that find_pc_misc_function will pick a global name + over a local name for the same address. */ struct misc_function { char *name; CORE_ADDR address; + unsigned char type; }; /* Address and length of the vector recording all misc function names/addresses. */ @@ -53,8 +59,8 @@ int misc_function_count; #include "symseg.h" -/* Each source file is represented by a struct symtab. - These objects are chained through the `next' field. */ +/* Each source file is represented by a struct symtab. */ +/* These objects are chained through the `next' field. */ struct symtab { @@ -95,10 +101,60 @@ struct symtab 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; @@ -131,6 +187,7 @@ int current_source_line; #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) @@ -225,7 +282,6 @@ int current_source_line; extern struct symtab *lookup_symtab (); extern struct symbol *lookup_symbol (); -extern struct symbol *lookup_symbol_1 (), *lookup_symbol_2 (); extern struct type *lookup_typename (); extern struct type *lookup_unsigned_typename (); extern struct type *lookup_struct (); @@ -255,6 +311,10 @@ 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; +#endif struct symtab_and_line { @@ -280,4 +340,5 @@ struct symtab_and_line find_pc_line (); 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/gdb/tags b/gdb/tags new file mode 100644 index 0000000..2b001d2 --- /dev/null +++ b/gdb/tags @@ -0,0 +1,799 @@ +ALL_BREAKPOINTS breakpoint.c /^#define ALL_BREAKPOINTS(b) for (b = breakpoint_ch/ +ASSERT malloc.c /^#define ASSERT(p) if (!(p)) botch("p"); else$/ +CHAIN malloc.c /^#define CHAIN(a) \\$/ +CORE_RELOCATE symmisc.c /^#define CORE_RELOCATE(slot) \\$/ +IGNORE_SYMBOL dbxread.c /^#define IGNORE_SYMBOL(type) (type == N_NSYMS)$/ +INFERIOR_AR0 hp9k320-dep.c /^#define INFERIOR_AR0(u) \\$/ +MAX_OF_TYPE dbxread.c /^#define MAX_OF_TYPE(t) ((1 << (sizeof (t) - 1)) - / +MIN_OF_TYPE dbxread.c /^#define MIN_OF_TYPE(t) (-(1 << (sizeof (t) - 1)))$/ +Mmain main.c /^main (argc, argv, envp)$/ +Mregex regex.c /^main (argc, argv)$/ +Mstuff stuff.c /^main (argc, argv)$/ +NEXTBYTE m68k-pinsn.c /^#define NEXTBYTE(p) (p += 2, ((char *)p)[-1])$/ +NEXTDOUBLE m68k-pinsn.c /^#define NEXTDOUBLE(p) \\$/ +NEXTEXTEND m68k-pinsn.c /^#define NEXTEXTEND(p) \\$/ +NEXTLONG m68k-pinsn.c /^#define NEXTLONG(p) \\$/ +NEXTPACKED m68k-pinsn.c /^#define NEXTPACKED(p) \\$/ +NEXTSINGLE m68k-pinsn.c /^#define NEXTSINGLE(p) \\$/ +NEXTWORD m68k-pinsn.c /^#define NEXTWORD(p) \\$/ +N_DATADDR convex-dep.c /^#define N_DATADDR(hdr) hdr.a_text$/ +N_MAGIC core.c /^#define N_MAGIC(exec) ((exec).magic)$/ +N_SET_MAGIC default-dep.c /^#define N_SET_MAGIC(exec, val) ((exec).a_magic = (/ +N_TXTADDR convex-dep.c /^#define N_TXTADDR(hdr) 0$/ +OP_C i386-pinsn.c /^OP_C (dummy)$/ +OP_D i386-pinsn.c /^OP_D (dummy)$/ +OP_DIR i386-pinsn.c /^OP_DIR (size)$/ +OP_DSSI i386-pinsn.c /^OP_DSSI (dummy)$/ +OP_E i386-pinsn.c /^OP_E (bytemode)$/ +OP_ESDI i386-pinsn.c /^OP_ESDI (dummy)$/ +OP_G i386-pinsn.c /^OP_G (bytemode)$/ +OP_I i386-pinsn.c /^OP_I (bytemode)$/ +OP_J i386-pinsn.c /^OP_J (bytemode)$/ +OP_OFF i386-pinsn.c /^OP_OFF (bytemode)$/ +OP_ONE i386-pinsn.c /^OP_ONE (dummy)$/ +OP_REG i386-pinsn.c /^OP_REG (code)$/ +OP_SEG i386-pinsn.c /^OP_SEG (dummy)$/ +OP_ST i386-pinsn.c /^OP_ST (ignore)$/ +OP_STi i386-pinsn.c /^OP_STi (ignore)$/ +OP_T i386-pinsn.c /^OP_T (dummy)$/ +OP_indirE i386-pinsn.c /^OP_indirE (bytemode)$/ +OP_rm i386-pinsn.c /^OP_rm (bytemode)$/ +OP_sI i386-pinsn.c /^OP_sI (bytemode)$/ +PATFETCH regex.c /^#define PATFETCH(c) \\$/ +PATFETCH_RAW regex.c /^#define PATFETCH_RAW(c) \\$/ +PATPUSH regex.c /^#define PATPUSH(ch) (*b++ = (char) (ch))$/ +POINTER obstack.c /^POINTER (obstack_base) (obstack)$/ +READ_FILE_HEADERS dbxread.c /^#define READ_FILE_HEADERS(DESC, NAME) \\$/ +READ_STRING_TABLE_SIZE dbxread.c /^#define READ_STRING_TABLE_SIZE(INTO) \\$/ +RELOCATE symmisc.c /^#define RELOCATE(slot) (slot ? (* (char **) &slot / +SET_ELEMENT_P dbxread.c /^#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SET/ +SIGN_EXTEND_CHAR regex.c /^#define SIGN_EXTEND_CHAR(x) (x)$/ +SYNTAX regex.c /^#define SYNTAX(c) re_syntax_table[c]$/ +TEXT_RELOCATE symmisc.c /^#define TEXT_RELOCATE(slot) ((slot) += text_reloc/ +TYPE_OF_SET_ELEMENT dbxread.c /^#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS)$/ +UNRELOCATE symmisc.c /^#define UNRELOCATE(slot) (slot ? (* (char **) &slo/ +_exit standalone.c /^_exit ()$/ +_flsbuf standalone.c /^_flsbuf ()$/ +_initialize_blockframe blockframe.c /^_initialize_blockframe ()$/ +_initialize_breakpoint breakpoint.c /^_initialize_breakpoint ()$/ +_initialize_coff coffread.c /^_initialize_coff ()$/ +_initialize_command command.c /^_initialize_command ()$/ +_initialize_core core.c /^_initialize_core()$/ +_initialize_dbxread dbxread.c /^_initialize_dbxread ()$/ +_initialize_infcmd infcmd.c /^_initialize_infcmd ()$/ +_initialize_inflow inflow.c /^_initialize_inflow ()$/ +_initialize_infrun infrun.c /^_initialize_infrun ()$/ +_initialize_printcmd printcmd.c /^_initialize_printcmd ()$/ +_initialize_source source.c /^_initialize_source ()$/ +_initialize_stack stack.c /^_initialize_stack ()$/ +_initialize_standalone standalone.c /^_initialize_standalone ()$/ +_initialize_symmisc symmisc.c /^_initialize_symmisc ()$/ +_initialize_symtab symtab.c /^_initialize_symtab ()$/ +_initialize_valprint valprint.c /^_initialize_valprint ()$/ +_initialize_values values.c /^_initialize_values ()$/ +_initialize_xgdb xgdb.c /^_initialize_xgdb ()$/ +_obstack_allocated_p obstack.c /^_obstack_allocated_p (h, obj)$/ +_obstack_begin obstack.c /^_obstack_begin (h, size, alignment, chunkfun, free/ +_obstack_free obstack.c /^_obstack_free (h, obj)$/ +_obstack_newchunk obstack.c /^_obstack_newchunk (h, length)$/ +access standalone.c /^access ()$/ +access_value_history values.c /^access_value_history (num)$/ +add_abbrev_cmd command.c /^add_abbrev_cmd (name, class, fun, doc, list)$/ +add_abbrev_prefix_cmd command.c /^add_abbrev_prefix_cmd (name, class, fun, doc, pref/ +add_alias_cmd command.c /^add_alias_cmd (name, oldname, class, abbrev_flag, / +add_bincl_to_list dbxread.c /^add_bincl_to_list (pst, name, instance)$/ +add_cmd command.c /^add_cmd (name, class, fun, doc, list)$/ +add_com main.c /^add_com (name, class, fun, doc)$/ +add_com_alias main.c /^add_com_alias (name, oldname, class, abbrev_flag)$/ +add_file_command dbxread.c /^add_file_command (arg_string)$/ +add_info main.c /^add_info (name, fun, doc)$/ +add_info_alias main.c /^add_info_alias (name, oldname, abbrev_flag)$/ +add_new_header_file dbxread.c /^add_new_header_file (name, instance)$/ +add_old_header_file dbxread.c /^add_old_header_file (name, instance)$/ +add_prefix_cmd command.c /^add_prefix_cmd (name, class, fun, doc, prefixlist,/ +add_symbol_to_list coffread.c /^add_symbol_to_list (symbol, listhead)$/ +add_this_object_header_file dbxread.c /^add_this_object_header_file (i)$/ +addbutton xgdb.c /^addbutton (parent, name, function, closure)$/ +address_info printcmd.c /^address_info (exp)$/ +allocate_repeat_value values.c /^allocate_repeat_value (type, count)$/ +allocate_value values.c /^allocate_value (type)$/ +ambiguous_line_spec source.c /^ambiguous_line_spec (sals)$/ +append_prefix i386-pinsn.c /^append_prefix ()$/ +args_info stack.c /^args_info ()$/ +attach dep.c /^attach (pid)$/ +attach_command infcmd.c /^attach_command (args, from_tty)$/ +attach_program infrun.c /^attach_program (pid)$/ +backtrace_command stack.c /^backtrace_command (count_exp)$/ +backtrace_limit_info stack.c /^backtrace_limit_info (arg, from_tty)$/ +bcmp regex.c /^#define bcmp(s1,s2,n) memcmp((s1),(s2),(n))$/ +bcmp_translate regex.c /^bcmp_translate (s1, s2, len, translate)$/ +bcopy regex.c /^#define bcopy(s,d,n) memcpy((d),(s),(n))$/ +binop_user_defined_p valarith.c /^binop_user_defined_p (op, arg1, arg2)$/ +bit_extract ns32k-pinsn.c /^bit_extract (buffer, offset, count)$/ +block_depth symmisc.c /^block_depth (block)$/ +block_for_pc blockframe.c /^block_for_pc (pc)$/ +block_function symtab.c /^block_function (bl)$/ +block_innermost_frame blockframe.c /^block_innermost_frame (block)$/ +break_command breakpoint.c /^break_command (arg, from_tty)$/ +break_command_1 breakpoint.c /^break_command_1 (arg, tempflag, from_tty)$/ +breakpoint_1 breakpoint.c /^breakpoint_1 (bnum)$/ +breakpoint_auto_delete breakpoint.c /^breakpoint_auto_delete (bnum)$/ +breakpoint_button xgdb.c /^breakpoint_button(w, runflag, call_data)$/ +breakpoint_cond_eval breakpoint.c /^breakpoint_cond_eval (exp)$/ +breakpoint_here_p breakpoint.c /^breakpoint_here_p (pc)$/ +breakpoint_stop_status breakpoint.c /^breakpoint_stop_status (pc, frame_address)$/ +breakpoints_info breakpoint.c /^breakpoints_info (bnum_exp)$/ +bzero regex.c /^#define bzero(s,n) memset((s),0,(n))$/ +call_function valops.c /^call_function (function, nargs, args)$/ +call_ptrace convex-dep.c /^call_ptrace (request, pid, arg3, arg4)$/ +catch_errors main.c /^catch_errors (func, arg, errstring)$/ +cd_command main.c /^cd_command (dir, from_tty)$/ +chdir standalone.c /^chdir ()$/ +check_duplicates breakpoint.c /^check_duplicates (address)$/ +check_field valops.c /^check_field (arg1, name)$/ +ckprefix i386-pinsn.c /^ckprefix ()$/ +clear_breakpoint_commands breakpoint.c /^clear_breakpoint_commands ()$/ +clear_breakpoints breakpoint.c /^clear_breakpoints ()$/ +clear_command breakpoint.c /^clear_command (arg, from_tty)$/ +clear_displays printcmd.c /^clear_displays ()$/ +clear_internalvars values.c /^clear_internalvars ()$/ +clear_momentary_breakpoints breakpoint.c /^clear_momentary_breakpoints ()$/ +clear_proceed_status infrun.c /^clear_proceed_status ()$/ +clear_value_history values.c /^clear_value_history ()$/ +close standalone.c /^close (desc)$/ +close_exec_file core.c /^close_exec_file ()$/ +codestream_fill i386-dep.c /^codestream_fill (peek_flag)$/ +codestream_get i386-dep.c /^#define codestream_get() (codestream_cnt-- == 0 ? / +codestream_peek i386-dep.c /^#define codestream_peek() (codestream_cnt == 0 ? \\/ +codestream_read i386-dep.c /^codestream_read (buf, count)$/ +codestream_seek i386-dep.c /^codestream_seek (place)$/ +codestream_tell i386-dep.c /^#define codestream_tell() (codestream_addr + codes/ +coff_alloc_type coffread.c /^coff_alloc_type (index)$/ +coff_lookup_type coffread.c /^coff_lookup_type (index)$/ +command_loop main.c /^command_loop ()$/ +commands_command breakpoint.c /^commands_command (arg)$/ +compare_misc_functions coffread.c /^compare_misc_functions (fn1, fn2)$/ +compare_psymbols dbxread.c /^compare_psymbols (s1, s2)$/ +compare_symbols coffread.c /^compare_symbols (s1, s2)$/ +complete_symtab coffread.c /^complete_symtab (name, start_addr, size)$/ +concat utils.c /^concat (s1, s2, s3)$/ +condense_addl_misc_bunches dbxread.c /^condense_addl_misc_bunches ()$/ +condense_misc_bunches coffread.c /^condense_misc_bunches ()$/ +condition_command breakpoint.c /^condition_command (arg, from_tty)$/ +cont_command infcmd.c /^cont_command (proc_count_exp, from_tty)$/ +contained_in symtab.c /^contained_in (a, b)$/ +convenience_info values.c /^convenience_info ()$/ +convert_from_68881 m68k-pinsn.c /^convert_from_68881 (from, to)$/ +convert_to_68881 m68k-pinsn.c /^convert_to_68881 (from, to)$/ +copy_name expread.tab.c /^copy_name (token)$/ +copying_info main.c /^copying_info ()$/ +core_file_command convex-dep.c /^core_file_command (filename, from_tty)$/ +create_buttons xgdb.c /^create_buttons (parent)$/ +create_inferior inflow.c /^create_inferior (allargs, env)$/ +create_label xgdb.c /^create_label (name, label)$/ +create_new_frame blockframe.c /^create_new_frame (addr, pc)$/ +create_text_widget xgdb.c /^create_text_widget (parent, filename)$/ +dbit_extract ns32k-pinsn.c /^dbit_extract (buffer, offset, count)$/ +dbx_alloc_type dbxread.c /^dbx_alloc_type (typenums)$/ +dbx_lookup_type dbxread.c /^dbx_lookup_type (typenums)$/ +dcache_alloc remote.c /^dcache_alloc ()$/ +dcache_fetch remote.c /^dcache_fetch (addr)$/ +dcache_flush remote.c /^dcache_flush ()$/ +dcache_hit remote.c /^dcache_hit (addr)$/ +dcache_init remote.c /^dcache_init ()$/ +dcache_poke remote.c /^dcache_poke (addr, data)$/ +dcache_value remote.c /^dcache_value (db, addr)$/ +decode_base_type coffread.c /^decode_base_type (cs, c_type, aux)$/ +decode_format printcmd.c /^decode_format (string_ptr, oformat, osize)$/ +decode_function_type coffread.c /^decode_function_type (cs, c_type, aux)$/ +decode_line_1 symtab.c /^decode_line_1 (argptr, funfirstline, default_symta/ +decode_line_2 symtab.c /^decode_line_2 (argptr, sym_arr, physnames, nelts, / +decode_line_spec symtab.c /^decode_line_spec (string, funfirstline)$/ +decode_line_spec_1 breakpoint.c /^decode_line_spec_1 (string, funfirstline)$/ +decode_type coffread.c /^decode_type (cs, c_type, aux)$/ +define_command main.c /^define_command (comname, from_tty)$/ +define_symbol dbxread.c /^define_symbol (value, string, desc)$/ +delete_breakpoint breakpoint.c /^delete_breakpoint (bpt)$/ +delete_cmd command.c /^delete_cmd (name, list)$/ +delete_command breakpoint.c /^delete_command (arg, from_tty)$/ +delete_current_display printcmd.c /^delete_current_display ()$/ +delete_display printcmd.c /^delete_display (num)$/ +describe_other_breakpoints breakpoint.c /^describe_other_breakpoints (pc)$/ +destructor_name_p valops.c /^destructor_name_p (name, type)$/ +detach dep.c /^detach (signal)$/ +detach_command infcmd.c /^detach_command (args, from_tty)$/ +directories_info source.c /^directories_info ()$/ +directory_command source.c /^directory_command (dirname, from_tty)$/ +disable_breakpoint breakpoint.c /^disable_breakpoint (bpt)$/ +disable_command breakpoint.c /^disable_command (args)$/ +disable_display printcmd.c /^disable_display (args)$/ +discard_cleanups utils.c /^discard_cleanups (old_chain)$/ +discard_misc_bunches coffread.c /^discard_misc_bunches ()$/ +disconnect main.c /^disconnect ()$/ +display_command printcmd.c /^display_command (exp, from_tty)$/ +display_info printcmd.c /^display_info ()$/ +do_breakpoint_commands breakpoint.c /^do_breakpoint_commands ()$/ +do_cleanups utils.c /^do_cleanups (old_chain)$/ +do_command xgdb.c /^do_command(w, command, call_data)$/ +do_displays printcmd.c /^do_displays ()$/ +do_examine printcmd.c /^do_examine (fmt, addr)$/ +do_nothing main.c /^do_nothing ()$/ +do_one_display printcmd.c /^do_one_display (d)$/ +do_restore_insn dep.c /^do_restore_insn (pc)$/ +do_save_insn dep.c /^do_save_insn (size)$/ +document_command main.c /^document_command (comname, from_tty)$/ +dofloat i386-pinsn.c /^dofloat ()$/ +dont_repeat main.c /^dont_repeat ()$/ +double_to_i387 i386-dep.c /^double_to_i387 (from, to)$/ +down_command stack.c /^down_command (count_exp)$/ +dump_me_command main.c /^dump_me_command ()$/ +echo_command main.c /^echo_command (text)$/ +enable_breakpoint breakpoint.c /^enable_breakpoint (bpt)$/ +enable_command breakpoint.c /^enable_command (args)$/ +enable_delete_breakpoint breakpoint.c /^enable_delete_breakpoint (bpt)$/ +enable_delete_command breakpoint.c /^enable_delete_command (args)$/ +enable_display printcmd.c /^enable_display (args)$/ +enable_once_breakpoint breakpoint.c /^enable_once_breakpoint (bpt)$/ +enable_once_command breakpoint.c /^enable_once_command (args)$/ +end_arglist expread.tab.c /^end_arglist ()$/ +end_psymtab dbxread.c /^end_psymtab (pst, include_list, num_includes, capp/ +end_symtab coffread.c /^end_symtab ()$/ +enter_linenos coffread.c /^enter_linenos (file_offset, first_line, last_line)/ +environ_vector environ.c /^environ_vector (e)$/ +environment_info infcmd.c /^environment_info (var)$/ +err stuff.c /^err (msg, a1, a2, a3)$/ +error regex.c /^error (string)$/ +error_no_arg main.c /^error_no_arg (why)$/ +evaluate_expression eval.c /^evaluate_expression (exp)$/ +evaluate_subexp eval.c /^evaluate_subexp (expect_type, exp, pos, noside)$/ +evaluate_subexp_for_address eval.c /^evaluate_subexp_for_address (exp, pos, noside)$/ +evaluate_subexp_for_sizeof eval.c /^evaluate_subexp_for_sizeof (exp, pos)$/ +evaluate_subexp_with_coercion eval.c /^evaluate_subexp_with_coercion (exp, pos, noside)$/ +evaluate_type eval.c /^evaluate_type (exp)$/ +exec_file_command convex-dep.c /^exec_file_command (filename, from_tty)$/ +execle standalone.c /^execle ()$/ +execute_command main.c /^execute_command (p, from_tty)$/ +exit standalone.c /^exit ()$/ +explicit_breakpoint_button xgdb.c /^explicit_breakpoint_button ()$/ +explicit_lookup_type dbxread.c /^explicit_lookup_type (real_filenum, index)$/ +fatal utils.c /^fatal (string, arg)$/ +fault standalone.c /^fault ()$/ +fbit_extract ns32k-pinsn.c /^fbit_extract (buffer, offset, count)$/ +fclose standalone.c /^fclose (desc)$/ +fdopen standalone.c /^fdopen (desc)$/ +fetch_arg m68k-pinsn.c /^fetch_arg (buffer, code, bits)$/ +fetch_inferior_register hp9k320-dep.c /^fetch_inferior_register (regno, regaddr)$/ +fetch_inferior_registers convex-dep.c /^fetch_inferior_registers ()$/ +fflush standalone.c /^fflush (ign)$/ +fgetc standalone.c /^fgetc (desc)$/ +files_info core.c /^files_info ()$/ +fill_in_vptr_fieldno coffread.c /^fill_in_vptr_fieldno (type)$/ +fill_symbuf dbxread.c /^fill_symbuf ()$/ +find_corresponding_bincl_psymtab dbxread.c /^find_corresponding_bincl_psymtab (name, instance)$/ +find_line_common symtab.c /^find_line_common (l, lineno, exact_match)$/ +find_line_pc symtab.c /^find_line_pc (symtab, line)$/ +find_line_pc_range symtab.c /^find_line_pc_range (symtab, thisline, startptr, en/ +find_pc_function blockframe.c /^find_pc_function (pc)$/ +find_pc_line symtab.c /^find_pc_line (pc, notcurrent)$/ +find_pc_line_pc_range symtab.c /^find_pc_line_pc_range (pc, startptr, endptr)$/ +find_pc_misc_function blockframe.c /^find_pc_misc_function (pc)$/ +find_pc_symtab symtab.c /^find_pc_symtab (pc)$/ +find_relative_frame stack.c /^find_relative_frame (frame, level_offset_ptr)$/ +find_saved_register findvar.c /^find_saved_register (frame, regnum)$/ +find_source_lines source.c /^find_source_lines (s, desc)$/ +find_symbol stuff.c /^find_symbol (sym_name, symbol_table, length, strin/ +findarg gld-pinsn.c /^findarg(frame)$/ +findframe gld-pinsn.c /^findframe(thisframe)$/ +finish_block coffread.c /^finish_block (symbol, listhead, old_blocks, start,/ +finish_command infcmd.c /^finish_command (arg, from_tty)$/ +flip_bytes ns32k-pinsn.c /^flip_bytes (ptr, count)$/ +float_info infcmd.c /^float_info (addr_exp)$/ +flush_cached_frames blockframe.c /^flush_cached_frames ()$/ +fopen standalone.c /^fopen (filename, modes)$/ +forward_search_command source.c /^forward_search_command (regex, from_tty)$/ +fprint_addr1 pinsn.c /^fprint_addr1 (stream, name, insn)$/ +fprint_c_ldst pinsn.c /^fprint_c_ldst (stream, insn, op)$/ +fprint_f_ldst pinsn.c /^fprint_f_ldst (stream, insn, op)$/ +fprint_fpop pinsn.c /^fprint_fpop (stream, insn, op, opcode)$/ +fprint_ldst pinsn.c /^fprint_ldst (stream, insn, op)$/ +fprint_mem pinsn.c /^fprint_mem (stream, insn)$/ +fprintf standalone.c /^fprintf (ign, a1, a2, a3, a4, a5, a6, a7, a8, a9)$/ +fputc standalone.c /^fputc (c, ign)$/ +frame_command stack.c /^frame_command (level_exp, from_tty)$/ +frame_info stack.c /^frame_info (addr_exp)$/ +frame_saved_pc dep.c /^frame_saved_pc (frame)$/ +framechain gld-pinsn.c /^framechain(frame)$/ +fread standalone.c /^fread (bufp, numelts, eltsize, stream)$/ +free malloc.c /^free (mem)$/ +free_all_psymtabs symmisc.c /^free_all_psymtabs()$/ +free_all_symtabs symmisc.c /^free_all_symtabs ()$/ +free_all_values values.c /^free_all_values ()$/ +free_bincl_list dbxread.c /^free_bincl_list ()$/ +free_command_lines main.c /^free_command_lines (lptr)$/ +free_current_contents utils.c /^free_current_contents (location)$/ +free_display printcmd.c /^free_display (d)$/ +free_environ environ.c /^free_environ (e)$/ +free_funcalls expread.tab.c /^free_funcalls ()$/ +free_header_files dbxread.c /^free_header_files ()$/ +free_stringtab coffread.c /^free_stringtab ()$/ +free_symtab symmisc.c /^free_symtab (s)$/ +free_symtab_block symmisc.c /^free_symtab_block (b)$/ +fromhex remote.c /^fromhex (a)$/ +fstat standalone.c /^fstat (desc, statbuf)$/ +functions_info symtab.c /^functions_info (regexp)$/ +fwrite standalone.c /^fwrite (buf, numelts, size, stream)$/ +garbage xgdb.c /^garbage (c)$/ +gdb_read_line main.c /^gdb_read_line (prompt, repeat)$/ +get16 i386-pinsn.c /^get16 ()$/ +get32 i386-pinsn.c /^get32 ()$/ +get_breakpoint_commands breakpoint.c /^get_breakpoint_commands ()$/ +get_current_block blockframe.c /^get_current_block ()$/ +get_current_frame blockframe.c /^get_current_frame ()$/ +get_displacement ns32k-pinsn.c /^get_displacement (buffer, aoffsetp)$/ +get_exec_file core.c /^get_exec_file (err)$/ +get_filename_and_charpos source.c /^get_filename_and_charpos (s, line, fullname)$/ +get_frame_block blockframe.c /^get_frame_block (frame)$/ +get_frame_function blockframe.c /^get_frame_function (frame)$/ +get_frame_info blockframe.c /^get_frame_info (frame)$/ +get_frame_pc blockframe.c /^get_frame_pc (frame)$/ +get_frame_saved_regs blockframe.c /^get_frame_saved_regs (frame_info_addr, saved_regs_/ +get_in_environ environ.c /^get_in_environ (e, var)$/ +get_lim_data malloc.c /^get_lim_data ()$/ +get_offset stuff.c /^get_offset (file, sym_name)$/ +get_pc_function_start blockframe.c /^get_pc_function_start (pc)$/ +get_prev_frame blockframe.c /^get_prev_frame (frame)$/ +get_prev_frame_info blockframe.c /^get_prev_frame_info (next_frame)$/ +get_selected_block stack.c /^get_selected_block ()$/ +get_sym_file coffread.c /^get_sym_file ()$/ +getfilename coffread.c /^getfilename (aux_entry)$/ +getpid standalone.c /^getpid ()$/ +getpkt remote.c /^getpkt (buf)$/ +getpool malloc.c /^getpool ()$/ +getrlimit standalone.c /^getrlimit (addr)$/ +getsymname coffread.c /^getsymname (symbol_entry)$/ +getwd standalone.c /^getwd (buf)$/ +handle_command infrun.c /^handle_command (args, from_tty)$/ +hash_symsegs dbxread.c /^hash_symsegs ()$/ +hashname coffread.c /^hashname (name)$/ +have_core_file_p core.c /^have_core_file_p ()$/ +have_inferior_p infcmd.c /^have_inferior_p ()$/ +help_cmd command.c /^help_cmd (command, stream)$/ +help_cmd_list command.c /^help_cmd_list (list, class, prefix, recurse, strea/ +help_command main.c /^help_command (command, from_tty)$/ +help_list command.c /^help_list (list, cmdtype, class, stream)$/ +history_info values.c /^history_info (num_exp)$/ +i386_float_info i386-dep.c /^i386_float_info ()$/ +i386_follow_jump i386-dep.c /^i386_follow_jump ()$/ +i386_frame_find_saved_regs i386-dep.c /^i386_frame_find_saved_regs (fip, fsrp)$/ +i386_get_frame_setup i386-dep.c /^i386_get_frame_setup (pc)$/ +i386_pop_frame i386-dep.c /^i386_pop_frame ()$/ +i386_push_dummy_frame i386-dep.c /^i386_push_dummy_frame ()$/ +i386_register_u_addr i386-dep.c /^i386_register_u_addr (blockend, regnum)$/ +i386_skip_prologue i386-dep.c /^i386_skip_prologue (pc)$/ +i386dis i386-pinsn.c /^i386dis (pc, inbuf, outbuf)$/ +i387_to_double i386-dep.c /^i387_to_double (from, to)$/ +identify_source_line source.c /^identify_source_line (s, line, mid_statement)$/ +ignore_command breakpoint.c /^ignore_command (args, from_tty)$/ +index utils.c /^index (s, c)$/ +inferior_died inflow.c /^inferior_died ()$/ +info_command main.c /^info_command ()$/ +init_bincl_list dbxread.c /^init_bincl_list (number)$/ +init_environ environ.c /^init_environ (e)$/ +init_header_files dbxread.c /^init_header_files ()$/ +init_lineno coffread.c /^init_lineno (chan, offset, count)$/ +init_misc_functions coffread.c /^init_misc_functions ()$/ +init_psymbol_list dbxread.c /^init_psymbol_list (total_symbols)$/ +init_source_path source.c /^init_source_path ()$/ +init_stringtab coffread.c /^init_stringtab (chan, offset)$/ +init_syntax_once regex.c /^init_syntax_once ()$/ +init_type symtab.c /^init_type (code, length, uns, name)$/ +initialize_all_files init.c /^void initialize_all_files () {$/ +initialize_cmd_lists main.c /^initialize_cmd_lists ()$/ +initialize_main main.c /^initialize_main ()$/ +input_from_terminal_p main.c /^input_from_terminal_p ()$/ +insert_breakpoints breakpoint.c /^insert_breakpoints ()$/ +insert_jump regex.c /^insert_jump (op, from, to, current_end)$/ +insert_step_breakpoint infrun.c /^insert_step_breakpoint ()$/ +insque utils.c /^insque (item, after)$/ +int obstack.c /^int (obstack_object_size) (obstack)$/ +internalvar_name values.c /^internalvar_name (var)$/ +ioctl standalone.c /^ioctl (desc, code, arg)$/ +is_nan valprint.c /^is_nan (arg)$/ +isabranch dep.c /^isabranch (addr, target)$/ +jump_command infcmd.c /^jump_command (arg, from_tty)$/ +kill standalone.c /^kill ()$/ +kill_command inflow.c /^kill_command ()$/ +kill_inferior convex-dep.c /^kill_inferior ()$/ +kill_inferior_fast convex-dep.c /^kill_inferior_fast ()$/ +length_of_subexp expread.tab.c /^length_of_subexp (expr, endpos)$/ +line_info source.c /^line_info (arg, from_tty)$/ +list_command source.c /^list_command (arg, from_tty)$/ +list_symbols symtab.c /^list_symbols (regexp, class)$/ +locals_info stack.c /^locals_info ()$/ +locate_var_value findvar.c /^locate_var_value (var, frame)$/ +lookup_basetype_type symtab.c /^lookup_basetype_type (type, offset, via_virtual, v/ +lookup_block_symbol symtab.c /^lookup_block_symbol (block, name, namespace)$/ +lookup_cmd command.c /^lookup_cmd (line, list, cmdtype, allow_unknown)$/ +lookup_enum symtab.c /^lookup_enum (name, block)$/ +lookup_function_type symtab.c /^lookup_function_type (type)$/ +lookup_internalvar values.c /^lookup_internalvar (name)$/ +lookup_member_type symtab.c /^lookup_member_type (type, domain)$/ +lookup_misc_func symtab.c /^lookup_misc_func (name)$/ +lookup_partial_symbol symtab.c /^lookup_partial_symbol (pst, name, global, namespac/ +lookup_partial_symtab symtab.c /^lookup_partial_symtab (name)$/ +lookup_pointer_type symtab.c /^lookup_pointer_type (type)$/ +lookup_reference_type symtab.c /^lookup_reference_type (type)$/ +lookup_struct symtab.c /^lookup_struct (name, block)$/ +lookup_symbol symtab.c /^lookup_symbol (name, block, namespace, is_a_field_/ +lookup_symtab symtab.c /^lookup_symtab (name)$/ +lookup_typename symtab.c /^lookup_typename (name, block, noerr)$/ +lookup_union symtab.c /^lookup_union (name, block)$/ +lookup_unsigned_typename symtab.c /^lookup_unsigned_typename (name)$/ +lseek standalone.c /^lseek (desc, pos)$/ +make_blockvector coffread.c /^make_blockvector ()$/ +make_cleanup utils.c /^make_cleanup (function, arg)$/ +make_environ environ.c /^make_environ ()$/ +malloc malloc.c /^malloc (n) \/* get a block *\/$/ +malloc_init malloc.c /^malloc_init (start, warnfun)$/ +malloc_mem_free malloc.c /^malloc_mem_free ()$/ +malloc_mem_used malloc.c /^malloc_mem_used ()$/ +malloc_stats malloc.c /^malloc_stats (size)$/ +malloc_usable_size malloc.c /^malloc_usable_size (mem)$/ +malloc_warning standalone.c /^malloc_warning (str)$/ +map_breakpoint_numbers breakpoint.c /^map_breakpoint_numbers (args, function)$/ +mark_breakpoints_out breakpoint.c /^mark_breakpoints_out ()$/ +max environ.c /^#define max(a, b) ((a) > (b) ? (a) : (b))$/ +memalign malloc.c /^memalign (alignment, size)$/ +methods_info symtab.c /^methods_info (regexp)$/ +min environ.c /^#define min(a, b) ((a) < (b) ? (a) : (b))$/ +modify_field values.c /^modify_field (addr, fieldval, bitpos, bitsize)$/ +morecore malloc.c /^morecore (nu) \/* ask system for more memory *\/$/ +myread core.c /^myread (desc, addr, len)$/ +new_object_header_files dbxread.c /^new_object_header_files ()$/ +new_tty inflow.c /^new_tty (ttyname)$/ +next_command infcmd.c /^next_command (count_string)$/ +next_symbol_text dbxread.c /^next_symbol_text ()$/ +nexti_command infcmd.c /^nexti_command (count_string)$/ +normal_stop infrun.c /^normal_stop ()$/ +ns32k_get_enter_addr ns32k-pinsn.c /^ns32k_get_enter_addr (pc)$/ +ns32k_localcount ns32k-pinsn.c /^ns32k_localcount (enter_pc)$/ +oappend i386-pinsn.c /^oappend (s)$/ +obconcat dbxread.c /^obconcat (s1, s2, s3)$/ +obsavestring dbxread.c /^obsavestring (ptr, size)$/ +obstack_free obstack.c /^obstack_free (h, obj)$/ +open standalone.c /^open (filename, modes)$/ +openp source.c /^openp (path, try_cwd_first, string, mode, prot, fi/ +output_command printcmd.c /^output_command (exp)$/ +output_source_filename symtab.c /^output_source_filename (name, next)$/ +parse_and_eval eval.c /^parse_and_eval (exp)$/ +parse_and_eval_address eval.c /^parse_and_eval_address (exp)$/ +parse_and_eval_address_1 eval.c /^parse_and_eval_address_1 (expptr)$/ +parse_c_1 expread.tab.c /^parse_c_1 (stringptr, block, comma)$/ +parse_c_expression expread.tab.c /^parse_c_expression (string)$/ +parse_escape utils.c /^parse_escape (string_ptr)$/ +parse_frame_specification stack.c /^parse_frame_specification (frame_exp)$/ +parse_number expread.tab.c /^parse_number (olen)$/ +parse_to_comma_and_eval eval.c /^parse_to_comma_and_eval (expp)$/ +patch_opaque_types coffread.c /^patch_opaque_types ()$/ +patch_type coffread.c /^patch_type (type, real_type)$/ +perror_with_name utils.c /^perror_with_name (string)$/ +pop_subfile dbxread.c /^pop_subfile ()$/ +prefixify_expression expread.tab.c /^prefixify_expression (expr)$/ +prefixify_subexp expread.tab.c /^prefixify_subexp (inexpr, outexpr, inend, outbeg)$/ +print_387_control_word i386-dep.c /^print_387_control_word (control)$/ +print_387_status i386-dep.c /^print_387_status (status, ep)$/ +print_387_status_word i386-dep.c /^print_387_status_word (status)$/ +print_address printcmd.c /^print_address (addr, stream)$/ +print_base m68k-pinsn.c /^print_base (regno, disp, stream)$/ +print_block_frame_locals stack.c /^print_block_frame_locals (b, frame, stream)$/ +print_buf regex.c /^print_buf (bufp)$/ +print_button xgdb.c /^print_button(w, starflag, call_data)$/ +print_command printcmd.c /^print_command (exp)$/ +print_expression expprint.c /^print_expression (exp, stream)$/ +print_formatted printcmd.c /^print_formatted (val, format, size)$/ +print_frame_arg_vars stack.c /^print_frame_arg_vars (frame, stream)$/ +print_frame_args printcmd.c /^print_frame_args (func, fi, num, stream)$/ +print_frame_info stack.c /^print_frame_info (fi, level, source, args)$/ +print_frame_local_vars stack.c /^print_frame_local_vars (frame, stream)$/ +print_frame_nameless_args printcmd.c /^print_frame_nameless_args (argsaddr, start, end, s/ +print_gdb_version main.c /^print_gdb_version ()$/ +print_indexed m68k-pinsn.c /^print_indexed (basereg, p, addr, stream)$/ +print_insn gld-pinsn.c /^print_insn (memaddr, stream)$/ +print_insn_arg m68k-pinsn.c /^print_insn_arg (d, buffer, p, addr, stream)$/ +print_prompt main.c /^print_prompt ()$/ +print_scalar_formatted printcmd.c /^print_scalar_formatted (valaddr, type, format, siz/ +print_sel_frame stack.c /^print_sel_frame (just_source)$/ +print_selected_frame stack.c /^print_selected_frame ()$/ +print_source_lines source.c /^print_source_lines (s, line, stopline, noerror)$/ +print_spaces utils.c /^print_spaces (n, file)$/ +print_stack_frame stack.c /^print_stack_frame (frame, level, source)$/ +print_subexp expprint.c /^print_subexp (exp, pos, stream, prec)$/ +print_symbol symmisc.c /^print_symbol (symbol, depth, outfile)$/ +print_symtabs symmisc.c /^print_symtabs (filename)$/ +print_sys_errmsg utils.c /^print_sys_errmsg (string, errcode)$/ +print_variable_value printcmd.c /^print_variable_value (var, frame, stream)$/ +printchar regex.c /^printchar (c)$/ +printf standalone.c /^printf (a1, a2, a3, a4, a5, a6, a7, a8, a9)$/ +printf_command printcmd.c /^printf_command (arg)$/ +proceed infrun.c /^proceed (addr, signal, step)$/ +process_coff_symbol coffread.c /^process_coff_symbol (cs, aux)$/ +process_one_symbol dbxread.c /^process_one_symbol (type, desc, value, name)$/ +process_symbol_for_psymtab dbxread.c /^process_symbol_for_psymtab (name)$/ +program_info infcmd.c /^program_info ()$/ +psymtab_to_symtab coffread.c /^psymtab_to_symtab ()$/ +ptrace standalone.c /^ptrace ()$/ +ptype_command printcmd.c /^ptype_command (typename)$/ +push_bytes valops.c /^push_bytes (sp, buffer, len)$/ +push_subfile dbxread.c /^push_subfile ()$/ +push_word valops.c /^push_word (sp, buffer)$/ +putop i386-pinsn.c /^putop (template)$/ +putpkt remote.c /^putpkt (buf)$/ +pwd_command main.c /^pwd_command (arg, from_tty)$/ +query utils.c /^query (ctlstr, arg1, arg2)$/ +quit utils.c /^quit ()$/ +quit_command main.c /^quit_command ()$/ +re_comp regex.c /^re_comp (s)$/ +re_compile_fastmap regex.c /^re_compile_fastmap (bufp)$/ +re_compile_pattern regex.c /^re_compile_pattern (pattern, size, bufp)$/ +re_exec regex.c /^re_exec (s)$/ +re_match regex.c /^re_match (pbufp, string, size, pos, regs)$/ +re_match_2 regex.c /^re_match_2 (pbufp, string1, size1, string2, size2,/ +re_search regex.c /^re_search (pbufp, string, size, startpos, range, r/ +re_search_2 regex.c /^re_search_2 (pbufp, string1, size1, string2, size2/ +re_set_syntax regex.c /^re_set_syntax (syntax)$/ +read_addl_syms dbxread.c /^read_addl_syms (desc, stringtab, nlistlen, text_ad/ +read_aout_hdr coffread.c /^read_aout_hdr (chan, aout_hdr, size)$/ +read_args dbxread.c /^read_args (pp, end)$/ +read_array_type dbxread.c /^read_array_type (pp, type)$/ +read_coff_symtab coffread.c /^read_coff_symtab (desc, nsyms)$/ +read_command_lines main.c /^read_command_lines ()$/ +read_dbx_symtab dbxread.c /^read_dbx_symtab (desc, stringtab, nlistlen, inclin/ +read_enum_type coffread.c /^read_enum_type (index, length, lastsym)$/ +read_file_hdr coffread.c /^read_file_hdr (chan, file_hdr)$/ +read_inferior_memory convex-dep.c /^read_inferior_memory (memaddr, myaddr, len)$/ +read_inferior_register standalone.c /^read_inferior_register ()$/ +read_memory core.c /^read_memory (memaddr, myaddr, len)$/ +read_memory_integer infcmd.c /^read_memory_integer (memaddr, len)$/ +read_number dbxread.c /^read_number (pp, end)$/ +read_ofile_symtab dbxread.c /^read_ofile_symtab (desc, stringtab, sym_offset,$/ +read_one_sym coffread.c /^read_one_sym (cs, sym, aux)$/ +read_pc infcmd.c /^read_pc ()$/ +read_range_type dbxread.c /^read_range_type (pp, typenums)$/ +read_register findvar.c /^read_register (regno)$/ +read_register_bytes findvar.c /^read_register_bytes (regbyte, myaddr, len)$/ +read_relative_register_raw_bytes findvar.c /^read_relative_register_raw_bytes (regnum, myaddr)$/ +read_section_hdr coffread.c /^read_section_hdr (chan, section_name, section_hdr,/ +read_struct_type coffread.c /^read_struct_type (index, length, lastsym)$/ +read_symsegs symmisc.c /^read_symsegs (desc, name)$/ +read_type dbxread.c /^read_type (pp)$/ +read_type_number dbxread.c /^read_type_number (pp, typenums)$/ +read_var_value findvar.c /^read_var_value (var, frame)$/ +readchar remote.c /^readchar ()$/ +realloc malloc.c /^realloc (mem, n)$/ +really_free_pendings dbxread.c /^really_free_pendings ()$/ +record_latest_value values.c /^record_latest_value (val)$/ +record_line coffread.c /^record_line (line, pc)$/ +record_misc_function coffread.c /^record_misc_function (name, address)$/ +record_selected_frame stack.c /^record_selected_frame (frameaddrp, levelp)$/ +redisplay_button xgdb.c /^redisplay_button()$/ +register_addr core.c /^register_addr (regno, blockend)$/ +registers_info infcmd.c /^registers_info (addr_exp)$/ +release_value values.c /^release_value (val)$/ +relocate_block symmisc.c /^relocate_block (bp)$/ +relocate_blockvector symmisc.c /^relocate_blockvector (blp)$/ +relocate_source symmisc.c /^relocate_source (sp)$/ +relocate_sourcevector symmisc.c /^relocate_sourcevector (svp)$/ +relocate_symbol symmisc.c /^relocate_symbol (sp)$/ +relocate_symtab symmisc.c /^relocate_symtab (root)$/ +relocate_type symmisc.c /^relocate_type (tp)$/ +relocate_typevector symmisc.c /^relocate_typevector (tv)$/ +remote_fetch_registers remote.c /^remote_fetch_registers (regs)$/ +remote_fetch_word remote.c /^remote_fetch_word (addr)$/ +remote_open remote.c /^remote_open (name, from_tty)$/ +remote_read_bytes remote.c /^remote_read_bytes (memaddr, myaddr, len)$/ +remote_resume remote.c /^remote_resume (step, signal)$/ +remote_send remote.c /^remote_send (buf)$/ +remote_store_registers remote.c /^remote_store_registers (regs)$/ +remote_store_word remote.c /^remote_store_word (addr, word)$/ +remote_wait remote.c /^remote_wait (status)$/ +remote_write_bytes remote.c /^remote_write_bytes (memaddr, myaddr, len)$/ +remove_breakpoints breakpoint.c /^remove_breakpoints ()$/ +remove_step_breakpoint infrun.c /^remove_step_breakpoint ()$/ +remque utils.c /^remque (item)$/ +reopen_exec_file core.c /^reopen_exec_file ()$/ +request_quit utils.c /^request_quit ()$/ +restore_cleanups utils.c /^restore_cleanups (chain)$/ +restore_gdb standalone.c /^restore_gdb ()$/ +restore_inferior_status infrun.c /^restore_inferior_status (inf_status)$/ +resume convex-dep.c /^resume (step, signal)$/ +return_command stack.c /^return_command (retval_exp, from_tty)$/ +return_to_top_level main.c /^return_to_top_level ()$/ +reverse_search_command source.c /^reverse_search_command (regex, from_tty)$/ +rindex utils.c /^rindex (s, c)$/ +run_command infcmd.c /^run_command (args, from_tty)$/ +run_stack_dummy infcmd.c /^run_stack_dummy (addr, buffer)$/ +save_cleanups utils.c /^save_cleanups ()$/ +save_frame_pointer standalone.c /^save_frame_pointer (val)$/ +save_inferior_status infrun.c /^save_inferior_status (inf_status, restore_stack_in/ +save_registers standalone.c /^save_registers (firstreg)$/ +savestring utils.c /^savestring (ptr, size)$/ +sbrk standalone.c /^sbrk (amount)$/ +scan_file_globals dbxread.c /^scan_file_globals (desc, stringtab, offset, numsym/ +select_frame stack.c /^select_frame (frame, level)$/ +select_source_symtab source.c /^select_source_symtab (s)$/ +set_args_command infcmd.c /^set_args_command (args)$/ +set_backtrace_limit_command stack.c /^set_backtrace_limit_command (count_exp, from_tty)$/ +set_breakpoint breakpoint.c /^set_breakpoint (s, line, tempflag)$/ +set_breakpoint_commands breakpoint.c /^set_breakpoint_commands (cmds)$/ +set_command printcmd.c /^set_command (exp)$/ +set_current_frame blockframe.c /^set_current_frame (frame)$/ +set_default_breakpoint breakpoint.c /^set_default_breakpoint (valid, addr, symtab, line)/ +set_environment_command infcmd.c /^set_environment_command (arg)$/ +set_ignore_count breakpoint.c /^set_ignore_count (bptnum, count, from_tty)$/ +set_in_environ environ.c /^set_in_environ (e, var, value)$/ +set_internalvar values.c /^set_internalvar (var, val)$/ +set_internalvar_component values.c /^set_internalvar_component (var, offset, bitpos, bi/ +set_maximum_command valprint.c /^set_maximum_command (arg)$/ +set_momentary_breakpoint breakpoint.c /^set_momentary_breakpoint (sal, frame)$/ +set_next_address printcmd.c /^set_next_address (addr)$/ +set_prompt_command main.c /^set_prompt_command (text)$/ +set_raw_breakpoint breakpoint.c /^set_raw_breakpoint (sal)$/ +set_return_value values.c /^set_return_value (val)$/ +setpgrp standalone.c /^setpgrp ()$/ +setup_arbitrary_frame dep.c /^setup_arbitrary_frame (frame, stack)$/ +shell_escape command.c /^shell_escape (arg, from_tty)$/ +sign_extend ns32k-pinsn.c /^sign_extend (value, bits)$/ +signal standalone.c /^int (* signal ()) ()$/ +signal_command infcmd.c /^signal_command (signum_exp, from_tty)$/ +signals_info infrun.c /^signals_info (signum_exp)$/ +sigsetmask standalone.c /^sigsetmask ()$/ +single_step dep.c /^single_step (signal)$/ +sizeof i386-dep.c /^static unsigned char codestream_buf[sizeof (int)];/ +skip_prologue dep.c /^skip_prologue (pc)$/ +smash_to_function_type symtab.c /^smash_to_function_type (type, to_type)$/ +smash_to_member_type symtab.c /^smash_to_member_type (type, domain, to_type)$/ +smash_to_pointer_type symtab.c /^smash_to_pointer_type (type, to_type)$/ +smash_to_reference_type symtab.c /^smash_to_reference_type (type, to_type)$/ +sort_block_syms symtab.c /^sort_block_syms (b)$/ +sort_syms coffread.c /^sort_syms ()$/ +sort_symtab_syms dbxread.c /^sort_symtab_syms (s)$/ +source_charpos_line source.c /^source_charpos_line (s, chr)$/ +source_cleanup main.c /^source_cleanup (stream)$/ +source_command main.c /^source_command (file)$/ +source_line_charpos source.c /^source_line_charpos (s, line)$/ +sources_info symtab.c /^sources_info ()$/ +specify_exec_file_hook core.c /^specify_exec_file_hook (hook)$/ +start kdb-start.c /^start ()$/ +start_arglist expread.tab.c /^start_arglist ()$/ +start_inferior infrun.c /^start_inferior ()$/ +start_of_data malloc.c /^#define start_of_data() &etext$/ +start_psymtab dbxread.c /^start_psymtab (filename, textlow, ldsymoff, global/ +start_remote infrun.c /^start_remote ()$/ +start_subfile dbxread.c /^start_subfile (name)$/ +start_symtab coffread.c /^start_symtab ()$/ +step_1 infcmd.c /^step_1 (skip_subroutines, single_inst, count_strin/ +step_command infcmd.c /^step_command (count_string)$/ +stepi_command infcmd.c /^stepi_command (count_string)$/ +stop_sig main.c /^stop_sig ()$/ +store_inferior_register hp9k320-dep.c /^store_inferior_register (regno, regaddr)$/ +store_inferior_register_1 hp9k320-dep.c /^store_inferior_register_1 (regno, regaddr, value)$/ +store_inferior_registers convex-dep.c /^store_inferior_registers (regno)$/ +store_jump regex.c /^store_jump (from, opcode, to)$/ +supply_register findvar.c /^supply_register (regno, val)$/ +symbol_file_command coffread.c /^symbol_file_command (name)$/ +sys_sbrk malloc.c /^sys_sbrk (incr)$/ +tbreak_command breakpoint.c /^tbreak_command (arg, from_tty)$/ +term_status_command inflow.c /^term_status_command ()$/ +terminal_inferior inflow.c /^terminal_inferior ()$/ +terminal_init_inferior inflow.c /^terminal_init_inferior ()$/ +terminal_ours inflow.c /^terminal_ours ()$/ +terminal_ours_1 inflow.c /^terminal_ours_1 (output_only)$/ +terminal_ours_for_output inflow.c /^terminal_ours_for_output ()$/ +tohex remote.c /^tohex (nib)$/ +try_writing_regs_command inflow.c /^try_writing_regs_command ()$/ +tty_command infcmd.c /^tty_command (file)$/ +type_print valprint.c /^type_print (type, varstring, stream, show)$/ +type_print_1 valprint.c /^type_print_1 (type, varstring, stream, show, level/ +type_print_base valprint.c /^type_print_base (type, stream, show, level)$/ +type_print_derivation_info valprint.c /^type_print_derivation_info (stream, type)$/ +type_print_method_args valprint.c /^type_print_method_args (args, prefix, varstring, s/ +type_print_varspec_prefix valprint.c /^type_print_varspec_prefix (type, stream, show, pas/ +type_print_varspec_suffix valprint.c /^type_print_varspec_suffix (type, stream, show, pas/ +typecmp valops.c /^int typecmp(t1, t2)$/ +types_info symtab.c /^types_info (regexp)$/ +ulimit standalone.c /^ulimit ()$/ +undisplay_command printcmd.c /^undisplay_command (args)$/ +unop_user_defined_p valarith.c /^int unop_user_defined_p (op, arg1)$/ +unpack_double values.c /^unpack_double (type, valaddr)$/ +unpack_field_as_long values.c /^unpack_field_as_long (type, valaddr, fieldno)$/ +unpack_long values.c /^unpack_long (type, valaddr)$/ +unrecord_misc_function coffread.c /^unrecord_misc_function ()$/ +unset_environment_command infcmd.c /^unset_environment_command (var)$/ +unset_in_environ environ.c /^unset_in_environ (e, var)$/ +until_break_command breakpoint.c /^until_break_command(arg, from_tty)$/ +until_command infcmd.c /^until_command (arg, from_tty)$/ +until_next_command infcmd.c /^until_next_command (arg, from_tty)$/ +up_command stack.c /^up_command (count_exp)$/ +using_struct_return values.c /^using_struct_return (function, funcaddr, value_typ/ +val_print valprint.c /^val_print (type, valaddr, address, stream, format,/ +validate_comname main.c /^validate_comname (comname)$/ +validate_files core.c /^validate_files ()$/ +validate_format printcmd.c /^validate_format (fmt, cmdname)$/ +valloc malloc.c /^valloc (size)$/ +value_add valarith.c /^value_add (arg1, arg2)$/ +value_addr valops.c /^value_addr (arg1)$/ +value_arg_coerce valops.c /^value_arg_coerce (arg)$/ +value_arg_push valops.c /^value_arg_push (sp, arg)$/ +value_as_double values.c /^value_as_double (val)$/ +value_as_long values.c /^value_as_long (val)$/ +value_assign valops.c /^value_assign (toval, fromval)$/ +value_at valops.c /^value_at (type, addr)$/ +value_being_returned values.c /^value_being_returned (valtype, retbuf, struct_retu/ +value_binop valarith.c /^value_binop (arg1, arg2, op)$/ +value_cast valops.c /^value_cast (type, arg2)$/ +value_coerce_array valops.c /^value_coerce_array (arg1)$/ +value_copy values.c /^value_copy (arg)$/ +value_equal valarith.c /^value_equal (arg1, arg2)$/ +value_field values.c /^value_field (arg1, fieldno)$/ +value_fn_field values.c /^value_fn_field (arg1, fieldno, subfieldno)$/ +value_from_double values.c /^value_from_double (type, num)$/ +value_from_long values.c /^value_from_long (type, num)$/ +value_from_register findvar.c /^value_from_register (type, regnum, frame)$/ +value_ind valops.c /^value_ind (arg1)$/ +value_less valarith.c /^value_less (arg1, arg2)$/ +value_lognot valarith.c /^value_lognot (arg1)$/ +value_neg valarith.c /^value_neg (arg1)$/ +value_of_internalvar values.c /^value_of_internalvar (var)$/ +value_of_register findvar.c /^value_of_register (regnum)$/ +value_of_this valops.c /^value_of_this (complain)$/ +value_of_variable valops.c /^value_of_variable (var)$/ +value_print valprint.c /^value_print (val, stream, format)$/ +value_push valops.c /^value_push (sp, arg)$/ +value_repeat valops.c /^value_repeat (arg1, count)$/ +value_static_field values.c /^value_static_field (type, fieldname, fieldno)$/ +value_string valops.c /^value_string (ptr, len)$/ +value_struct_elt valops.c /^value_struct_elt (arg1, args, name, err)$/ +value_struct_elt_for_address valops.c /^value_struct_elt_for_address (domain, intype, name/ +value_sub valarith.c /^value_sub (arg1, arg2)$/ +value_subscript valarith.c /^value_subscript (array, idx)$/ +value_virtual_fn_field values.c /^value_virtual_fn_field (arg1, f, j, type)$/ +value_x_binop valarith.c /^value_x_binop (arg1, arg2, op, otherop)$/ +value_x_unop valarith.c /^value_x_unop (arg1, op)$/ +value_zerop valarith.c /^value_zerop (arg1)$/ +variables_info symtab.c /^variables_info (regexp)$/ +version_info main.c /^version_info ()$/ +vfork standalone.c /^vfork ()$/ +vlimit standalone.c /^vlimit ()$/ +void obstack.c /^void (obstack_grow) (obstack, pointer, length)$/ +wait standalone.c /^wait (w)$/ +wait_for_inferior infrun.c /^wait_for_inferior ()$/ +warranty_info main.c /^warranty_info ()$/ +whatis_command printcmd.c /^whatis_command (exp)$/ +write_exp_elt expread.tab.c /^write_exp_elt (expelt)$/ +write_exp_elt_dblcst expread.tab.c /^write_exp_elt_dblcst (expelt)$/ +write_exp_elt_intern expread.tab.c /^write_exp_elt_intern (expelt)$/ +write_exp_elt_longcst expread.tab.c /^write_exp_elt_longcst (expelt)$/ +write_exp_elt_opcode expread.tab.c /^write_exp_elt_opcode (expelt)$/ +write_exp_elt_sym expread.tab.c /^write_exp_elt_sym (expelt)$/ +write_exp_elt_type expread.tab.c /^write_exp_elt_type (expelt)$/ +write_exp_string expread.tab.c /^write_exp_string (str)$/ +write_inferior_memory convex-dep.c /^write_inferior_memory (memaddr, myaddr, len)$/ +write_inferior_register standalone.c /^write_inferior_register ()$/ +write_memory core.c /^write_memory (memaddr, myaddr, len)$/ +write_pc infcmd.c /^write_pc (val)$/ +write_register findvar.c /^write_register (regno, val)$/ +write_register_bytes findvar.c /^write_register_bytes (regbyte, myaddr, len)$/ +writing_pc infrun.c /^writing_pc (val)$/ +x_command printcmd.c /^x_command (exp, from_tty)$/ +xfer_core_file core.c /^xfer_core_file (memaddr, myaddr, len)$/ +xgdb_create_window xgdb.c /^xgdb_create_window ()$/ +xgdb_dispatch xgdb.c /^xgdb_dispatch (fp)$/ +xgdb_display_exec_file xgdb.c /^xgdb_display_exec_file (filename)$/ +xgdb_display_source xgdb.c /^xgdb_display_source ()$/ +xgdb_window_hook xgdb.c /^xgdb_window_hook (infile, prompt)$/ +xmalloc utils.c /^xmalloc (size)$/ +xrealloc utils.c /^xrealloc (ptr, size)$/ +xxmalloc dbxread.c /^xxmalloc (n)$/ +yyerror expread.tab.c /^yyerror ()$/ +yylex expread.tab.c /^yylex ()$/ +yyparse expread.tab.c /^yyparse() {$/ diff --git a/gdb/test.c b/gdb/test.c deleted file mode 100644 index ff92691..0000000 --- a/gdb/test.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -main () -{ - Rational r = Rational (PI); -} diff --git a/gdb/test2.c b/gdb/test2.c deleted file mode 100644 index e6964f0..0000000 --- a/gdb/test2.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include -#include - -main () -{ - struct user u; - printf ("&u.u_ar0 - &u = %d, 0%o\n", (int) &u.u_ar0 - (int) &u, - (int) &u.u_ar0 - (int) &u); - printf ("sizeof (struct pcb) = %d, 0%o\n", - sizeof (struct pcb), sizeof (struct pcb)); -} diff --git a/gdb/test4.c b/gdb/test4.c deleted file mode 100644 index e465534..0000000 --- a/gdb/test4.c +++ /dev/null @@ -1,40 +0,0 @@ -main() -{ - int i,j,k; - - i = 100; - j = 101; - k = foo(0,1,2,3,4,5,6,7,8); -} - -int f3 (x) -{ - return x; -} - -int f2 (x) -{ - return f3 (x+1); -} - -int f1 (x) -{ - return f2 (x+1); -} - -foo(a,b,c,d,e,f,g,h,i) - int a,b,c,d,e,f,g,h,i; -{ - int r; - r = a + b + c + d + e + f + g + h + i; - if (f1 (11)) - return r; - else - return 0; -} - -bar(ind) - int ind; -{ - printf("this is a test\n"); -} diff --git a/gdb/testbpt.c b/gdb/testbpt.c deleted file mode 100644 index baa4e51..0000000 --- a/gdb/testbpt.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Run this program straight. Then set a breakpoint in `dump', - run it again, and continue the program. Diff the outputs - and you will see what the supplied debugger does for a breakpoint. */ - -int dump (); -int after_dump (); - -main () -{ - printf ("main = 0x%x\ndump = 0x%x\nend = 0x%x\n", main, dump, after_dump); - - dump (main, after_dump); -} - -int dump (p, q) - int *p; - int *q; -{ - int cnt = 0; - printf ("dump: 0x%x-0x%x\n", p, q); - - while (p < q) - { - if ((cnt++ & 3) == 0) - printf ("\n0x%08x: ", p); - printf ("0x%08x ", *p++); - } - printf ("\n"); -} - -after_dump () -{ -} diff --git a/gdb/testfun.c b/gdb/testfun.c deleted file mode 100644 index eeeebd7..0000000 --- a/gdb/testfun.c +++ /dev/null @@ -1,22 +0,0 @@ -main () -{ - register double a = 1.5; - foo (a); -} - -foo (x) -{ - printf ("%f\n", x); -} - -do_add (x, y) -{ - return x + y; -} - -double -do_float_add (x, y, z) - register double x, y, z; -{ - return x + y + z; -} diff --git a/gdb/testrec.c b/gdb/testrec.c deleted file mode 100644 index 797c08b..0000000 --- a/gdb/testrec.c +++ /dev/null @@ -1,12 +0,0 @@ -main () -{ - foo (4); -} - -foo (x) - int x; -{ - if (x > 0) - foo (x - 1); -} - diff --git a/gdb/testreg.c b/gdb/testreg.c deleted file mode 100644 index f19ec05..0000000 --- a/gdb/testreg.c +++ /dev/null @@ -1,22 +0,0 @@ -main (argc, argv) - int argc; - char **argv; -{ - register int d1 = 34; - register int d2 = 35; - register int d3 = 36; - register int d4 = 37; - register char *a1 = "1"; - register char *a2 = "2"; - register char *a3 = "3"; - register char *a4 = "4"; - register char *a5 = "5"; - int x[4]; - foo (); - foo (0x222, abort (), 0x444); -} - -foo () -{ - return 22; -} diff --git a/gdb/testregs.c b/gdb/testregs.c deleted file mode 100644 index 7a5acb3..0000000 --- a/gdb/testregs.c +++ /dev/null @@ -1,20 +0,0 @@ -typedef struct aa { int b;} *hack; - -static int -foo (argc) -{ - register int a = 0x1234; - register int b = 0x56788765; - register char *x = (char *) 0xabababab; - register char *y = (char *) 0xcdcdcdcd; - register double d = 1.582; - int loser; - printf ("Address of loser is 0x%x.\n", &loser); - printf ("Address of argc is 0x%x.\n", &argc); - abort (); -} - -main (argc) -{ - foo (argc); -} diff --git a/gdb/teststruct.c b/gdb/teststruct.c deleted file mode 100644 index 75f1642..0000000 --- a/gdb/teststruct.c +++ /dev/null @@ -1,111 +0,0 @@ -struct small -{ - int i; -}; - -struct med -{ - struct small s1, s2; -}; - -struct large -{ - struct med m1, m2; -}; - -struct xlarge -{ - struct large l1, l2; -}; - -struct small ret_small (); -struct med ret_med (); -struct large ret_large (); -struct xlarge ret_xlarge (); - -void print_small (); -void print_med (); -void print_large (); -void print_xlarge (); - -main () -{ - struct small s; - struct med m; - struct large l; - struct xlarge x; - - s = ret_small (1); - m = ret_med (s,s); - l = ret_large (m, m); - x = ret_xlarge (l, l); - - print_small (s); - print_med (m); - print_large (l); - print_xlarge (x); -} - -struct small ret_small (i) - int i; -{ - struct small s; - s.i = i; - return s; -} - -struct med ret_med (s1, s2) - struct small s1, s2; -{ - struct med m; - m.s1 = s1; - m.s2 = s2; - return m; -} - -struct large ret_large (m1, m2) - struct med m1, m2; -{ - struct large l; - l.m1 = m1; - l.m2 = m2; - return l; -} - -struct xlarge ret_xlarge (l1, l2) - struct large l1, l2; -{ - struct xlarge x; - x.l1 = l1; - x.l2 = l2; - return x; -} - -void print_small (s) - struct small s; -{ - printf ("small: s.i = %d\n", s.i); -} - -void print_med (m) - struct med m; -{ - printf ("med: m.s1.i = %d; m.s2.i = %d\n", m.s1.i, m.s2.i); -} - -void print_large (l) - struct large l; -{ - printf ("large: l.m1.s1.i = %d; l.m1.s2.i = %d; l.m2.s1.i = %d; l.m2.s2.i = %d\n", - l.m1.s1.i, l.m1.s2.i, l.m2.s1.i, l.m2.s2.i); -} - -void print_xlarge (x) - struct xlarge x; -{ - printf ("xlarge: x.l1: "); - print_large (x.l1); - printf ("xlarge: x.l2: "); - print_large (x.l2); -} - diff --git a/gdb/umax-dep.c b/gdb/umax-dep.c new file mode 100644 index 0000000..09d6a34 --- /dev/null +++ b/gdb/umax-dep.c @@ -0,0 +1,579 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 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! +*/ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#define PTRACE_ATTACH PT_ATTACH +#define PTRACE_DETACH PT_FREEPROC + +#include +#include + +extern int errno; +extern int attach_flag; + +/* 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"); + } +} + +#ifdef ATTACH_DETACH + +/* Start debugging the process whose number is PID. */ + +attach (pid) + int pid; +{ + errno = 0; + ptrace (PTRACE_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 (PTRACE_DETACH, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +void +fetch_inferior_registers () +{ + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + unsigned int offset = 0; + + 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]; + + unsigned int offset = 0; + + 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); + } + } +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes 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. */ + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#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 */ + +/* 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 +#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; + +#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) + { + 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 ptrace_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 + u.pt_dsize; + stack_start = stack_end - u.pt_ssize; + data_offset = sizeof u; + stack_offset = data_offset + u.pt_dsize; + reg_offset = 0; + + bcopy (&u.pt_aouthdr, &core_aouthdr, sizeof (AOUTHDR)); + printf ("Core file is from \"%s\".\n", u.pt_comm); + if (u.pt_signal > 0) + printf ("Program terminated with signal %d, %s.\n", + u.pt_signal, + u.pt_signal < NSIG + ? sys_siglist[u.pt_signal] + : "(undocumented)"); + + /* 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) + { + 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) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 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; + + 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); +} diff --git a/gdb/utils.c b/gdb/utils.c index 2a0b943..2db7359 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -21,6 +21,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include #include #include +#include #include "defs.h" #include "param.h" #ifdef HAVE_TERMIO @@ -97,6 +98,24 @@ discard_cleanups (old_chain) } } +/* 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 @@ -201,6 +220,7 @@ quit () #else /* not HAVE_TERMIO */ ioctl (fileno (stdout), TIOCFLUSH, 0); #endif /* not HAVE_TERMIO */ + #ifdef TIOCGPGRP error ("Quit"); #else @@ -214,6 +234,12 @@ void request_quit () { quit_flag = 1; + +#ifdef USG + /* Restore the signal handler */ + signal(SIGINT, request_quit); +#endif + if (immediate_quit) quit (); } @@ -435,3 +461,196 @@ printchar (ch, stream, quoter) fputc (c, 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); +} + +/* 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; +} + + +/* + * There is too much variation in Sys V signal numbers and names, so + * we must initialize them at runtime. If C provided a way to initialize + * an array based on subscript and value, this would not be necessary. + */ +static char undoc[] = "(undocumented)"; + +char *sys_siglist[NSIG]; + +_initialize_utils() +{ + int i; + + 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/gdb/valarith.c b/gdb/valarith.c index adf0044..772e590 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -19,13 +19,11 @@ anyone else from sharing it farther. Help stamp out software hoarding! */ #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "value.h" #include "expression.h" -START_FILE value value_x_binop (); @@ -332,7 +330,7 @@ value_binop (arg1, arg2, op) } else { - long v1, v2, v; + LONGEST v1, v2, v; v1 = value_as_long (arg1); v2 = value_as_long (arg2); @@ -398,8 +396,8 @@ value_binop (arg1, arg2, op) error ("Invalid binary operation on numbers."); } - val = allocate_value (builtin_type_long); - *(long *) VALUE_CONTENTS (val) = v; + val = allocate_value (BUILTIN_TYPE_LONGEST); + *(LONGEST *) VALUE_CONTENTS (val) = v; } return val; @@ -532,9 +530,3 @@ value_lognot (arg1) return value_from_long (VALUE_TYPE (arg1), ~ value_as_long (arg1)); } -static -initialize () -{ -} - -END_FILE diff --git a/gdb/valops.c b/gdb/valops.c index f88069f..06091c4 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -17,14 +17,13 @@ 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! */ - +#include "stdio.h" #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "value.h" - -START_FILE +#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, @@ -60,7 +59,9 @@ value_cast (type, arg2) return arg2; } else if (VALUE_LVAL (arg2) == lval_memory) - return value_at (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2)); + { + return value_at (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2)); + } else error ("Invalid cast."); } @@ -73,8 +74,17 @@ value_at (type, addr) 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 ()) + 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); + } - read_memory (addr, VALUE_CONTENTS (val), TYPE_LENGTH (type)); VALUE_LVAL (val) = lval_memory; VALUE_ADDRESS (val) = addr; @@ -94,6 +104,8 @@ value_assign (toval, fromval) 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) @@ -103,7 +115,7 @@ value_assign (toval, fromval) 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))) { @@ -136,7 +148,7 @@ value_assign (toval, fromval) int val; read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), &val, sizeof val); - modify_field (&val, value_as_long (fromval), + 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); @@ -156,7 +168,7 @@ value_assign (toval, fromval) read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), &val, sizeof val); - modify_field (&val, value_as_long (fromval), + 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); @@ -169,6 +181,76 @@ value_assign (toval, fromval) 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."); } @@ -238,7 +320,7 @@ value_coerce_array (arg1) /* Get the type of the result. */ type = lookup_pointer_type (type); val = value_from_long (builtin_type_long, - VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)); + (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1))); VALUE_TYPE (val) = type; return val; } @@ -265,7 +347,7 @@ value_addr (arg1) /* Get the type of the result. */ type = lookup_pointer_type (VALUE_TYPE (arg1)); val = value_from_long (builtin_type_long, - VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)); + (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1))); VALUE_TYPE (val) = type; return val; } @@ -277,7 +359,7 @@ value_ind (arg1) value arg1; { /* Must do this before COERCE_ARRAY, otherwise an infinite loop - will result. */ + 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)); @@ -289,7 +371,7 @@ value_ind (arg1) /* Allow * on an integer so we can cast it to whatever we want. */ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT) - return value_at (builtin_type_long, + return value_at (builtin_type_long, (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)), @@ -415,15 +497,22 @@ call_function (function, nargs, args) 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; + + save_inferior_status (&inf_status, 1); + old_chain = make_cleanup (restore_inferior_status, &inf_status); PUSH_DUMMY_FRAME; old_sp = sp = read_register (SP_REGNUM); -#if 1 INNER_THAN 2 /* Stack grows down */ +#if 1 INNER_THAN 2 /* Stack grows down */ sp -= sizeof dummy; start_sp = sp; -#else /* Stack grows up */ +#else /* Stack grows up */ start_sp = sp; sp += sizeof dummy; #endif @@ -471,44 +560,98 @@ call_function (function, nargs, args) 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); -#ifdef sun4 FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, value_type); -#else - FIX_CALL_DUMMY (dummy1, funaddr, nargs); -#endif } write_memory (start_sp, dummy1, sizeof dummy); +#ifdef convex + /* 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; + start_sp = text_end - sizeof dummy; + write_memory (start_sp, dummy1, sizeof dummy); + } +#else /* !convex */ #ifdef STACK_ALIGN - /* If stack grows down, we must leave a hole at the top. */ + /* 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 (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 +#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; + sp -= CALL_DUMMY_STACK_ADJUST; #else - sp += CALL_DUMMY_STACK_ADJUST; -#endif + sp += CALL_DUMMY_STACK_ADJUST; #endif +#endif /* CALL_DUMMY_STACK_ADJUST */ +#endif /* !convex */ + + /* 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. */ @@ -520,7 +663,9 @@ call_function (function, nargs, args) after storing the contents of all regs into retbuf. */ run_stack_dummy (start_sp + CALL_DUMMY_START_OFFSET, retbuf); - return value_being_returned (value_type, retbuf); + do_cleanups (old_chain); + + return value_being_returned (value_type, retbuf, struct_return); } } @@ -566,7 +711,7 @@ value_string (ptr, len) /* Find the address of malloc in the inferior. */ - sym = lookup_symbol ("malloc", 0, VAR_NAMESPACE); + sym = lookup_symbol ("malloc", 0, VAR_NAMESPACE, 0); if (sym != 0) { if (SYMBOL_CLASS (sym) != LOC_BLOCK) @@ -581,16 +726,16 @@ value_string (ptr, len) break; if (i < misc_function_count) val = value_from_long (builtin_type_long, - misc_function_vector[i].address); + (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, len + 1); + 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 (value_as_long (val), copy, len + 1); + write_memory ((CORE_ADDR) value_as_long (val), copy, len + 1); VALUE_TYPE (val) = lookup_pointer_type (builtin_type_char); return val; } @@ -634,14 +779,13 @@ value_struct_elt (arg1, args, name, err) error ("not implemented: member type in value_struct_elt"); if (TYPE_CODE (t) != TYPE_CODE_STRUCT - && - TYPE_CODE (t) != TYPE_CODE_UNION) + && TYPE_CODE (t) != TYPE_CODE_UNION) error ("Attempt to extract a component of a value that is not a %s.", err); baseclass = t; if (!args) - { + { /* if there are no arguments ...do this... */ /* Try as a variable first, because if we succeed, there @@ -656,7 +800,7 @@ value_struct_elt (arg1, args, name, err) break; } } - + if (i >= 0) return TYPE_FIELD_STATIC (t, i) ? value_static_field (t, name, i) : value_field (arg1, i); @@ -669,7 +813,7 @@ value_struct_elt (arg1, args, name, err) } /* C++: If it was not found as a data field, then try to - return it as a pointer to a method. */ + return it as a pointer to a method. */ t = baseclass; VALUE_TYPE (arg1) = t; /* side effect! */ @@ -702,7 +846,8 @@ value_struct_elt (arg1, args, name, err) if (!args[1]) { /* destructors are a special case. */ - return (value)value_fn_field (arg1, 0, TYPE_FN_FIELDLIST_LENGTH (t, 0)); + return (value)value_fn_field (arg1, 0, + TYPE_FN_FIELDLIST_LENGTH (t, 0)); } else { @@ -740,7 +885,7 @@ value_struct_elt (arg1, args, name, err) if (TYPE_N_BASECLASSES (t) == 0) break; - + t = TYPE_BASECLASS (t, 1); VALUE_TYPE (arg1) = t; /* side effect! */ } @@ -764,7 +909,7 @@ value_struct_elt (arg1, args, name, err) break; } } - + if (i >= 0) return TYPE_FIELD_STATIC (t, i) ? value_static_field (t, name, i) : value_field (arg1, i); @@ -808,7 +953,7 @@ destructor_name_p (name, type) /* 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; @@ -851,7 +996,6 @@ check_field (arg1, name) return 1; } } - if (TYPE_N_BASECLASSES (t) == 0) break; @@ -860,7 +1004,7 @@ check_field (arg1, name) } /* C++: If it was not found as a data field, then try to - return it as a pointer to a method. */ + return it as a pointer to a method. */ t = baseclass; VALUE_TYPE (arg1) = t; /* side effect! */ @@ -889,7 +1033,7 @@ check_field (arg1, name) 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; @@ -917,8 +1061,10 @@ value_struct_elt_for_address (domain, intype, name) if (TYPE_FIELD_PACKED (t, i)) error ("pointers to bitfield members not allowed"); - v = value_from_long (builtin_type_int, TYPE_FIELD_BITPOS (t, i) >> 3); - VALUE_TYPE (v) = lookup_pointer_type (lookup_member_type (TYPE_FIELD_TYPE (t, i), baseclass)); + 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; } } @@ -930,7 +1076,7 @@ value_struct_elt_for_address (domain, intype, name) } /* C++: If it was not found as a data field, then try to - return it as a pointer to a method. */ + return it as a pointer to a method. */ t = baseclass; /* Destructors are a special case. */ @@ -968,12 +1114,12 @@ value_struct_elt_for_address (domain, intype, name) if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) { v = value_from_long (builtin_type_long, - TYPE_FN_FIELD_VOFFSET (f, j)); + (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j)); } else { struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j), - 0, VAR_NAMESPACE); + 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)); @@ -1000,7 +1146,7 @@ int typecmp(t1, t2) value t2[]; { int i; - + if (t1[0]->code == TYPE_CODE_VOID) return 0; if (!t1[1]) return 0; for (i = 1; t1[i] && t1[i]->code != TYPE_CODE_VOID; i++) @@ -1016,10 +1162,6 @@ int typecmp(t1, t2) return t2[i] ? i+1 : 0; } -#ifndef FRAME -#include "frame.h" -#endif - /* 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. */ @@ -1061,9 +1203,3 @@ value_of_this (complain) return read_var_value (sym, selected_frame); } - -static -initialize () -{ } - -END_FILE diff --git a/gdb/valprint.c b/gdb/valprint.c index 1aae021..b55aa87 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -20,7 +20,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "value.h" @@ -35,7 +34,6 @@ static void type_print_varspec_prefix (); static void type_print_base (); static void type_print_method_args (); -START_FILE char **unsigned_type_table; char **signed_type_table; @@ -46,6 +44,7 @@ char **float_type_table; If the object printed is a string pointer, returns the number of string bytes printed. */ +int value_print (val, stream, format) value val; FILE *stream; @@ -83,21 +82,22 @@ value_print (val, stream, format) if (i) fprintf (stream, ", "); val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i, - VALUE_ADDRESS (val) + typelen * i, stream, format, 1); + VALUE_ADDRESS (val) + typelen * i, + stream, format, 1); } if (i < n) fprintf (stream, "..."); } fputc ('}', stream); + return n * typelen; } else { - /* A simple (nonrepeated) value */ /* If it is a pointer, indicate what it points to. - C++: print type also if it is a reference. + Print type also if it is a reference. - If it is a member pointer, we will take care + 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) @@ -119,8 +119,8 @@ value_print (val, stream, 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. */ + if DEREF_REF is nonzero, then dereference references, + otherwise just print them like pointers. */ int val_print (type, valaddr, address, stream, format, deref_ref) @@ -135,7 +135,7 @@ val_print (type, valaddr, address, stream, format, deref_ref) int len, n_baseclasses; struct type *elttype; int eltlen; - int val; + LONGEST val; unsigned char c; QUIT; @@ -217,7 +217,7 @@ val_print (type, valaddr, address, stream, format, deref_ref) } else { - struct symbol *sym = find_pc_function (val); + struct symbol *sym = find_pc_function ((CORE_ADDR) val); if (sym == 0) error ("invalid pointer to member function"); len = TYPE_NFN_FIELDS (domain); @@ -302,31 +302,63 @@ val_print (type, valaddr, address, stream, format, deref_ref) fprintf (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); - if (TYPE_LENGTH (elttype) == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT + i = 0; /* Number of characters printed. */ + if (TYPE_LENGTH (elttype) == 1 + && TYPE_CODE (elttype) == TYPE_CODE_INT && format == 0 - && unpack_long (type, valaddr) != 0) + /* Convex needs this typecast to a long */ + && (long) unpack_long (type, valaddr) != 0 + && print_max) { fputc (' ', stream); - fputc ('"', stream); - for (i = 0; i < print_max; i++) + + /* Get first character. */ + if (read_memory ( (CORE_ADDR) unpack_long (type, valaddr), + &c, 1)) { - QUIT; - read_memory (unpack_long (type, valaddr) + i, &c, 1); - if (c == 0) - break; - printchar (c, stream, '"'); + /* First address out of bounds. */ + fprintf (stream, "
", + (* (int *) valaddr)); + break; + } + else + { + /* A real string. */ + int out_of_bounds = 0; + + fputc ('"', stream); + while (c) + { + QUIT; + printchar (c, stream, '"'); + if (++i >= print_max) + break; + if (read_memory ((CORE_ADDR) unpack_long (type, valaddr) + + i, &c, 1)) + { + /* This address was out of bounds. */ + fprintf (stream, + "\"***
", + (* (int *) valaddr) + i); + out_of_bounds = 1; + break; + } + } + if (!out_of_bounds) + { + fputc ('"', stream); + if (i == print_max) + fprintf (stream, "..."); + } } - fputc ('"', stream); - if (i == print_max) - fprintf (stream, "..."); fflush (stream); - /* Return number of characters printed, plus one for the - terminating null if we have "reached the end". */ - return i + (i != print_max); } + /* 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; @@ -335,18 +367,19 @@ val_print (type, valaddr, address, stream, format, deref_ref) break; case TYPE_CODE_REF: - fprintf (stream, "0x%x", * (int *) valaddr); + fprintf (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); - fprintf (stream, " = "); - val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), - VALUE_ADDRESS (val), stream, format, deref_ref); - } - else - fprintf (stream, " = ???"); + { + 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); + } + else + fprintf (stream, "???"); + } break; case TYPE_CODE_STRUCT: @@ -378,12 +411,15 @@ val_print (type, valaddr, address, stream, format, deref_ref) else if (TYPE_FIELD_PACKED (type, i)) { val = unpack_field_as_long (type, valaddr, i); - val_print (TYPE_FIELD_TYPE (type, i), &val, 0, stream, format, deref_ref); + val_print (TYPE_FIELD_TYPE (type, i), &val, 0, + stream, format, deref_ref); } else - val_print (TYPE_FIELD_TYPE (type, i), - valaddr + TYPE_FIELD_BITPOS (type, i) / 8, - 0, stream, format, deref_ref); + { + val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / 8, + 0, stream, format, deref_ref); + } } fprintf (stream, "}"); break; @@ -395,11 +431,11 @@ val_print (type, valaddr, address, stream, format, deref_ref) break; } len = TYPE_NFIELDS (type); - val = unpack_long (builtin_type_int, valaddr); + val = (long) unpack_long (builtin_type_int, valaddr); for (i = 0; i < len; i++) { QUIT; - if (val == TYPE_FIELD_VALUE (type, i)) + if (val == TYPE_FIELD_BITPOS (type, i)) break; } if (i < len) @@ -432,7 +468,8 @@ val_print (type, valaddr, address, stream, format, deref_ref) if (TYPE_LENGTH (type) == 1) { fprintf (stream, " '"); - printchar (unpack_long (type, valaddr), stream, '\''); + printchar ((unsigned char) unpack_long (type, valaddr), + stream, '\''); fputc ('\'', stream); } break; @@ -443,14 +480,25 @@ val_print (type, valaddr, address, stream, format, deref_ref) print_scalar_formatted (valaddr, type, format, 0, stream); break; } + /* FIXME: When printing NaNs or invalid floats, print them + in raw hex in addition to the message. */ #ifdef IEEE_FLOAT - if (is_nan (unpack_double (type, valaddr))) + if (is_nan ((void *)valaddr, TYPE_LENGTH(type))) { - fprintf (stream, "Nan"); + fprintf (stream, "NaN"); break; } #endif - fprintf (stream, "%g", unpack_double (type, valaddr)); + { + double doub; + int inv; + + doub = unpack_double (type, valaddr, &inv); + if (inv) + fprintf (stream, "Invalid float value"); + else + fprintf (stream, TYPE_LENGTH (type) <= 4? "%.6g": "%.16g", doub); + } break; case TYPE_CODE_VOID: @@ -465,28 +513,38 @@ val_print (type, valaddr, address, stream, format, deref_ref) #ifdef IEEE_FLOAT -union ieee { - int i[2]; - double d; -}; - /* Nonzero if ARG (a double) is a NAN. */ int -is_nan (arg) - union ieee arg; +is_nan (fp, len) + void *fp; + int len; { int lowhalf, highhalf; - union { int i; char c; } test; + union ieee { + long i[2]; /* ASSUMED 32 BITS */ + float f; /* ASSUMED 32 BITS */ + double d; /* ASSUMED 64 BITS */ + } *arg; + + arg = (union ieee *)fp; + + /* + * Single precision float. + */ + if (len == sizeof(long)) { + highhalf = arg->i[0]; + return ((((highhalf >> 23) & 0xFF) == 0xFF) + && 0 != (highhalf & 0x7FFFFF)); + } /* Separate the high and low words of the double. Distinguish big and little-endian machines. */ - test.i = 1; - if (test.c != 1) - /* Big-endian machine */ - lowhalf = arg.i[1], highhalf = arg.i[0]; - else - lowhalf = arg.i[0], highhalf = arg.i[1]; +#ifdef WORDS_BIG_ENDIAN + lowhalf = arg->i[1], highhalf = arg->i[0]; +#else + lowhalf = arg->i[0], highhalf = arg->i[1]; +#endif /* Nan: exponent is the maximum possible, and fraction is nonzero. */ return (((highhalf>>20) & 0x7ff) == 0x7ff @@ -502,6 +560,7 @@ is_nan (arg) 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; @@ -513,6 +572,7 @@ type_print (type, varstring, stream, show) /* LEVEL is the depth to indent lines by. */ +void type_print_1 (type, varstring, stream, show, level) struct type *type; char *varstring; @@ -569,7 +629,7 @@ type_print_method_args (args, prefix, varstring, stream) } fprintf (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. @@ -665,11 +725,15 @@ type_print_varspec_prefix (type, stream, show, passed_a_ptr) break; case TYPE_CODE_FUNC: - case TYPE_CODE_ARRAY: - type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); if (passed_a_ptr) fputc ('(', stream); break; + + case TYPE_CODE_ARRAY: + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); } } @@ -695,11 +759,11 @@ type_print_varspec_suffix (type, stream, show, passed_a_ptr) switch (TYPE_CODE (type)) { case TYPE_CODE_ARRAY: - type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0); - if (passed_a_ptr) - fprintf (stream, ")"); + type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); fprintf (stream, "["); - if (TYPE_LENGTH (type) >= 0) + if (TYPE_LENGTH (type) >= 0 + && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) fprintf (stream, "%d", TYPE_LENGTH (type) / TYPE_LENGTH (TYPE_TARGET_TYPE (type))); fprintf (stream, "]"); @@ -717,7 +781,8 @@ type_print_varspec_suffix (type, stream, show, passed_a_ptr) break; case TYPE_CODE_FUNC: - type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0); + type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); if (passed_a_ptr) fprintf (stream, ")"); fprintf (stream, "()"); @@ -793,12 +858,14 @@ type_print_base (type, stream, show, level) int i; type_print_derivation_info (stream, type); - + fprintf (stream, "{"); len = TYPE_NFIELDS (type); if (len) fprintf (stream, "\n"); else fprintf (stream, "\n"); + /* If there is a base class for this type, + do not print the field that it occupies. */ for (i = TYPE_N_BASECLASSES (type); i < len; i++) { QUIT; @@ -808,28 +875,6 @@ type_print_base (type, stream, show, level) continue; print_spaces (level + 4, stream); - - /* If this is a bit-field and there is a gap before it, - print a nameless field to account for the gap. */ - - if (TYPE_FIELD_PACKED (type, i)) - { - int gap = (TYPE_FIELD_BITPOS (type, i) - - (i > 0 - ? (TYPE_FIELD_BITPOS (type, i - 1) - + (TYPE_FIELD_PACKED (type, i - 1) - ? TYPE_FIELD_BITSIZE (type, i - 1) - : TYPE_LENGTH (TYPE_FIELD_TYPE (type, i - 1)) * 8)) - : 0)); - if (gap != 0) - { - fprintf (stream, "int : %d;\n", gap); - print_spaces (level + 4, stream); - } - } - - /* Print the declaration of this field. */ - if (TYPE_FIELD_STATIC (type, i)) { fprintf (stream, "static "); @@ -837,12 +882,11 @@ type_print_base (type, stream, show, level) type_print_1 (TYPE_FIELD_TYPE (type, i), TYPE_FIELD_NAME (type, i), stream, show - 1, level + 4); - - /* Print the field width. */ - - if (TYPE_FIELD_PACKED (type, i)) - fprintf (stream, " : %d", TYPE_FIELD_BITSIZE (type, i)); - + if (!TYPE_FIELD_STATIC (type, i) + && TYPE_FIELD_PACKED (type, i)) + { + /* ??? don't know what to put here ??? */; + } fprintf (stream, ";\n"); } @@ -901,10 +945,10 @@ type_print_base (type, stream, show, level) QUIT; if (i) fprintf (stream, ", "); fprintf (stream, "%s", TYPE_FIELD_NAME (type, i)); - if (lastval != TYPE_FIELD_VALUE (type, i)) + if (lastval != TYPE_FIELD_BITPOS (type, i)) { - fprintf (stream, " : %d", TYPE_FIELD_VALUE (type, i)); - lastval = TYPE_FIELD_VALUE (type, i); + fprintf (stream, " : %d", TYPE_FIELD_BITPOS (type, i)); + lastval = TYPE_FIELD_BITPOS (type, i); } lastval++; } @@ -946,29 +990,38 @@ set_maximum_command (arg) print_max = atoi (arg); } -static -initialize () +extern struct cmd_list_element *setlist; + +void +_initialize_valprint () { - add_com ("set-maximum", class_vars, set_maximum_command, - "Set NUMBER as limit on string chars or array elements to print."); + add_cmd ("array-max", class_vars, set_maximum_command, + "Set NUMBER as limit on string chars or array elements to print.", + &setlist); print_max = 200; unsigned_type_table - = (char **) xmalloc ((1 + sizeof (unsigned long)) * sizeof (char *)); - bzero (unsigned_type_table, (1 + sizeof (unsigned long))); + = (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 (long)) * sizeof (char *)); - bzero (signed_type_table, (1 + sizeof (long))); + = (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 *)); @@ -977,4 +1030,3 @@ initialize () float_type_table[sizeof (double)] = "double"; } -END_FILE diff --git a/gdb/value.h b/gdb/value.h index dcaf245..3a14661 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -18,25 +18,73 @@ 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! */ -enum lval_type { not_lval, lval_memory, lval_register, lval_internalvar, - lval_internalvar_component }; +/* + * 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; - int offset; + /* 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]; }; @@ -47,6 +95,8 @@ typedef struct value *value; #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 @@ -61,7 +111,7 @@ typedef struct value *value; References are dereferenced. */ #define COERCE_ARRAY(arg) \ -{ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_REF) \ +{ 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) \ @@ -73,7 +123,7 @@ typedef struct value *value; /* If ARG is an enum, convert it to an integer. */ #define COERCE_ENUM(arg) \ -{ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_REF) \ +{ 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); \ @@ -89,14 +139,15 @@ struct internalvar value value; }; -long value_as_long (); +LONGEST value_as_long (); double value_as_double (); -long unpack_long (); +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 (); @@ -122,6 +173,7 @@ value value_subscript (); value call_function (); value value_being_returned (); +int using_struct_return (); value evaluate_expression (); value evaluate_type (); @@ -143,3 +195,8 @@ 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 (); diff --git a/gdb/values.c b/gdb/values.c index 0d5fc27..c81991e 100644 --- a/gdb/values.c +++ b/gdb/values.c @@ -1,3 +1,4 @@ + /* Low level packing and unpacking of values for GDB. Copyright (C) 1986, 1987 Free Software Foundation, Inc. @@ -20,7 +21,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "value.h" @@ -45,7 +45,6 @@ static struct value_history_chunk *value_history_chain; static int value_history_count; /* Abs number of last entry stored */ -START_FILE /* List of all value objects currently allocated (except for those released by calls to release_value) @@ -67,6 +66,7 @@ allocate_value (type) 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; @@ -92,6 +92,7 @@ allocate_repeat_value (type, count) 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; @@ -178,11 +179,15 @@ int record_latest_value (val) value val; { - register int i; + int i; + double foo; - /* Get error now if about to store an invalid float. */ - if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT) - value_as_double (val); + /* 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. */ @@ -341,7 +346,7 @@ set_internalvar_component (var, offset, bitpos, bitsize, newval) { register char *addr = VALUE_CONTENTS (var->value) + offset; if (bitsize) - modify_field (addr, value_as_long (newval), + modify_field (addr, (int) value_as_long (newval), bitpos, bitsize); else bcopy (VALUE_CONTENTS (newval), addr, @@ -408,7 +413,7 @@ use \"set\" as in \"set $foo = 5\" to define them.\n"); floating values to long. Does not deallocate the value. */ -long +LONGEST value_as_long (val) register value val; { @@ -419,7 +424,13 @@ double value_as_double (val) register value val; { - return unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (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 @@ -432,7 +443,7 @@ value_as_double (val) to member which reaches here is considered to be equivalent to an INT (or some size). After all, it is only an offset. */ -long +LONGEST unpack_long (type, valaddr) struct type *type; char *valaddr; @@ -478,6 +489,11 @@ unpack_long (type, 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) @@ -486,24 +502,33 @@ unpack_long (type, valaddr) return (CORE_ADDR) * (char **) valaddr; } else if (code == TYPE_CODE_MEMBER) - error ("not impelmented: member types in unpack_long"); + 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) +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)) - error ("Invalid floating value found in program."); + if (INVALID_FLOAT (valaddr, len)) { + *invp = 1; + return 1.234567891011121314; + } if (len == sizeof (float)) return * (float *) valaddr; @@ -530,6 +555,11 @@ unpack_double (type, 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) { @@ -544,6 +574,11 @@ unpack_double (type, 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."); @@ -553,7 +588,7 @@ unpack_double (type, valaddr) 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. */ + For C++, must also be able to return values from static fields */ value value_field (arg1, fieldno) @@ -570,7 +605,7 @@ value_field (arg1, fieldno) if (TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno)) { v = value_from_long (type, - unpack_field_as_long (VALUE_TYPE (arg1), + (LONGEST) unpack_field_as_long (VALUE_TYPE (arg1), VALUE_CONTENTS (arg1), fieldno)); VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) % 8; @@ -602,7 +637,7 @@ value_fn_field (arg1, fieldno, subfieldno) struct symbol *sym; sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, subfieldno), - 0, VAR_NAMESPACE); + 0, VAR_NAMESPACE, 0); if (! sym) error ("Internal error: could not find physical method named %s", TYPE_FN_FIELD_PHYSNAME (f, subfieldno)); @@ -631,7 +666,8 @@ value_virtual_fn_field (arg1, f, j, type) 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, TYPE_FN_FIELD_VOFFSET (f, j)); + 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 @@ -688,7 +724,7 @@ value_static_field (type, fieldname, fieldno) else error ("field `%s' is not static"); } - t = TYPE_BASECLASS (t, 1); + t = TYPE_BASECLASSES (t) ? TYPE_BASECLASS (t, 1) : 0; } t = type; @@ -707,7 +743,7 @@ value_static_field (type, fieldname, fieldno) error ("use `info method' command to print value of method \"%s\"", fieldname); } } - t = TYPE_BASECLASS (t, 1); + t = TYPE_BASECLASSES (t) ? TYPE_BASECLASS (t, 1) : 0; } error("there is no field named %s", fieldname); } @@ -715,7 +751,7 @@ value_static_field (type, fieldname, fieldno) found: sym = lookup_symbol (TYPE_FIELD_STATIC_PHYSNAME (type, fieldno), - 0, VAR_NAMESPACE); + 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); @@ -732,37 +768,34 @@ unpack_field_as_long (type, valaddr, fieldno) long val; int bitpos = TYPE_FIELD_BITPOS (type, fieldno); int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); - union { int i; char c; } test; bcopy (valaddr + bitpos / 8, &val, sizeof val); - /* Extracting bits depends on endianness of the machine. */ - test.i = 1; - if (test.c == 1) - /* Little-endian. */ - val = val >> (bitpos % 8); - else - val = val >> (sizeof val * 8 - bitpos % 8 - bitsize); + /* Extracting bits depends on endianness of the target 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; - union { int i; char c; } test; bcopy (addr, &oword, sizeof oword); - /* Shifting for bit field depends on endianness of the machine. */ - test.c = 1; - if (test.i != 1) - /* not little-endian: assume big-endian. */ - bitpos = sizeof oword * 8 - bitpos - bitsize; + /* Shifting for bit field depends on endianness of the target machine. */ +#ifdef BITS_BIG_ENDIAN + bitpos = sizeof oword * 8 - bitpos - bitsize; +#endif oword &= ~(((1 << bitsize) - 1) << bitpos); oword |= fieldval << bitpos; @@ -774,7 +807,7 @@ modify_field (addr, fieldval, bitpos, bitsize) value value_from_long (type, num) struct type *type; - register long num; + register LONGEST num; { register value val = allocate_value (type); register enum type_code code = TYPE_CODE (type); @@ -790,6 +823,10 @@ value_from_long (type, num) * (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."); } @@ -831,17 +868,21 @@ value_from_double (type, num) 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. */ + 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) +value_being_returned (valtype, retbuf, struct_return) register struct type *valtype; char retbuf[REGISTER_BYTES]; + int struct_return; { register value val; - if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT - || TYPE_CODE (valtype) == TYPE_CODE_UNION) + if (struct_return) return value_at (valtype, EXTRACT_STRUCT_VALUE_ADDRESS (retbuf)); val = allocate_value (valtype); @@ -850,6 +891,35 @@ value_being_returned (valtype, retbuf) 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_ENUM || + 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. */ @@ -861,7 +931,7 @@ set_return_value (val) register enum type_code code = TYPE_CODE (VALUE_TYPE (val)); char regbuf[REGISTER_BYTES]; double dbuf; - long lbuf; + LONGEST lbuf; if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) @@ -880,8 +950,8 @@ set_return_value (val) } } -static -initialize () +void +_initialize_values () { add_info ("convenience", convenience_info, "Debugger convenience (\"$foo\") variables.\n\ @@ -895,4 +965,3 @@ A few convenience variables are given values automatically GDB:\n\ "Elements of value history (around item number IDX, or last ten)."); } -END_FILE diff --git a/gdb/version.c b/gdb/version.c index d4bbebe..a83b002 100644 --- a/gdb/version.c +++ b/gdb/version.c @@ -1,3 +1,3 @@ /* Define the current version number of GDB. */ -char *version = "2.8.1 (GNU C++ 1.31.0 compatible)"; +char *version = "3.1"; diff --git a/gdb/xgdb.c b/gdb/xgdb.c index d90132c..2431699 100644 --- a/gdb/xgdb.c +++ b/gdb/xgdb.c @@ -21,7 +21,6 @@ anyone else from sharing it farther. Help stamp out software hoarding! /* Original version was contributed by Derek Beatty, 30 June 87. */ #include "defs.h" -#include "initialize.h" #include "param.h" #include "symtab.h" #include "frame.h" @@ -30,12 +29,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! #include #include #include -#include +#include #include #include #include +/*#define XtNfunction "function"*/ + /* Cursor used in GDB window. */ #define gdb_width 16 @@ -60,27 +61,23 @@ static short gdb_mask_bits[] = { /* The X display on which the window appears. */ -static Display *screen_display; +Display *screen_display; + +#if 0 +/* The graphics context. */ +GC default_gc; +#endif /* Windows manipulated by this package. */ +static Window icon_window; static Widget main_widget; static Widget containing_widget; -static Widget title_widget; static Widget source_name_widget; static Widget source_text_widget; static Widget exec_name_widget; static Widget button_box_widget; -#ifdef VTFD -/* Interaction Window */ - -static Widget interactive_widget; -XtTextSource PseudoDiskSourceCreate(); -XtTextSource TSource; -static int vtfd[2], vifd[2]; -#endif - /* Source text display. */ static struct symtab *source_window_symtab = 0; @@ -88,43 +85,29 @@ static struct symtab *source_window_symtab = 0; /* Forward declarations */ static Widget create_text_widget (); - -START_FILE -/* Return number of text lines displayed in text widget W. */ - -int /* was XtTextPosition */ -XtTextLines (w) - Widget w; -{ - TextWidget ctx = (TextWidget)w; - - return ctx->text.lt.lines; -} - /* Display an appropriate piece of source code in the source window. */ xgdb_display_source () { char *filename; - Arg args[1]; - Arg labelArgs[1]; + static Arg labelArgs[1]; int linenumbers_changed = 0; - int must_scroll = 0; - int height = XtTextLines (source_text_widget); + static int new = 1; struct symtab_and_line get_selected_frame_sal (); struct symtab_and_line sal; - struct frame_info fi; + struct frame_info *fi; - /* Do nothing if called before we are initialized */ + /* Do nothing if called before we are initialized or when there + is nothing to show. */ - if (!containing_widget) return; + if (!containing_widget || !selected_frame) return; /* Get the symtab and line number of the selected frame. */ fi = get_frame_info (selected_frame); - sal = find_pc_line (fi.pc, fi.next_frame); + sal = find_pc_line (fi->pc, fi->next_frame); /* Strictly this is wrong, but better than a blank display */ @@ -148,18 +131,17 @@ xgdb_display_source () if (linenumbers_changed || source_window_symtab != sal.symtab) { - Arg fileArgs[1]; - XtTextSource src; - - must_scroll = 1; + static Arg fileArgs[1]; + XtTextSource src; + new = 1; source_window_symtab = sal.symtab; - src = XtTextGetSource (source_text_widget); - XtDiskSourceDestroy (src); + src = XtTextGetSource(source_text_widget); + XtDiskSourceDestroy(src); XtSetArg (fileArgs[0], XtNfile, filename); - src = XtDiskSourceCreate (source_text_widget->core.parent, fileArgs, 1); - XtTextSetSource (source_text_widget, src, 0); + src = XtDiskSourceCreate(source_text_widget->core.parent, fileArgs, 1); + XtTextSetSource(source_text_widget, src, 0); XtSetArg (labelArgs[0], XtNlabel, filename ? filename : "No source displayed."); @@ -170,38 +152,46 @@ xgdb_display_source () /* Update display and cursor positions as necessary. Cursor should be placed on line sal.line. */ - /* Find out where the display is positioned (in case user scrolled it). */ - - if (! must_scroll) - { - int top_line_number; - - XtSetArg (args[0], XtNdisplayPosition, NULL); - XtGetValues (source_text_widget, args, 1); - top_line_number = source_charpos_line (source_window_symtab, - (int) args[0].value); - /* If desired position is off screen, we must scroll. */ - if (sal.line < top_line_number - || sal.line >= top_line_number + height) - must_scroll = 1; - } - - /* If appropriate, scroll the text display. */ - - if (must_scroll) - { - int top_line_number = (sal.line > height/3) ? sal.line - height/3 : 1; - - XtSetArg (args[0], XtNdisplayPosition, - source_line_charpos (source_window_symtab, top_line_number)); - XtSetValues (source_text_widget, args, 1); - } + { + static int top_line_number, bottom_line_number; + int current_top; + Arg textArgs[1]; + + if (! new) + { + int new_top; + + /* Get positions of start of display, and caret */ + XtSetArg (textArgs[0], XtNdisplayPosition, NULL); + XtGetValues (source_text_widget, textArgs, XtNumber (textArgs)); + new_top = source_charpos_line (source_window_symtab, + (int) textArgs[0].value); + bottom_line_number += new_top - top_line_number; + top_line_number = new_top; + } + + /* If appropriate, scroll the text display. */ + if (sal.line < top_line_number + || sal.line > bottom_line_number + || new) + { + /* yes, these magic numbers are ugly, but I don't know how + * to get the height of a text widget in a V11-portable way + */ + top_line_number = (sal.line > 15) ? sal.line - 15 : 0; + bottom_line_number = top_line_number + 35; + + XtSetArg (textArgs[0], XtNdisplayPosition, + source_line_charpos (source_window_symtab, top_line_number)); + XtSetValues (source_text_widget, textArgs, XtNumber (textArgs)); + } - /* Set the text display cursor position within the text. */ + /* Set the text display cursor position within the text. */ - XtSetArg (args[0], XtNinsertPosition, - source_line_charpos (source_window_symtab, sal.line)); - XtSetValues (source_text_widget, args, 1); + XtSetArg (textArgs[0], XtNinsertPosition, + source_line_charpos (source_window_symtab, sal.line)); + XtSetValues (source_text_widget, textArgs, XtNumber (textArgs)); + } } /* Display FILENAME in the title bar at bottom of window. */ @@ -223,10 +213,7 @@ static void print_prompt () { if (prompt_string) - { - printf ("%s", prompt_string); - fflush (stdout); - } + printf ("%s", prompt_string); } /* Handlers for buttons. */ @@ -236,10 +223,10 @@ print_prompt () Get the "selection" from X and use it as the operand of a print command. */ static void -print_button (w, starflag, call_data) - Widget w; - int starflag; - caddr_t call_data; +print_button(w, starflag, call_data) +Widget w; +int starflag; +caddr_t call_data; { int selected_length; char *selected_text; @@ -269,10 +256,10 @@ print_button (w, starflag, call_data) in the source window, and, if RUNFLAG is nonzero, continue. */ static void -breakpoint_button (w, runflag, call_data) - Widget w; - int runflag; - caddr_t call_data; +breakpoint_button(w, runflag, call_data) +Widget w; +int runflag; +caddr_t call_data; { XtTextPosition start, finish; @@ -339,13 +326,12 @@ explicit_breakpoint_button () print_prompt (); } -/* Handle a button by running the command COMMAND. */ static void -do_command (w, command, call_data) - Widget w; - char *command; - caddr_t call_data; +do_command(w, command, call_data) +Widget w; +char *command; +caddr_t call_data; { execute_command (command, 0); xgdb_display_source (); @@ -355,34 +341,32 @@ do_command (w, command, call_data) static void redisplay_button() { - xgdb_display_source(); + xgdb_display_source(); } /* Define and display all the buttons. */ static void addbutton (parent, name, function, closure) - Widget parent; - char *name; - void (*function) (); - caddr_t 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}, - }; - - Callback[0].callback = (XtCallbackProc)function; - Callback[0].closure = (caddr_t)closure; - commandArgs[0].value = (XtArgVal)name; - XtCreateManagedWidget (name, commandWidgetClass, parent, - commandArgs, XtNumber(commandArgs)); + static XtCallbackRec Callback[] = { + {NULL, (caddr_t)NULL}, + {NULL, (caddr_t)NULL}, + }; + static Arg commandArgs[] = { + {XtNlabel, (XtArgVal)NULL}, + {XtNcallback, (XtArgVal)Callback}, + }; + + Callback[0].callback = (XtCallbackProc)function; + Callback[0].closure = (caddr_t)closure; + commandArgs[0].value = (XtArgVal)name; + XtCreateManagedWidget (name, commandWidgetClass, parent, + commandArgs, XtNumber(commandArgs)); } /* Create the button windows and store them in `buttons'. */ @@ -418,16 +402,13 @@ static Widget create_label (name, label) char *name, *label; { - Arg labelArgs[2]; - Widget w; + static Arg labelArgs[2]; XtSetArg (labelArgs[0], XtNname, name); - XtSetArg (labelArgs[1], XtNlabel, label); - w = XtCreateManagedWidget ("label", labelWidgetClass, containing_widget, - labelArgs, XtNumber (labelArgs)); - XtPanedSetMinMax (w, w->core.height, w->core.height); - return w; + XtSetArg (labelArgs[1], XtNlabel, label); + return XtCreateManagedWidget ("label", labelWidgetClass, containing_widget, + labelArgs, XtNumber (labelArgs)); } /* Create a subwindow of PARENT that displays and scrolls the contents @@ -445,128 +426,119 @@ create_text_widget (parent, filename) XtSetArg (fileArgs[0], XtNfile, filename); src = XtDiskSourceCreate(parent, fileArgs, 1); sink = XtAsciiSinkCreate(parent, NULL, 0); - + XtSetArg (fileArgs[0], XtNtextOptions, scrollVertical); XtSetArg (fileArgs[1], XtNtextSource, src); XtSetArg (fileArgs[2], XtNtextSink, sink); - return XtCreateManagedWidget ("disk", textWidgetClass, parent, - fileArgs, XtNumber (fileArgs)); - -#if 0 /* This is tucker's method. */ - - /* Create an empty source-display window and add to containing_widget */ - XtSetArg (argl[0], XtNfile, "/dev/null"); - XtSetArg (argl[1], XtNtextOptions, scrollVertical); - XtSetArg (argl[2], XtNheight, (XtArgVal)sheight); - source_text_widget = XtCreateManagedWidget (NULL, asciiDiskWidgetClass, - containing_widget, argl, - XtNumber (argl)); - - /* Create NULL disk source */ - XtSetArg (argl[0], XtNfile, "/dev/null"); - NullSource = XtDiskSourceCreate (source_text_widget, argl, ONE); -#endif + return XtCreateManagedWidget("disk", textWidgetClass, parent, fileArgs, XtNumber (fileArgs)); } -/* window manager argument parsing */ -extern int *win_argc; -extern char **win_argv; - /* Entry point to create the widgets representing our display. */ + int xgdb_create_window () { - int width, height; - int sheight; - Arg argl[3]; - - /* initialize toolkit, setup defaults */ - main_widget = XtInitialize ("gdb", "gdb", NULL, 0, win_argc, win_argv); - screen_display = XtDisplay (main_widget); - - /* Find out what size the user specified. */ - - XtSetArg (argl[0], XtNwidth, (XtArgVal)&width); - XtSetArg (argl[1], XtNheight, (XtArgVal)&height); - XtGetValues (main_widget, argl, XtNumber(argl)); - - /* If none specified, set a default size. */ - - if (!width || !height) - { - width = 500, height = 700; - XtSetArg (argl[0], XtNwidth, (XtArgVal)width); - XtSetArg (argl[1], XtNheight, (XtArgVal)height); - XtSetValues (main_widget, argl, XtNumber(argl)); - } - sheight = (float)height / 2.5; - - /* Create the (toplevel) main_widget */ - XtSetArg (argl[0], XtNwidth, (XtArgVal)width); - XtSetArg (argl[1], XtNheight, (XtArgVal)height); - containing_widget - = XtCreateManagedWidget ("vpaned", vPanedWidgetClass, - main_widget, argl, XtNumber (argl)); - XtPanedSetRefigureMode (containing_widget, FALSE); - - /* Create title */ + static Arg frameArgs[]= { + {XtNwidth, (XtArgVal) 600}, + {XtNheight, (XtArgVal) 700}, + }; { - char buf[200]; - extern char *version; - sprintf (buf, "GDB %s", version); - title_widget = - create_label ("Title", buf); + char *dummy1[2]; + int dummy2 = 1; + + dummy1[0] = "xgdb"; + dummy1[1] = NULL; + main_widget = XtInitialize ("xgdb", "XGdb", 0, 0, &dummy2, dummy1); } + screen_display = XtDisplay(main_widget); + + /* Create the containing_widget. */ + + containing_widget = XtCreateManagedWidget ("frame", vPanedWidgetClass, main_widget, + frameArgs, XtNumber (frameArgs)); + /* Create source file name window and add to containing_widget */ + source_name_widget + = create_label ("Source File", "No source file yet."); + /* Create exec file name window and add */ - exec_name_widget = - create_label ("Executable", "No executable specified"); + exec_name_widget = create_label ("Executable", "No executable specified."); /* Create window full of buttons. */ - button_box_widget = XtCreateManagedWidget ("buttons", boxWidgetClass, - containing_widget, NULL, 0); + button_box_widget = XtCreateManagedWidget ("buttonbox", boxWidgetClass, + containing_widget, NULL, 0); create_buttons (button_box_widget); - /* Create source file name window and add to containing_widget */ - source_name_widget = - create_label ("Source File", "No source file yet."); - /* Create an empty source-display window and add to containing_widget */ source_text_widget = create_text_widget (containing_widget, "/dev/null"); -#ifdef VFTD - /* Create Fake Text source */ + XSync(screen_display, 0); + XtRealizeWidget(main_widget); + +#if 0 + default_gc = XCreateGC (screen_display, XtWindow(containing_widget), 0, NULL); + /* Create icon window. */ { - extern XtTextSource TCreateApAsSource(); - TSource = TCreateApAsSource(); + static Arg iconArgs[2]; + void (*compiler_bug) () = deiconify_button; + XtSetArg (iconArgs[0], XtNlabel, "(gdb)"); + XtSetArg (iconArgs[1], XtNfunction, compiler_bug); + icon_window = XtCreateWidget ("Icon", commandWidgetClass, + iconArgs, XtNumber (iconArgs)); + XMoveWindow (screen_display, icon_window, 100, 100); /* HACK */ + XSetIconWindow (screen_display, containing_widget, icon_window); } - /* Create interactive box */ - XtSetArg (argl[0], XtNtextSource, (XtArgVal)TSource); - XtSetArg (argl[1], XtNtextSink, - (XtArgVal)XtAsciiSinkCreate(containing_widget, NULL, 0)); - XtSetArg (argl[2], XtNtextOptions, - (XtArgVal)(scrollVertical | wordBreak)); - interactive_widget = XtCreateManagedWidget ("gdbWindow", textWidgetClass, - containing_widget, argl, THREE); -#endif - - /* Put them one screen */ - XtPanedSetRefigureMode(containing_widget, TRUE); - XtRealizeWidget (main_widget); - - /* Define GDB cursor */ -#if 0 - XDefineCursor (screen_display, XtWindow (main_widget), - XCreateFontCursor (screen_display, XC_circle)); -#endif + /* Now make the whole thing appear on the display. */ + { + Pixmap pm1, pm2; + XImage image; + Cursor curse; + + image.width = gdb_width; + image.height = gdb_height; + image.xoffset = 0; + image.format = XYBitmap; + image.byte_order = LSBFirst; + image.bitmap_unit = 16; + image.bitmap_bit_order = LSBFirst; + image.depth = 1; + image.bytes_per_line = 2; + image.bits_per_pixel = 1; + + pm1 = XCreatePixmap (screen_display, DefaultScreen (screen_display), + gdb_width, gdb_height, 1); + pm2 = XCreatePixmap (screen_display, DefaultScreen (screen_display), + gdb_width, gdb_height, 1); + + image.data = (char *) gdb_bits; + XPutImage (screen_display, pm1, default_gc, &image, 0, 0, 0, 0, + gdb_width, gdb_height); + + image.data = (char *) gdb_mask_bits; + XPutImage (screen_display, pm2, default_gc, &image, 0, 0, 0, 0, + gdb_width, gdb_height); + + curse = XCreatePixmapCursor (screen_display, pm1, pm2, + BlackPixel (screen_display, + DefaultScreen (screen_display)), + WhitePixel (screen_display, + DefaultScreen (screen_display)), + gdb_x_hot, gdb_y_hot); + + XFreePixmap (screen_display, pm1); + XFreePixmap (screen_display, pm2); + + XDefineCursor (screen_display, containing_widget, curse); + XDefineCursor (screen_display, icon_window, curse); + } +#endif 0 XFlush (screen_display); + return 1; } -#define MAX_XGDB_READ 128 - /* xgdb_dispatch -- Loop, dispatching on window events, until data is available on FP (which is normally stdin). Then return, so the data on FP can be processed. */ @@ -581,20 +553,13 @@ xgdb_dispatch (fp) int nfds; XEvent ev; int pend; - int nread; - char buf[1024]; - int ipmask; - -#ifdef VTFD - ipmask = 1 << vtfd[0]; -#endif - + while (! (rfds & inmask)) { pend = XPending (screen_display); if (!pend) { - rfds = inmask | xmask | ipmask; + rfds = inmask | xmask; /* this isn't right for 4.3 but it works 'cuz of 4.2 compatibility */ nfds = select (32, &rfds, 0, 0, (struct timeval *) 0); } @@ -603,133 +568,11 @@ xgdb_dispatch (fp) XNextEvent (screen_display, &ev); XtDispatchEvent (&ev); } - -#ifdef VTFD - /* Handle I/O through the command window. */ - if (pend == 0 && (rfds & ipmask)) - { - nread = read (vtfd[0], buf, sizeof(buf)); - xgdb_write (buf, nread); - } - nread = xgdb_read (buf, MAX_XGDB_READ); - if (pend == 0 && nread > 0) - { - write (vifd[1], buf, nread); - } -#endif } } -#ifdef VTFD - -static int output_size; -static int used_size; -static char *output_string; - -static void -xgdb_init_text () -{ - Arg args[2]; - - output_size = 1000; - output_string = (char *) xmalloc (output_size); - used_size = 0; - - XtSetArg (args[0], XtNstring, (XtArgVal) output_string); - XtSetArg (args[1], XtNlength, (XtArgVal) output_size); - TSource - = XtStringSourceCreate (toplevel, args, 2); - - XtSetArg (args[0], XtNtextSource, TSource); - XtSetValues (interaction_widget, Args, 1); -} - -static void -xgdb_grow_text (size) - int size; -{ - if (output_size < used_size + size + 200) - { - Arg args[2]; - - XtStringSourceDestroy (TSource); - - output_size = (used_size + size + 1010 + 512) / 1010 * 1010; - output_string = xrealloc (output_string, output_size); - - XtSetArg (args[0], XtNstring, (XtArgVal) output_string); - XtSetArg (args[1], XtNlength, (XtArgVal) output_size); - TSource - = XtStringSourceCreate (toplevel, args, 2); - - XtSetArg (args[0], XtNtextSource, TSource); - XtSetValues (interaction_widget, Args, 1); - } -} - -/*VARARGS*/ -xgdb_printf (fmt, arg1, arg2, arg3, arg4) - char *fmt; -{ - char buf[1024]; - XtTextBlock text; - XtTextPosition pos; - -/* ??? This will crash on the wrong data. */ - pos = (*TSource->Scan)(TSource, 0, XtstAll, XtsdRight, 1, 0); - sprintf (buf, fmt, arg1, arg2, arg3, arg4); - text.length = strlen (buf); - text.ptr = buf; - xgdb_grow_text (text.length); - used_size += text.length; - XtTextReplace (interactive_widget, pos, pos, &text); - XtTextSetInsertionPoint (interactive_widget, pos + text.length); - XFlush (screen_display); -} - -int -xgdb_write (buf, len) - char *buf; - int len; -{ - XtTextBlock text; - XtTextPosition pos; - - pos = (*TSource->Scan)(TSource, 0, XtstAll, XtsdRight, 1, 0); - text.length = len; - text.ptr = buf; - xgdb_grow_text (text.length); - used_size += text.length; - XtTextReplace (interactive_widget, pos, pos, &text); - XtTextSetInsertionPoint (interactive_widget, pos + text.length); - XFlush (screen_display); -} - -int -xgdb_read (buf, maxlen) - char *buf; - int maxlen; -{ - XtTextBlock text; - XtTextPosition endpos; - int length = 0; - - xgdb_grow_text (maxlen); - endpos = XtTextGetInsertionPoint (interactive_widget); - length = endpos - used_size; - if (length > 0) - { - (*TSource->Read) (TSource, lastpos, &text, maxlen - 10); - length = text.length; - strncpy(buf, text.ptr, length); - buf[length] = NULL; - used_size += length; - } - return length; -} -#endif /* VTFD */ - /* If we use an X window, the GDB command loop is told to call this function + before reading a command from stdin. PROMPT is saved for later use so buttons can print a prompt-string. */ @@ -743,8 +586,7 @@ xgdb_window_hook (infile, prompt) xgdb_dispatch (infile); } -static -initialize () +_initialize_xgdb () { extern void (*window_hook) (); extern int inhibit_windows; @@ -756,5 +598,4 @@ initialize () specify_exec_file_hook (xgdb_display_exec_file); } -END_FILE