aboutsummaryrefslogtreecommitdiff
path: root/gdb/RCS
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/RCS')
-rw-r--r--gdb/RCS/Makefile,v160
-rw-r--r--gdb/RCS/coffread.c,v304
-rw-r--r--gdb/RCS/core.c,v763
-rw-r--r--gdb/RCS/infcmd.c,v966
-rw-r--r--gdb/RCS/inflow.c,v731
-rw-r--r--gdb/RCS/m-mac-aux.h,v523
-rw-r--r--gdb/RCS/m-mac-auxinit.h,v43
-rw-r--r--gdb/RCS/m68k-pinsn.c,v828
-rw-r--r--gdb/RCS/main.c,v1110
-rw-r--r--gdb/RCS/source.c,v705
-rw-r--r--gdb/RCS/symmisc.c,v575
-rw-r--r--gdb/RCS/symtab.c,v1153
-rw-r--r--gdb/RCS/utils.c,v461
13 files changed, 8322 insertions, 0 deletions
diff --git a/gdb/RCS/Makefile,v b/gdb/RCS/Makefile,v
new file mode 100644
index 0000000..d942be0
--- /dev/null
+++ b/gdb/RCS/Makefile,v
@@ -0,0 +1,160 @@
+head 1.4;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @# @;
+
+
+1.4
+date 88.06.08.23.14.28; author gnu; state Exp;
+branches ;
+next 1.3;
+
+1.3
+date 88.02.28.03.38.17; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 88.01.26.05.14.43; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.26.05.14.07; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Original from RMS's wheaties devl dirs
+@
+
+
+1.4
+log
+@Add -DEBUG
+@
+text
+@# -I. for "#include <obstack.h>"
+CFLAGS = -g -I. -Dvfork=fork -DDEBUG
+# NOTE!!! -O may FAIL TO WORK! See initialize.h for some weird hacks.
+
+# 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.
+OBSTACK = obstack.o alloca.o -lPW
+OBSTACK1 = obstack.o alloca.o
+
+STARTOBS = main.o firstfile.o
+
+OBS = 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
+
+TSOBS = core.o inflow.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) -o gdb $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) -lg $(OBSTACK)
+
+xgdb : $(STARTOBS) $(OBS) xgdb.o $(TSOBS) $(ENDOBS) $(OBSTACK1)
+ $(CC) -o xgdb $(STARTOBS) $(OBS) xgdb.o $(TSOBS) $(ENDOBS) \
+ -lXtk11 -lXrm -lX11 -lg $(OBSTACK)
+
+kdb : $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) $(OBSTACK1)
+ ld -o kdb $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) -lc -lg $(OBSTACK)
+
+clean:
+ rm -f $(STARTOBS) $(OBS) $(TSOBS) $(OBSTACK1) $(NTSSTART) $(NTSOBS)
+ rm -f xgdb.o gdb xgdb kdb tags errs expread.tab.c
+
+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.'
+ 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
+# 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
+printcmd.o : printcmd.c defs.h initialize.h param.h symtab.h value.h expression.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 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 $@@
+
+obstack.o : obstack.c
+@
+
+
+1.3
+log
+@Make clean
+@
+text
+@d2 1
+a2 1
+CFLAGS = -g -I. -Dvfork=fork
+@
+
+
+1.2
+log
+@We don't have vfork or alloca, and regexp routines are in libPW.a for
+no good reason.
+@
+text
+@d38 4
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d2 1
+a2 1
+CFLAGS = -g -I.
+d8 2
+a9 2
+OBSTACK = obstack.o
+OBSTACK1 = obstack.o
+@
diff --git a/gdb/RCS/coffread.c,v b/gdb/RCS/coffread.c,v
new file mode 100644
index 0000000..7542030
--- /dev/null
+++ b/gdb/RCS/coffread.c,v
@@ -0,0 +1,304 @@
+head 1.4;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.4
+date 88.06.08.23.13.40; author gnu; state Exp;
+branches ;
+next 1.3;
+
+1.3
+date 88.02.28.03.37.53; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 88.01.26.05.02.32; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.26.00.38.04; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Original from RMS's work dirs on Wheaties
+@
+
+
+1.4
+log
+@Half reasonable reading of coff files. Problem was that it assumed
+that a .text would show up sometime, and it never did. We have to close
+out each source file's symtab as we hit the next one.
+@
+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 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 "initialize.h"
+#include "symtab.h"
+
+#include <a.out.h>
+#include <stdio.h>
+#include <obstack.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+
+static void add_symbol_to_list ();
+static void read_coff_symtab ();
+static void patch_opaque_types ();
+static struct type *decode_function_type ();
+static struct type *decode_type ();
+static struct type *decode_base_type ();
+static struct type *read_enum_type ();
+static struct type *read_struct_type ();
+static void finish_block ();
+static struct blockvector *make_blockvector ();
+static struct symbol *process_coff_symbol ();
+static int init_stringtab ();
+static void free_stringtab ();
+static char *getfilename ();
+static char *getsymname ();
+static int init_lineno ();
+static void enter_linenos ();
+
+START_FILE
+
+/* 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;
+
+int debug = 1;
+
+
+/* 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)
+ {
+ 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];
+}
+
+/* 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 *) xmalloc (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 \ No newline at end of file
diff --git a/gdb/RCS/core.c,v b/gdb/RCS/core.c,v
new file mode 100644
index 0000000..99547f8
--- /dev/null
+++ b/gdb/RCS/core.c,v
@@ -0,0 +1,763 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.04.52; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.21.05.04.03; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@From RMS's development version on wheaties, 20Jan88
+@
+
+
+1.2
+log
+@Hacks to get it to compile on a/ux. Needs work at finding the registers
+in a core file.
+@
+text
+@/* Work with core dump and executable files, 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 "initialize.h"
+#include "defs.h"
+#include "param.h"
+
+#include <a.out.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
+#ifdef AOUTHDR
+#define COFF_FORMAT
+#endif
+
+#ifdef NEW_SUN_CORE
+#include <sys/core.h>
+#else /* not NEW_SUN_CORE */
+#ifdef UMAX_CORE
+#include <sys/ptrace.h>
+#else /* not UMAX_CORE */
+#ifdef mac_aux
+#include <sys/seg.h>
+#include <sys/mmu.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/user.h>
+#else
+#include <sys/user.h>
+#endif /* mac_aux */
+#endif /* UMAX_CORE */
+#endif /* NEW_SUN_CORE */
+
+#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
+
+START_FILE
+
+/* Hook for `exec_file_command' command to call. */
+
+void (*exec_file_display_hook) ();
+
+/* File names of core file and executable file. */
+
+static char *corefile;
+static 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;
+
+/* 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. */
+
+static CORE_ADDR data_start;
+static CORE_ADDR data_end;
+static CORE_ADDR stack_start;
+static 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. */
+
+static CORE_ADDR text_start;
+static CORE_ADDR text_end;
+static CORE_ADDR exec_data_start;
+static CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+static int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+static int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+static int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+static int stack_offset;
+
+#ifdef COFF_FORMAT
+/* various coff data structures */
+
+static FILHDR file_hdr;
+static SCNHDR text_hdr;
+static SCNHDR data_hdr;
+
+#endif /* not COFF_FORMAT */
+
+/* a.out header saved in core file. */
+
+static AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+static AOUTHDR exec_aouthdr;
+
+static 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;
+
+ bcopy (&corestr.c_regs, registers, 16 * 4);
+ *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps;
+ *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc;
+ bcopy (corestr.c_fpstatus.fps_regs,
+ &registers[REGISTER_BYTE (FP0_REGNUM)],
+ sizeof corestr.c_fpstatus.fps_regs);
+ bcopy (&corestr.c_fpstatus.fps_control,
+ &registers[REGISTER_BYTE (FPC_REGNUM)],
+ sizeof corestr.c_fpstatus - sizeof corestr.c_fpstatus.fps_regs);
+
+ bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec));
+
+ printf ("Core file is from \"%s\".\n", corestr.c_cmdname);
+ }
+#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));
+
+#else /* not UMAX_CORE */
+#ifdef mac_aux
+ /* This may well not work for 0407 (nonshared text) a.out's */
+ data_end = data_start + u.u_dsize << PAGESHIFT;
+ stack_start = stack_end - u.u_ssize << PAGESHIFT;
+ data_offset = USIZE;
+ stack_offset = USIZE + u.u_dsize << PAGESHIFT;
+ reg_offset = (int) &u.u_ar0[0] - (int) &u;
+
+ core_aouthdr.a_magic = u.u_exdata.ux_mag;
+#else
+ 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 mac_aux */
+#endif /* not UMAX_CORE */
+
+ /* 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);
+ }
+ }
+ }
+#endif /* not NEW_SUN_CORE */
+ if (filename[0] == '/')
+ corefile = savestring (filename, strlen (filename));
+ else
+ {
+ char dirname[MAXPATHLEN];
+
+ getwd (dirname);
+ corefile = concat (dirname, "/", 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;
+
+ val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
+
+ if (val < 0)
+ perror_with_name (filename);
+
+ 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 ? filename : "No executable specified.\n");
+}
+
+/* Call this to specify the hook for exec_file_command to call back.
+ This is called from the x-window display code. */
+
+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. */
+
+close_exec_file ()
+{
+ if (execchan >= 0)
+ close (execchan);
+ execchan = -1;
+}
+
+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. */
+
+static void
+validate_files ()
+{
+ if (execfile != 0 && corefile != 0)
+ {
+ struct stat st_core;
+
+ fstat (corechan, &st_core);
+
+ if (core_aouthdr.a_magic != 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");
+ }
+}
+
+char *
+get_exec_file ()
+{
+ if (execfile == 0)
+ error ("No executable file specified.\n\
+Use the \"exec-file\" and \"symbol-file\" commands.");
+ return execfile;
+}
+
+int
+have_core_file_p ()
+{
+ return corefile != 0;
+}
+
+static void
+files_info ()
+{
+ char *symfile;
+ extern char *get_sym_file ();
+
+ if (execfile)
+ printf ("Executable file \"%s\".\n", execfile);
+ else
+ printf ("No executable file\n");
+ if (corefile == 0)
+ printf ("No core dump file\n");
+ else
+ printf ("Core dump file \"%s\".\n", corefile);
+
+ if (have_inferior_p ())
+ printf ("Using the running image of the program, rather than these files.\n");
+
+ symfile = get_sym_file ();
+ if (symfile != 0)
+ printf ("Symbols loaded from \"%s\".\n", symfile);
+
+ if (! have_inferior_p ())
+ {
+ if (execfile)
+ {
+ printf ("Text segment from 0x%x to 0x%x.\n",
+ text_start, text_end);
+ }
+ 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);
+ }
+ }
+}
+
+/* Read "memory data" from core file and/or executable file */
+
+read_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ if (have_inferior_p ())
+ read_inferior_memory (memaddr, myaddr, len);
+ else
+ xfer_core_file (memaddr, myaddr, len, 0);
+}
+
+/* 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.");
+}
+
+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;
+
+ 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. */
+
+ 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)
+ {
+ 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;
+ }
+
+ /* 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. */
+ else
+ bzero (myaddr, i);
+
+ memaddr += i;
+ myaddr += i;
+ len -= i;
+ }
+}
+
+/* My replacement for the read system call.
+ Used like `read' but keeps going if `read' returns too soon. */
+
+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;
+ }
+}
+
+#ifndef NEW_SUN_CORE
+
+/* 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);
+
+#ifdef mac_aux
+/* FIXME, we don't know where the regs are. Maybe the test command
+ * that tests what parts of the upage are writeable will find 'em for us.
+ */
+#define REGISTER_U_ADDR(addr, foo, bar) addr = 0;
+#endif
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+#endif /* not NEW_SUN_CORE */
+
+static
+initialize ()
+{
+ 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.");
+}
+
+END_FILE
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d27 1
+d44 5
+d50 4
+a53 1
+#endif
+d240 10
+d259 1
+d675 6
+@
diff --git a/gdb/RCS/infcmd.c,v b/gdb/RCS/infcmd.c,v
new file mode 100644
index 0000000..cc30fe4
--- /dev/null
+++ b/gdb/RCS/infcmd.c,v
@@ -0,0 +1,966 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.06.19; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.26.01.19.05; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Original from RMS's wheaties devl sources
+@
+
+
+1.2
+log
+@Add local sys_siglist for a/ux because they don't provide one, sigh.
+@
+text
+@/* Memory-access and commands for inferior process, 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 "defs.h"
+#include "initialize.h"
+#include "symtab.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "environ.h"
+#include "value.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/param.h>
+
+#ifdef mac_aux
+/* Warning! This table is positional and highly dependent on the local
+ system. Check it closely against <sys/signal.h> when porting. */
+char *sys_siglist[] = {
+ "Signal 0",
+ "Hangup",
+ "Interrupt",
+ "Quit",
+ "Invalid instruction",
+ "Trace/breakpoint trap",
+ "IOT trap",
+ "EMT trap",
+ "Floating point exception",
+ "Killed",
+ "Bus error",
+ "Segmentation fault",
+ "Bad system call",
+ "Broken pipe",
+ "Alarm clock",
+ "Terminated",
+ "User signal 1",
+ "User signal 2",
+ "Child exited",
+ "Power-fail restart",
+ "Stopped",
+ "Stopped (tty input)",
+ "Stopped (tty output)",
+ "Stopped (signal)",
+ "Cputime limit exceeded",
+ "File size limit exceeded",
+ "Virtual timer expired",
+ "Profiling timer expired",
+ "Window changed",
+ "Continued",
+ "Urgent I/O condition",
+ "I/O possible",
+};
+#else
+/* More portable systems do it for you */
+extern char *sys_siglist[];
+#endif
+
+#define ERROR_NO_INFERIOR \
+ if (inferior_pid == 0) error ("The program is not being run.");
+
+/* String containing arguments to give to the program,
+ with a space added at the front. Just a space means no args. */
+
+static char *inferior_args;
+
+/* File name for default use for standard in/out in the inferior. */
+
+char *inferior_io_terminal;
+
+/* Pid of our debugged inferior, or 0 if no inferior now. */
+
+int inferior_pid;
+
+/* Last signal that the inferior received (why it stopped). */
+
+int stop_signal;
+
+/* Address at which inferior stopped. */
+
+CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped. */
+
+FRAME stop_frame;
+
+/* Number of breakpoint it stopped at, or 0 if none. */
+
+int stop_breakpoint;
+
+/* Nonzero if stopped due to a step command. */
+
+int stop_step;
+
+/* Nonzero if stopped due to completion of a stack dummy routine. */
+
+int stop_stack_dummy;
+
+/* Range to single step within.
+ If this is nonzero, respond to a single-step signal
+ by continuing to step if the pc is in this range. */
+
+CORE_ADDR step_range_start; /* Inclusive */
+CORE_ADDR step_range_end; /* Exclusive */
+
+/* Stack frame address as of when stepping command was issued.
+ This is how we know when we step into a subroutine call,
+ and how to set the frame for the breakpoint used to step out. */
+
+CORE_ADDR step_frame;
+
+/* 1 means step over all subroutine calls.
+ -1 means step over calls to undebuggable functions. */
+
+int step_over_calls;
+
+/* If stepping, nonzero means step count is > 1
+ so don't print frame next time inferior stops
+ if it stops due to stepping. */
+
+int step_multi;
+
+/* Environment to use for running inferior,
+ in format described in environ.h. */
+
+struct environ *inferior_environ;
+
+CORE_ADDR read_pc ();
+struct command_line *get_breakpoint_commands ();
+
+START_FILE
+
+int
+have_inferior_p ()
+{
+ return inferior_pid != 0;
+}
+
+static void
+set_args_command (args)
+ char *args;
+{
+ free (inferior_args);
+ if (!args) args = "";
+ inferior_args = concat (" ", args, "");
+}
+
+void
+tty_command (file)
+ char *file;
+{
+ if (file == 0)
+ error_no_arg ("terminal name for running target process");
+
+ inferior_io_terminal = savestring (file, strlen (file));
+}
+
+static void
+run_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ extern char **environ;
+ register int i;
+ char *exec_file;
+ char *allargs;
+
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int errno;
+
+ dont_repeat ();
+
+ if (inferior_pid)
+ {
+ if (query ("The program being debugged has been started already.\n\
+Start it from the beginning? "))
+ kill_inferior ();
+ else
+ error ("Program already started.");
+ }
+
+ if (args)
+ set_args_command (args);
+
+ exec_file = (char *) get_exec_file ();
+ if (from_tty)
+ {
+ printf ("Starting program: %s%s\n",
+ exec_file, inferior_args);
+ fflush (stdout);
+ }
+
+ allargs = concat ("exec ", exec_file, inferior_args);
+ inferior_pid = create_inferior (allargs, environ_vector (inferior_environ));
+
+ clear_proceed_status ();
+
+ start_inferior ();
+}
+
+void
+cont_command (proc_count_exp, from_tty)
+ char *proc_count_exp;
+ int from_tty;
+{
+ ERROR_NO_INFERIOR;
+
+ clear_proceed_status ();
+
+ /* If have argument, set proceed count of breakpoint we stopped at. */
+
+ if (stop_breakpoint && proc_count_exp)
+ {
+ set_ignore_count (stop_breakpoint,
+ parse_and_eval_address (proc_count_exp) - 1,
+ from_tty);
+ if (from_tty)
+ printf (" ");
+ }
+
+ if (from_tty)
+ printf ("Continuing.\n");
+
+ proceed (-1, -1, 0);
+}
+
+/* Step until outside of current statement. */
+static void step_1 ();
+
+static void
+step_command (count_string)
+{
+ step_1 (0, 0, count_string);
+}
+
+/* Likewise, but skip over subroutine calls as if single instructions. */
+
+static void
+next_command (count_string)
+{
+ step_1 (1, 0, count_string);
+}
+
+/* Likewise, but step only one instruction. */
+
+static void
+stepi_command (count_string)
+{
+ step_1 (0, 1, count_string);
+}
+
+static void
+nexti_command (count_string)
+{
+ step_1 (1, 1, count_string);
+}
+
+static void
+step_1 (skip_subroutines, single_inst, count_string)
+ int skip_subroutines;
+ int single_inst;
+ char *count_string;
+{
+ register int count = 1;
+
+ ERROR_NO_INFERIOR;
+ count = count_string ? parse_and_eval_address (count_string) : 1;
+
+ for (; count > 0; count--)
+ {
+ clear_proceed_status ();
+
+ step_frame = get_current_frame ();
+
+ if (! single_inst)
+ {
+ find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
+ if (step_range_end == 0)
+ {
+ terminal_ours ();
+ error ("Current function has no line number information.");
+ }
+ }
+ else
+ {
+ /* Say we are stepping, but stop after one insn whatever it does.
+ Don't step through subroutine calls even to undebuggable functions. */
+ step_range_start = step_range_end = 1;
+ if (!skip_subroutines)
+ step_over_calls = 0;
+ }
+
+ if (skip_subroutines)
+ step_over_calls = 1;
+
+ step_multi = (count > 1);
+ proceed (-1, -1, 1);
+ if (! stop_step)
+ break;
+ }
+}
+
+/* Continue program at specified address. */
+
+static void
+jump_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register CORE_ADDR addr;
+ struct symtab_and_line sal;
+
+ ERROR_NO_INFERIOR;
+
+ if (!arg)
+ error_no_arg ("starting address");
+
+ sal = decode_line_spec (arg, 1);
+
+ if (sal.symtab == 0 && sal.pc == 0)
+ error ("No source file has been specified.");
+
+ if (sal.pc == 0)
+ sal.pc = find_line_pc (sal.symtab, sal.line);
+
+ {
+ struct symbol *fn = get_frame_function (get_current_frame ());
+ struct symbol *sfn = find_pc_function (sal.pc);
+ if (fn != 0 && sfn != fn
+ && ! query ("That is not in function %s. Continue there? ",
+ sal.line, SYMBOL_NAME (fn)))
+ error ("Not confirmed.");
+ }
+
+ if (sal.pc == 0)
+ error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename);
+
+ addr = sal.pc;
+
+ clear_proceed_status ();
+
+ if (from_tty)
+ printf ("Continuing at 0x%x.\n", addr);
+
+ proceed (addr, 0, 0);
+}
+
+/* Continue program giving it specified signal. */
+
+static void
+signal_command (signum_exp, from_tty)
+ char *signum_exp;
+ int from_tty;
+{
+ register int signum;
+
+ dont_repeat (); /* Too dangerous. */
+ ERROR_NO_INFERIOR;
+
+ if (!signum_exp)
+ error_no_arg ("signal number");
+
+ signum = parse_and_eval_address (signum_exp);
+
+ clear_proceed_status ();
+
+ if (from_tty)
+ printf ("Continuing with signal %d.\n", signum);
+
+ proceed (stop_pc, signum, 0);
+}
+
+/* Execute a "stack dummy", a piece of code stored in the stack
+ by the debugger to be executed in the inferior.
+
+ To call: first, do PUSH_DUMMY_FRAME.
+ Then push the contents of the dummy. It should end with a breakpoint insn.
+ Then call here, passing address at which to start the dummy.
+
+ The contents of all registers are saved before the dummy frame is popped
+ and copied into the buffer BUFFER.
+
+ The dummy's frame is automatically popped whenever that break is hit.
+ If that is the first time the program stops, run_stack_dummy
+ returns to its caller with that frame already gone.
+ Otherwise, the caller never gets returned to. */
+
+/* 4 => return instead of letting the stack dummy run. */
+
+static int stack_dummy_testing = 0;
+
+void
+run_stack_dummy (addr, buffer)
+ CORE_ADDR addr;
+ REGISTER_TYPE *buffer;
+{
+ 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)
+ {
+ POP_FRAME;
+ return;
+ }
+ proceed (addr, 0, 0);
+
+ 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);
+}
+
+/* "finish": Set a temporary breakpoint at the place
+ the selected frame will return to, then continue. */
+
+static void
+finish_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtab_and_line sal;
+ register FRAME frame;
+ struct frame_info fi;
+
+ register struct symbol *function;
+
+ if (!have_inferior_p ())
+ error ("The program is not being run.");
+ if (arg)
+ error ("The \"finish\" command does not take any arguments.");
+
+ frame = get_prev_frame (selected_frame);
+ if (frame == 0)
+ error ("\"finish\" not meaningful in the outermost frame.");
+
+ clear_proceed_status ();
+
+ fi = get_frame_info (frame);
+ sal = find_pc_line (fi.pc, 0);
+ sal.pc = fi.pc;
+ set_momentary_breakpoint (sal, frame);
+
+ /* Find the function we will return from. */
+
+ fi = get_frame_info (fi.next_frame);
+ function = find_pc_function (fi.pc);
+
+ if (from_tty)
+ {
+ printf ("Run till exit from ");
+ print_selected_frame ();
+ }
+
+ proceed (-1, -1, 0);
+
+ if (stop_breakpoint == -3 && function != 0)
+ {
+ struct type *value_type;
+ register value val;
+
+ if (TYPE_CODE (SYMBOL_TYPE (function)) != TYPE_CODE_VOID)
+ value_type = SYMBOL_TYPE (function);
+ else
+ return;
+
+ val = value_being_returned (value_type, stop_registers);
+ printf ("Value returned is $%d = ", record_latest_value (val));
+ value_print (val, stdout);
+ putchar ('\n');
+ }
+}
+
+static void
+program_info ()
+{
+ if (inferior_pid == 0)
+ {
+ printf ("The program being debugged is not being run.\n");
+ return;
+ }
+
+ printf ("Program being debugged is in process %d, stopped at 0x%x.\n",
+ inferior_pid, stop_pc);
+ if (stop_step)
+ printf ("It stopped after being stepped.\n");
+ else if (stop_breakpoint)
+ printf ("It stopped at breakpoint %d.\n", stop_breakpoint);
+ else if (stop_signal)
+ printf ("It stopped with signal %d (%s).\n",
+ stop_signal, sys_siglist[stop_signal]);
+
+ printf ("\nType \"info stack\" or \"info reg\" for more information.\n");
+}
+
+static void
+environment_info (var)
+ char *var;
+{
+ if (var)
+ {
+ register char *val = get_in_environ (inferior_environ, var);
+ if (val)
+ printf ("%s = %s\n", var, val);
+ else
+ printf ("Environment variable \"%s\" not defined.\n", var);
+ }
+ else
+ {
+ register char **vector = environ_vector (inferior_environ);
+ while (*vector)
+ printf ("%s\n", *vector++);
+ }
+}
+
+static void
+set_environment_command (arg)
+ char *arg;
+{
+ register char *p, *val, *var;
+
+ if (arg == 0)
+ error_no_arg ("environment variable and value");
+
+ p = (char *) index (arg, '=');
+ val = (char *) index (arg, ' ');
+ if (p != 0 && val != 0)
+ 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++;
+ while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--;
+
+ var = savestring (arg, p - arg);
+ set_in_environ (inferior_environ, var, val);
+ free (var);
+}
+
+static void
+unset_environment_command (var)
+ char *var;
+{
+ if (var == 0)
+ error_no_arg ("environment variable");
+
+ unset_in_environ (inferior_environ, var);
+}
+
+/* Read an integer from debugged memory, given address and number of bytes. */
+
+read_memory_integer (memaddr, len)
+ CORE_ADDR memaddr;
+ int len;
+{
+ char cbuf;
+ short sbuf;
+ int ibuf;
+ long lbuf;
+
+ if (len == sizeof (char))
+ {
+ read_memory (memaddr, &cbuf, len);
+ return cbuf;
+ }
+ if (len == sizeof (short))
+ {
+ read_memory (memaddr, &sbuf, len);
+ return sbuf;
+ }
+ if (len == sizeof (int))
+ {
+ read_memory (memaddr, &ibuf, len);
+ return ibuf;
+ }
+ if (len == sizeof (lbuf))
+ {
+ read_memory (memaddr, &lbuf, len);
+ return lbuf;
+ }
+ error ("Cannot handle integers of %d bytes.", len);
+}
+
+CORE_ADDR
+read_pc ()
+{
+ return (CORE_ADDR) read_register (PC_REGNUM);
+}
+
+write_pc (val)
+ CORE_ADDR val;
+{
+ write_register (PC_REGNUM, (long) val);
+}
+
+char *reg_names[] = REGISTER_NAMES;
+
+static void
+registers_info (addr_exp)
+ char *addr_exp;
+{
+ register int i;
+ int regnum;
+
+ if (addr_exp)
+ {
+ if (*addr_exp >= '0' && *addr_exp <= '9')
+ regnum = atoi (addr_exp);
+ else
+ {
+ register char *p = addr_exp;
+ if (p[0] == '$')
+ p++;
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ if (!strcmp (p, reg_names[regnum]))
+ break;
+ if (regnum == NUM_REGS)
+ error ("%s: invalid register name.", addr_exp);
+ }
+ }
+ else
+ printf ("Reg\tContents\n\n");
+
+ for (i = 0; i < NUM_REGS; i++)
+ {
+ unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ REGISTER_TYPE val;
+
+ if (addr_exp != 0 && i != regnum)
+ continue;
+
+ /* On machines with lots of registers, pause every 16 lines
+ so user can read the output. */
+ if (addr_exp == 0 && i > 0 && i % 16 == 0)
+ {
+ printf ("--Type Return to print more--");
+ fflush (stdout);
+ read_line ();
+ }
+
+ /* Get the data in raw format, then convert also to virtual format. */
+ read_relative_register_raw_bytes (i, raw_buffer);
+ REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer);
+
+ printf ("%s\t", reg_names[i]);
+
+ /* 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);
+ /* Else if virtual format is too long for printf,
+ print in hex a byte at a time. */
+ else if (REGISTER_VIRTUAL_SIZE (i) > sizeof (long))
+ {
+ register int j;
+ printf ("0x");
+ for (j = 0; j < REGISTER_VIRTUAL_SIZE (i); j++)
+ printf ("%02x", virtual_buffer[j]);
+ }
+ /* Else print as integer in hex and in decimal. */
+ else
+ {
+ long val;
+
+ bcopy (virtual_buffer, &val, sizeof (long));
+ if (val == 0)
+ printf ("0");
+ else
+ printf ("0x%08x %d", val, val);
+ }
+
+ /* If register has different raw and virtual formats,
+ print the raw format in hex now. */
+
+ if (REGISTER_CONVERTIBLE (i))
+ {
+ register int j;
+
+ printf (" (raw 0x");
+ for (j = 0; j < REGISTER_RAW_SIZE (i); j++)
+ printf ("%02x", raw_buffer[j]);
+ printf (")");
+ }
+ printf ("\n");
+ }
+
+ printf ("Contents are relative to selected stack frame.\n");
+}
+
+#ifdef ATTACH_DETACH
+/*
+ * TODO:
+ * Should save/restore the tty state since it might be that the
+ * program to be debugged was started on this tty and it wants
+ * the tty in some state other than what we want. If it's running
+ * on another terminal or without a terminal, then saving and
+ * restoring the tty state is a harmless no-op.
+ */
+
+/*
+ * attach_command --
+ * takes a program started up outside of gdb and ``attaches'' to it.
+ * This stops it cold in it's tracks and allows us to start tracing
+ * it. For this to work, we must be able to send the process a
+ * signal and we must have the same effective uid as the program.
+ */
+static void
+attach_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *exec_file;
+ int pid;
+
+ dont_repeat();
+
+ if (!args)
+ error_no_arg ("process-id to attach");
+ else
+ pid = atoi (args);
+
+ if (inferior_pid)
+ {
+ if (query ("A program is being debugged already. Kill it? "))
+ kill_inferior ();
+ else
+ error ("Inferior not killed.");
+ }
+
+ exec_file = (char *) get_exec_file ();
+
+ if (from_tty)
+ {
+ printf ("Attaching program: %s pid %d\n",
+ exec_file, pid);
+ fflush (stdout);
+ }
+
+ attach_program (pid);
+}
+
+/*
+ * detach_command --
+ * takes a program previously attached to and detaches it.
+ * The program resumes execution and will no longer stop
+ * on signals, etc. We better not have left any breakpoints
+ * in the program or it'll die when it hits one. For this
+ * to work, it may be necessary for the process to have been
+ * previously attached. It *might* work if the program was
+ * started via the normal ptrace (PTRACE_TRACEME).
+ */
+
+static void
+detach_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *exec_file = (char *)get_exec_file ();
+ int signal = 0;
+
+ if (!inferior_pid)
+ error ("Not currently tracing a program\n");
+ if (from_tty)
+ {
+ printf ("Detaching program: %s pid %d\n",
+ exec_file, inferior_pid);
+ fflush (stdout);
+ }
+ if (args)
+ signal = atoi (args);
+
+ detach (signal);
+ inferior_pid = 0;
+}
+#endif /* ATTACH_DETACH */
+
+static
+initialize ()
+{
+ 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,
+ "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.");
+
+ add_info ("environment", environment_info,
+ "The environment to give the program, or one variable's value.\n\
+With an argument VAR, prints the value of environment variable VAR to\n\
+give the program being debugged. With no arguments, prints the entire\n\
+environment to be given to the program.");
+
+ add_com ("unset-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,
+ "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.");
+
+#ifdef ATTACH_DETACH
+ add_com ("attach", class_run, attach_command,
+ "Attach to a process that was started up outside of GDB.\n\
+To do this, you must have permission to send the process a signal.\n\
+And it must have the same effective uid as the debugger.\n\n\
+Before using \"attach\", you must use the \"exec-file\" command\n\
+to specify the program running in the process,\n\
+and the \"symbol-file\" command to load its symbol table.");
+ add_com ("detach", class_run, detach_command,
+ "Detach the process previously attached.\n\
+The process is no longer traced and continues its execution.");
+#endif /* ATTACH_DETACH */
+
+ add_com ("signal", class_run, signal_command,
+ "Continue program giving it signal number SIGNUMBER.");
+
+ add_com ("stepi", class_run, stepi_command,
+ "Step one instruction exactly.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("si", "stepi", class_alias, 0);
+
+ add_com ("nexti", class_run, nexti_command,
+ "Step one instruction, but proceed through subroutine calls.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("ni", "nexti", class_alias, 0);
+
+ add_com ("finish", class_run, finish_command,
+ "Execute until selected stack frame returns.\n\
+Upon return, the value returned is printed and put in the value history.");
+
+ add_com ("next", class_run, next_command,
+ "Step program, proceeding through subroutine calls.\n\
+Like the \"step\" command as long as subroutine calls do not happen;\n\
+when they do, the call is treated as one instruction.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("n", "next", class_run, 1);
+
+ add_com ("step", class_run, step_command,
+ "Step program until it reaches a different source line.\n\
+Argument N means do this N times (or till program stops for another reason).");
+ add_com_alias ("s", "step", class_run, 1);
+
+ add_com ("jump", class_run, jump_command,
+ "Continue program being debugged at specified line or address.\n\
+Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\
+for an address to start at.");
+
+ add_com ("cont", class_run, cont_command,
+ "Continue program being debugged, after signal or breakpoint.\n\
+If proceeding from breakpoint, a number N may be used as an argument:\n\
+then the same breakpoint won't break until the Nth time it is reached.");
+ add_com_alias ("c", "cont", class_run, 1);
+
+ add_com ("run", class_run, run_command,
+ "Start debugged program. You may specify arguments to give it.\n\
+Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\
+Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\
+With no arguments, uses arguments last specified (with \"run\" or \"set-args\".\n\
+To cancel previous arguments and run with no arguments,\n\
+use \"set-args\" without arguments.");
+ add_com_alias ("r", "run", class_run, 1);
+
+ add_info ("registers", registers_info,
+ "List of registers and their contents, for selected stack frame.\n\
+Register name as argument means describe only that register.");
+
+ add_info ("program", program_info,
+ "Execution status of the program.");
+
+ inferior_args = savestring (" ", 1); /* By default, no args. */
+ inferior_environ = make_environ ();
+ init_environ (inferior_environ);
+}
+
+END_FILE
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d34 39
+d74 1
+@
diff --git a/gdb/RCS/inflow.c,v b/gdb/RCS/inflow.c,v
new file mode 100644
index 0000000..83f44d9
--- /dev/null
+++ b/gdb/RCS/inflow.c,v
@@ -0,0 +1,731 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.07.38; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.21.05.04.57; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@From RMS's development sources on wheaties, 20Jan88
+@
+
+
+1.2
+log
+@Major Sys V tty changes, and a few changes to try to find the registers
+in the upage (untested yet).
+@
+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 "initialize.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sgtty.h>
+#include <fcntl.h>
+
+#ifdef mac_aux
+#include <sys/seg.h>
+#include <sys/mmu.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/user.h>
+#else
+#include <sys/user.h>
+#endif /* mac_aux */
+
+
+#ifdef UMAX_PTRACE
+#include <a.out.h>
+#endif
+
+#ifdef NEW_SUN_PTRACE
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#endif
+
+#ifdef SYSV_TTYS
+#include <termio.h>
+#endif
+
+extern int errno;
+
+/* Nonzero if we are debugging an attached outside process
+ rather than an inferior. */
+
+static int attach_flag;
+
+#define UPAGE_MASK 0x00003FFF
+
+START_FILE
+
+/* Record terminal status separately for debugger and inferior. */
+
+#ifdef SYSV_TTYS
+static struct termio ti_inferior;
+#else
+static struct sgttyb sg_inferior;
+static struct tchars tc_inferior;
+static struct ltchars ltc_inferior;
+static int lmode_inferior;
+#endif
+static int tflags_inferior;
+static int pgrp_inferior;
+
+#ifdef SYSV_TTYS
+static struct termio ti_ours;
+#else
+static struct sgttyb sg_ours;
+static struct tchars tc_ours;
+static struct ltchars ltc_ours;
+static int lmode_ours;
+#endif
+static int tflags_ours;
+static int pgrp_ours;
+
+/* 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 ()
+{
+
+#ifdef SYSV_TTYS
+ ti_inferior = ti_ours;
+#else
+ sg_inferior = sg_ours;
+ tc_inferior = tc_ours;
+ ltc_inferior = ltc_ours;
+ lmode_inferior = lmode_ours;
+#endif
+ tflags_inferior = tflags_ours;
+ pgrp_inferior = inferior_pid;
+
+ terminal_is_ours = 1;
+}
+
+/* Put the inferior's terminal settings into effect.
+ This is preparation for starting or resuming the inferior. */
+
+void
+terminal_inferior ()
+{
+ if (terminal_is_ours) /* && inferior_thisrun_terminal == 0) */
+ {
+ fcntl (0, F_SETFL, tflags_inferior);
+ fcntl (0, F_SETFL, tflags_inferior);
+#ifdef SYSV_TTYS
+ ioctl (0, TCSETA, &ti_inferior);
+#else
+ ioctl (0, TIOCSETN, &sg_inferior);
+ ioctl (0, TIOCSETC, &tc_inferior);
+ ioctl (0, TIOCSLTC, &ltc_inferior);
+ ioctl (0, TIOCLSET, &lmode_inferior);
+#endif
+ ioctl (0, TIOCSPGRP, &pgrp_inferior);
+ }
+ terminal_is_ours = 0;
+}
+
+/* Put some of our terminal settings into effect,
+ enough to get proper results from our output,
+ but do not change into or out of RAW mode
+ so that no input is discarded.
+
+ After doing this, either terminal_ours or terminal_inferior
+ should be called to get back to a normal state of affairs. */
+
+void
+terminal_ours_for_output ()
+{
+ terminal_ours_1 (1);
+}
+
+/* Put our terminal settings into effect.
+ First record the inferior's terminal settings
+ so they can be restored properly later. */
+
+void
+terminal_ours ()
+{
+ terminal_ours_1 (0);
+}
+
+static void
+terminal_ours_1 (output_only)
+ int output_only;
+{
+ /* Ignore this signal since it will happen when we try to set the pgrp. */
+ int (*osigttou) ();
+
+ if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */
+ {
+ terminal_is_ours = 1;
+
+ osigttou = signal (SIGTTOU, SIG_IGN);
+
+ ioctl (0, TIOCGPGRP, &pgrp_inferior);
+ ioctl (0, TIOCSPGRP, &pgrp_ours);
+
+ signal (SIGTTOU, osigttou);
+
+ tflags_inferior = fcntl (0, F_GETFL, 0);
+#ifdef SYSV_TTYS
+ ioctl (0, TCGETA, &ti_inferior);
+#else
+ ioctl (0, TIOCGETP, &sg_inferior);
+ ioctl (0, TIOCGETC, &tc_inferior);
+ ioctl (0, TIOCGLTC, &ltc_inferior);
+ ioctl (0, TIOCLGET, &lmode_inferior);
+#endif
+ }
+
+ fcntl (0, F_SETFL, tflags_ours);
+ fcntl (0, F_SETFL, tflags_ours);
+
+
+#ifdef SYSV_TTYS
+ ti_ours.c_lflag |= ICANON | ISIG;
+ if (output_only)
+ ti_ours.c_lflag &= ~((ICANON|ISIG)&ti_inferior.c_lflag);
+ ioctl (0, TCSETA, &ti_ours);
+ ti_ours.c_lflag |= ICANON | ISIG;
+#else
+ sg_ours.sg_flags &= ~RAW & ~CBREAK;
+ if (output_only)
+ sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags;
+ ioctl (0, TIOCSETN, &sg_ours);
+ ioctl (0, TIOCSETC, &tc_ours);
+ ioctl (0, TIOCSLTC, &ltc_ours);
+ ioctl (0, TIOCLSET, &lmode_ours);
+ sg_ours.sg_flags &= ~RAW & ~CBREAK;
+#endif
+}
+
+static void
+term_status_command ()
+{
+ register int i;
+ printf ("Inferior's terminal status (currently saved by GDB):\n");
+#ifdef SYSV_TTYS
+ printf ("fcntl flags = 0x%x, owner pid = %d.\n",
+ tflags_inferior, pgrp_inferior);
+ printf ("iflag = 0x%04x, oflag = 0x%04x, cflag = 0x%04x, lflag = 0x%04x\n",
+ ti_inferior.c_iflag, ti_inferior.c_oflag,
+ ti_inferior.c_cflag, ti_inferior.c_lflag);
+ printf ("line discipline = %d\n", ti_inferior.c_line);
+ printf ("control chars: ");
+ for (i = 0; i < NCC; i++)
+ printf ("0x%x ", ti_inferior.c_cc[i]);
+ printf ("\n");
+#else
+ 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 ("tchars: ");
+ for (i = 0; i < sizeof (struct tchars); i++)
+ printf ("0x%x ", ((char *)&tc_inferior)[i]);
+ printf ("\n");
+ printf ("ltchars: ");
+ for (i = 0; i < sizeof (struct ltchars); i++)
+ printf ("0x%x ", ((char *)&ltc_inferior)[i]);
+ printf ("\n");
+#endif
+}
+
+static void
+new_tty (ttyname)
+ char *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. */
+
+ /* 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 vector of program-name and args.
+ ENV is the environment vector to pass. */
+
+int
+create_inferior (allargs, env)
+ char **allargs;
+ char **env;
+{
+ int pid;
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int errno;
+
+ /* exec is said to fail if the executable is open. */
+ close_exec_file ();
+
+ pid = vfork ();
+ if (pid < 0)
+ perror_with_name ("vfork");
+
+ if (pid == 0)
+ {
+ /* Run inferior in a separate process group. */
+ setpgrp (getpid (), getpid ());
+
+ 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); */
+
+ ptrace (0);
+ execle ("/bin/sh", "sh", "-c", allargs, 0, env);
+
+ fprintf (stderr, "Cannot exec /bin/sh: %s.\n",
+ 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 (inferior_pid == 0)
+ error ("The program is not being run.");
+ if (!query ("Kill the inferior process? "))
+ error ("Not confirmed.");
+ kill_inferior ();
+}
+
+kill_inferior ()
+{
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+ inferior_died ();
+}
+
+inferior_died ()
+{
+ inferior_pid = 0;
+ attach_flag = 0;
+ mark_breakpoints_out ();
+ 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;
+ ptrace (step ? 9 : 7, inferior_pid, 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+}
+
+#ifdef NEW_SUN_PTRACE
+
+/* 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
+
+#ifdef NEW_SUN_PTRACE
+
+void
+fetch_inferior_registers ()
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+ extern char registers[];
+
+ ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers);
+ ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers);
+
+ bcopy (&inferior_registers, registers, 16 * 4);
+ bcopy (&inferior_fp_registers, &registers[REGISTER_BYTE (FP0_REGNUM)],
+ sizeof inferior_fp_registers.fps_regs);
+ *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
+ *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
+ bcopy (&inferior_fp_registers.fps_control,
+ &registers[REGISTER_BYTE (FPC_REGNUM)],
+ sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
+}
+
+/* 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[];
+
+ bcopy (registers, &inferior_registers, 16 * 4);
+ bcopy (&registers[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
+ sizeof inferior_fp_registers.fps_regs);
+ inferior_registers.r_ps = *(int *)&registers[REGISTER_BYTE (PS_REGNUM)];
+ inferior_registers.r_pc = *(int *)&registers[REGISTER_BYTE (PC_REGNUM)];
+ bcopy (&registers[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);
+}
+
+#else
+
+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) & UPAGE_MASK;
+#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];
+
+#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) & UPAGE_MASK;
+#endif
+
+ 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);
+ }
+ }
+}
+
+#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))
+ 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 memnory 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. */
+
+ buffer[0] = ptrace (1, inferior_pid, addr, 0);
+ if (count > 1)
+ buffer[count - 1]
+ = ptrace (1, inferior_pid,
+ addr + (count - 1) * sizeof (int), 0);
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ ptrace (4, inferior_pid, addr, buffer[i]);
+ if (errno)
+ return errno;
+ }
+
+ return 0;
+}
+
+static void
+try_writing_regs_command ()
+{
+ register int i;
+ register int value;
+ extern int errno;
+
+ if (inferior_pid == 0)
+ error ("The program is not being run.");
+
+ for (i = 0; ; i += 2)
+ {
+ QUIT;
+ errno = 0;
+ value = ptrace (3, inferior_pid, i, 0);
+ 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);
+ }
+}
+
+static
+initialize ()
+{
+ 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;
+
+#ifdef SYSV_TTYS
+ ioctl (0, TCGETA, &ti_ours);
+#else
+ ioctl (0, TIOCGETP, &sg_ours);
+ ioctl (0, TIOCGETC, &tc_ours);
+ ioctl (0, TIOCGLTC, &ltc_ours);
+ ioctl (0, TIOCLGET, &lmode_ours);
+#endif
+ fcntl (0, F_GETFL, tflags_ours);
+ ioctl (0, TIOCGPGRP, &pgrp_ours);
+
+ terminal_is_ours = 1;
+}
+
+END_FILE
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d28 1
+a30 1
+#include <sys/user.h>
+d36 11
+d56 4
+d67 2
+d73 3
+d80 1
+d84 3
+d91 1
+d110 4
+d118 1
+d135 3
+d142 1
+d191 3
+d198 1
+d201 11
+a214 3
+
+ fcntl (0, F_SETFL, tflags_ours);
+ fcntl (0, F_SETFL, tflags_ours);
+d220 1
+d228 12
+d251 1
+d470 1
+a470 1
+ offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
+d500 1
+a500 1
+ offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
+d647 3
+d654 1
+@
diff --git a/gdb/RCS/m-mac-aux.h,v b/gdb/RCS/m-mac-aux.h,v
new file mode 100644
index 0000000..eaac3dd
--- /dev/null
+++ b/gdb/RCS/m-mac-aux.h,v
@@ -0,0 +1,523 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.16.06; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.26.05.15.44; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Originally nonexistent, I create it.
+@
+
+
+1.2
+log
+@Original new config file for Mac-II running A/UX.
+@
+text
+@/* Parameters for execution on Macintosh under A/UX, 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 mac_aux
+#define mac_aux
+#endif
+
+/* Get rid of any system-imposed stack limit if possible. */
+
+#undef 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. */
+
+#undef NAMES_HAVE_UNDERSCORE
+
+/* COFF format object files */
+
+#define COFF_FORMAT
+
+/* System eVil ttys */
+
+#define SYSV_TTYS
+
+/* Debugger information will not be in DBX format. */
+
+#undef 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)
+
+/* Address of end of stack space. */
+
+#define STACK_END_ADDR 0x20000000
+
+/* Stack grows downward. */
+
+#define INNER_THAN <
+
+/* Sequence of bytes for breakpoint instruction. */
+
+#define BREAKPOINT {0x4e, 0x4f}
+
+/* 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) == 0x4e76)
+
+/* 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 31
+
+/* 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", "fpcode", "fpflags" }
+
+/* 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+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)
+
+/* 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))
+
+/* Enable use of alternate code to read and write registers. */
+
+#undef NEW_SUN_PTRACE
+
+/* Enable use of alternate code for Sun's format of core dump file. */
+
+#undef NEW_SUN_CORE
+
+/* Do implement the attach and detach commands. */
+
+#undef 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). */
+
+/* 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, 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 + 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.frame); \
+ 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 CORE_ADDR fp = read_register (FP_REGNUM); \
+ register int regnum; \
+ struct frame_saved_regs fsr; \
+ struct frame_info fi; \
+ char raw_buffer[12]; \
+ fi = get_frame_info (fp); \
+ 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); \
+ set_current_frame (read_register (FP_REGNUM)); }
+
+/* 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, 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, fun, nargs) \
+{ *(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.1
+log
+@Initial revision
+@
+text
+@d1 485
+@
diff --git a/gdb/RCS/m-mac-auxinit.h,v b/gdb/RCS/m-mac-auxinit.h,v
new file mode 100644
index 0000000..796bc8d
--- /dev/null
+++ b/gdb/RCS/m-mac-auxinit.h,v
@@ -0,0 +1,43 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.19.09; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.26.05.18.45; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Originally nonexistent.
+@
+
+
+1.2
+log
+@Created by John Gilmore for Mac A/UX
+@
+text
+@
+/* This is how the size of an individual .o file's text segment
+ is rounded on a mac under a/ux. */
+
+#define FILEADDR_ROUND(addr) (addr)
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d1 5
+@
diff --git a/gdb/RCS/m68k-pinsn.c,v b/gdb/RCS/m68k-pinsn.c,v
new file mode 100644
index 0000000..dedc0e7
--- /dev/null
+++ b/gdb/RCS/m68k-pinsn.c,v
@@ -0,0 +1,828 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.08.29; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.21.22.04.55; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@From RMS's development sources on wheaties, 20Jan88
+@
+
+
+1.2
+log
+@Avoid the so-called "portable" preassembled instructions; call a macro
+to generate them, since a/ux assembler uses a different syntax (grumble)
+@
+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 <stdio.h>
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "m68k-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, 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, "<invalid address mode 0%o>", 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. */
+
+#ifdef mac_aux
+#ifdef __STDC__
+#define asm16(str) asm ("short " str#)
+#else
+#define asm16(str) asm ("short str")
+#endif
+#else
+#ifdef __STDC__
+#define asm16(str) asm (".word " str#)
+#else
+#define asm16(str) asm (".word str")
+#endif
+#endif
+
+convert_from_68881 (from, to)
+ char *from;
+ double *to;
+{
+#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. */
+ asm16 (020156);
+ asm16 (8);
+ asm16 (021156);
+ asm16 (12);
+ asm16 (0xf210);
+ asm16 (0x4800);
+ asm16 (0xf211);
+ asm16 (0x7400);
+#endif
+}
+
+/* The converse: convert the double *FROM to an extended float
+ and store where TO points. */
+
+convert_to_68881 (from, to)
+ double *from;
+ char *to;
+{
+#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. */
+ asm16 (020156);
+ asm16 (8);
+ asm16 (021156);
+ asm16 (12);
+ asm16 (0xf210);
+ asm16 (0x5400);
+ asm16 (0xf211);
+ asm16 (0x6800);
+#endif
+}
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d713 14
+d739 8
+a746 6
+ asm (".word 020156");
+ asm (".word 8");
+ asm (".word 021156");
+ asm (".word 12");
+ asm (".long 0xf2104800");
+ asm (".long 0xf2117400");
+d764 8
+a771 6
+ asm (".word 020156");
+ asm (".word 8");
+ asm (".word 021156");
+ asm (".word 12");
+ asm (".long 0xf2105400");
+ asm (".long 0xf2116800");
+@
diff --git a/gdb/RCS/main.c,v b/gdb/RCS/main.c,v
new file mode 100644
index 0000000..ae6615f
--- /dev/null
+++ b/gdb/RCS/main.c,v
@@ -0,0 +1,1110 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.09.12; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.21.04.23.16; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Original from RMS development on wheaties, 20Jan88
+@
+
+
+1.2
+log
+@Add <sys/types.h>
+@
+text
+@/* Top level 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 <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/param.h>
+#include "defs.h"
+#include "command.h"
+#include "param.h"
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+/* Version number of GDB, as a string. */
+
+extern char *version;
+
+/* Chain containing all defined commands. */
+
+struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands. */
+
+struct cmd_list_element *infolist;
+
+/* stdio stream that command input is being read from. */
+
+FILE *instream;
+
+/* 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) ();
+
+void free_command_lines ();
+char *read_line ();
+static void initialize_main ();
+void command_loop ();
+static void source_command ();
+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;
+
+return_to_top_level ()
+{
+ quit_flag = 0;
+ immediate_quit = 0;
+ clear_breakpoint_commands ();
+ clear_momentary_breakpoints ();
+ do_cleanups (0);
+ longjmp (to_top_level, 1);
+}
+
+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;
+
+#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);
+ 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 (argv[i][0] == '-')
+ i++;
+ }
+
+ /* Run the init function of each source file */
+
+ initialize_all_files ();
+ initialize_main (); /* But that omits this file! Do it now */
+
+ signal (SIGINT, request_quit);
+ signal (SIGQUIT, SIG_IGN);
+
+ 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"))
+ /* 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);
+ /* -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)
+ {
+ if (*p)
+ error ("User-defined commands cannot take command-line arguments: \"%s\"",
+ p);
+ cmdlines = (struct command_line *) c->function;
+ if (cmdlines == (struct command_line *) 0)
+ /* Null command */
+ return;
+ while (cmdlines)
+ {
+ execute_command (cmdlines->line, 0);
+ cmdlines = cmdlines->next;
+ }
+ }
+ 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 (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);
+ /* Do any commands attached to breakpoint we stopped at. */
+ do_breakpoint_commands ();
+ do_cleanups (old_chain);
+ }
+}
+
+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;
+}
+
+/* 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 *
+read_line (repeat)
+ 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++;
+ signal (SIGTSTP, stop_sig);
+
+ while (1)
+ {
+ c = fgetc (instream);
+ if (c == -1 || c == '\n')
+ break;
+ if (p - line == linesize - 1)
+ {
+ linesize *= 2;
+ nline = (char *) xrealloc (line, linesize);
+ p += nline - line;
+ line = nline;
+ }
+ *p++ = c;
+ }
+
+ signal (SIGTSTP, SIG_DFL);
+ 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 = read_line (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, 0, 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_cmd (0, 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, cmdlist, "", -2, 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 >= '1' && *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);
+
+ 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\
+\n\
+ Copyright (C) 1986 Richard M. Stallman\n\
+ Everyone is permitted to copy and distribute verbatim copies\n\
+ of this license, but changing it is not allowed.\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);
+ read_line ();
+
+ 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);
+ read_line ();
+
+ 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) 1987 Free Software Foundation, Inc.\" (or with the year updated if\n\
+that is 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);
+ read_line ();
+
+ 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 third\n\
+ 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) 1987 Free Software Foundation, Inc.\" (or with\n\
+ the year updated if appropriate), saying that there\n\
+ is no warranty (or else, saying that you provide\n\
+ a warranty) and that users may redistribute the program under\n\
+ these conditions, and telling the user how to view a copy of\n\
+ 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\
+--Type Return to print more--");
+ fflush (stdout);
+ read_line ();
+
+ printf ("\
+ 3. You may copy and distribute GDB or any portion of it in\n\
+compiled, executable or object code form under the terms of Paragraphs\n\
+1 and 2 above provided that you do the following:\n\
+\n\
+ a) cause each such copy to be accompanied by the\n\
+ corresponding machine-readable source code, which must\n\
+ be distributed under the terms of Paragraphs 1 and 2 above; or,\n\
+\n\
+ b) cause each such copy to be accompanied by a\n\
+ written offer, with no time limit, to give any third party\n\
+ free (except for a nominal shipping charge) a machine readable\n\
+ copy of the corresponding source code, to be distributed\n\
+ under the terms of Paragraphs 1 and 2 above; or,\n\n");
+
+ printf ("\
+ c) in the case of a recipient of GDB in compiled, executable\n\
+ or object code form (without the corresponding source code) you\n\
+ shall cause copies you distribute to be accompanied by a copy\n\
+ of the written offer of source code which you received along\n\
+ with the copy you received.\n\
+--Type Return to print more--");
+ fflush (stdout);
+ read_line ();
+
+ 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\
+ 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) 1987 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--;
+}
+
+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;
+{
+ char buf[MAXPATHLEN];
+ if (arg) error ("The \"pwd\" command does not take an argument: %s", arg);
+ printf ("Working directory %s.\n", getwd (buf));
+}
+
+static void
+cd_command (dir, from_tty)
+ char *dir;
+ int from_tty;
+{
+ if (dir == 0)
+ error_no_arg ("new working directory");
+
+ if (chdir (dir) < 0)
+ perror_with_name (dir);
+ if (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;
+{
+ 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
+initialize_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_com ("set-prompt", class_support, set_prompt_command,
+ "Change gdb's prompt from the default of \"(gdb)\"");
+ 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
+@d21 1
+@
diff --git a/gdb/RCS/source.c,v b/gdb/RCS/source.c,v
new file mode 100644
index 0000000..bd3218b
--- /dev/null
+++ b/gdb/RCS/source.c,v
@@ -0,0 +1,705 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.09.34; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.21.04.30.11; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Original from RMS development sources on wheaties, 20Jan88
+@
+
+
+1.2
+log
+@Add <sys/types.h>
+@
+text
+@/* List lines of source files 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#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. */
+
+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 for "info line" to work on if no line specified. */
+
+static int line_info_default_line;
+
+/* First line number listed by last listing command. */
+
+static int first_line_listed;
+
+START_FILE
+
+/* Set the source file default for the "list" command,
+ specifying a symtab. */
+
+void
+select_source_symtab (s)
+ register struct symtab *s;
+{
+ if (s)
+ {
+ 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))
+ {
+ sal = decode_line_spec ("main", 1);
+ 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;
+ 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;
+ }
+}
+
+static void
+directories_info ()
+{
+ printf ("Source directories searched: %s\n", source_path);
+}
+
+static void
+init_source_path ()
+{
+ register struct symtab *s;
+ char wd[MAXPATHLEN];
+ if (getwd (wd) == NULL)
+ perror_with_name ("getwd");
+
+ source_path = savestring (wd, strlen (wd));
+
+ /* 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;
+
+ char wd[MAXPATHLEN];
+ if (getwd (wd) == NULL)
+ perror_with_name ("getwd");
+
+ if (dirname == 0)
+ {
+ if (query ("Reinitialize source path to %s? ", wd))
+ {
+ 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 = wd;
+ 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 (wd, "/", 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
+ {
+ char dirname[MAXPATHLEN];
+ if (getwd (dirname) == NULL)
+ perror_with_name ("getwd");
+ *filename_opened = concat (dirname, "/", 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 && 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')
+ {
+ if (nlines == lines_allocated)
+ line_charpos = (int *) xrealloc (line_charpos,
+ sizeof (int) * (lines_allocated *= 2));
+ 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, fullname);
+ if (desc < 0)
+ {
+ *fullname = NULL;
+ return 0;
+ }
+ if (s->line_charpos == 0) linenums_changed = 1;
+ if (linenums_changed) find_source_lines (s, desc);
+ close (desc);
+ return linenums_changed;
+}
+
+/* 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)
+ struct symtab *s;
+ int line, stopline;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int nlines = stopline - line;
+
+ desc = openp (source_path, 0, s->filename, O_RDONLY, 0, (char **) 0);
+ if (desc < 0)
+ perror_with_name (s->filename);
+
+ 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;
+ line_info_default_line = 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);
+}
+
+static void
+list_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ 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)
+ error ("Listing source lines requires symbols.");
+
+ /* "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);
+ 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);
+ 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
+ sal = decode_line_1 (&arg1, 0, 0, 0);
+
+ /* 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)
+ sal_end = decode_line_1 (&arg1, 0, 0, 0);
+ else
+ sal_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
+ }
+
+ 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);
+ 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);
+ else
+ print_source_lines (sal.symtab, sal.line,
+ dummy_end ? sal.line + 10 : sal_end.line + 1);
+}
+
+/* Print info on range of pc's in a specified line. */
+
+static void
+line_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtab_and_line sal;
+ int start_pc, end_pc;
+
+ if (arg == 0)
+ {
+ sal.symtab = current_source_symtab;
+ sal.line = line_info_default_line;
+ }
+ else
+ {
+ sal = decode_line_spec (arg);
+
+ /* 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))
+ {
+ 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. */
+ line_info_default_line = sal.line + 1;
+ }
+ else
+ printf ("Line number %d is out of range for \"%s\".\n",
+ sal.line, sal.symtab->filename);
+}
+
+static
+initialize ()
+{
+ 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 ("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.");
+}
+
+END_FILE
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d22 1
+@
diff --git a/gdb/RCS/symmisc.c,v b/gdb/RCS/symmisc.c,v
new file mode 100644
index 0000000..42653dfb
--- /dev/null
+++ b/gdb/RCS/symmisc.c,v
@@ -0,0 +1,575 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.09.53; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.26.04.25.22; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Original from RMS's devl sources on wheaties
+@
+
+
+1.2
+log
+@Check for null pointer passed to free()...
+@
+text
+@/* Do various things to symbol tables (other than lookup)), 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 "defs.h"
+#include "initialize.h"
+#include "symtab.h"
+
+#include <stdio.h>
+#include <obstack.h>
+
+static void free_symtab ();
+
+START_FILE
+
+/* Free all the symtabs that are currently installed,
+ and all storage associated with them.
+ Leaves us in a consistent state with no symtabs installed. */
+
+void
+free_all_symtabs ()
+{
+ register struct symtab *s, *snext;
+
+ /* All values will be invalid because their types will be! */
+
+ clear_value_history ();
+ clear_displays ();
+ clear_internalvars ();
+ clear_breakpoints ();
+ set_default_breakpoint (0, 0, 0, 0);
+
+ current_source_symtab = 0;
+
+ for (s = symtab_list; s; s = snext)
+ {
+ snext = s->next;
+ free_symtab (s);
+ }
+ symtab_list = 0;
+ obstack_free (symbol_obstack, 0);
+ obstack_init (symbol_obstack);
+
+ if (misc_function_vector)
+ free (misc_function_vector);
+ misc_function_count = 0;
+ misc_function_vector = 0;
+}
+
+/* Free a struct block <- B and all the symbols defined in that block. */
+
+static void
+free_symtab_block (b)
+ struct block *b;
+{
+ register int i, n;
+ n = BLOCK_NSYMS (b);
+ for (i = 0; i < n; i++)
+ {
+ free (SYMBOL_NAME (BLOCK_SYM (b, i)));
+ free (BLOCK_SYM (b, i));
+ }
+ free (b);
+}
+
+/* Free all the storage associated with the struct symtab <- S.
+ Note that some symtabs have contents malloc'ed structure by structure,
+ while some have contents that all live inside one big block of memory,
+ and some share the contents of another symbol table and so you should
+ not free the contents on their behalf (except sometimes the linetable,
+ which maybe per symtab even when the rest is not).
+ It is s->free_code that says which alternative to use. */
+
+static void
+free_symtab (s)
+ register struct symtab *s;
+{
+ register int i, n;
+ register struct blockvector *bv;
+ register struct type *type;
+ register struct typevector *tv;
+
+ switch (s->free_code)
+ {
+ case free_nothing:
+ /* All the contents are part of a big block of memory
+ and some other symtab is in charge of freeing that block.
+ Therefore, do nothing. */
+ break;
+
+ case free_explicit:
+ /* All the contents are part of a big block of memory
+ and that is our `free_ptr' and will be freed below. */
+ break;
+
+ case free_contents:
+ /* Here all the contents were malloc'ed structure by structure
+ and must be freed that way. */
+ /* First free the blocks (and their symbols. */
+ bv = BLOCKVECTOR (s);
+ n = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < n; i++)
+ free_symtab_block (BLOCKVECTOR_BLOCK (bv, i));
+ /* Free the blockvector itself. */
+ free (bv);
+ /* Free the type vector. */
+ tv = TYPEVECTOR (s);
+ if (tv) /* FIXME, should this happen? It does... */
+ free (tv);
+ /* Also free the linetable. */
+
+ case free_linetable:
+ /* Everything will be freed either by our `free_ptr'
+ or by some other symbatb, except for our linetable.
+ Free that now. */
+ free (LINETABLE (s));
+ break;
+ }
+
+ /* If there is a single block of memory to free, free it. */
+ if (s->free_ptr)
+ free (s->free_ptr);
+
+ if (s->line_charpos)
+ free (s->line_charpos);
+ free (s->filename);
+ free (s);
+}
+
+/* Convert a raw symbol-segment to a struct symtab,
+ and relocate its internal pointers so that it is valid. */
+
+/* This is how to relocate one pointer, given a name for it.
+ Works independent of the type of object pointed to. */
+#define RELOCATE(slot) (slot ? (* (char **) &slot += relocation) : 0)
+
+/* This is the inverse of RELOCATE. We use it when storing
+ a core address into a slot that has yet to be relocated. */
+#define UNRELOCATE(slot) (slot ? (* (char **) &slot -= relocation) : 0)
+
+/* During the process of relocation, this holds the amount to relocate by
+ (the address of the file's symtab data, in core in the debugger). */
+static int relocation;
+
+#define CORE_RELOCATE(slot) \
+ ((slot) += (((slot) < data_start) ? text_relocation \
+ : ((slot) < bss_start) ? data_relocation : bss_relocation))
+
+#define TEXT_RELOCATE(slot) ((slot) += text_relocation)
+
+/* Relocation amounts for addresses in the program's core image. */
+static int text_relocation, data_relocation, bss_relocation;
+
+/* Boundaries that divide program core addresses into text, data and bss;
+ used to determine which relocation amount to use. */
+static int data_start, bss_start;
+
+static void relocate_typevector ();
+static void relocate_blockvector ();
+static void relocate_type ();
+static void relocate_block ();
+static void relocate_symbol ();
+
+/* Relocate a file symbol table so that all the pointers
+ are valid C pointers. Pass the struct symtab for the file
+ and the amount to relocate by. */
+
+static struct symtab *
+relocate_symtab (root)
+ struct symbol_root *root;
+{
+ struct symtab *sp = (struct symtab *) xmalloc (sizeof (struct symtab));
+ bzero (sp, sizeof (struct symtab));
+
+ relocation = (int) root;
+ text_relocation = root->textrel;
+ data_relocation = root->datarel;
+ bss_relocation = root->bssrel;
+ data_start = root->databeg;
+ bss_start = root->bssbeg;
+
+ sp->filename = root->filename;
+ sp->ldsymoff = root->ldsymoff;
+ sp->language = root->language;
+ sp->compilation = root->compilation;
+ sp->version = root->version;
+ sp->blockvector = root->blockvector;
+ sp->typevector = root->typevector;
+ sp->free_code = free_explicit;
+ sp->free_ptr = (char *) root;
+
+ RELOCATE (TYPEVECTOR (sp));
+ RELOCATE (BLOCKVECTOR (sp));
+ RELOCATE (sp->version);
+ RELOCATE (sp->compilation);
+ RELOCATE (sp->filename);
+
+ relocate_typevector (TYPEVECTOR (sp));
+ relocate_blockvector (BLOCKVECTOR (sp));
+
+ return sp;
+}
+
+static void
+relocate_typevector (tv)
+ struct typevector *tv;
+{
+ register int ntypes = TYPEVECTOR_NTYPES (tv);
+ register int i;
+
+ for (i = 0; i < ntypes; i++)
+ RELOCATE (TYPEVECTOR_TYPE (tv, i));
+ for (i = 0; i < ntypes; i++)
+ relocate_type (TYPEVECTOR_TYPE (tv, i));
+}
+
+static void
+relocate_blockvector (blp)
+ register struct blockvector *blp;
+{
+ register int nblocks = BLOCKVECTOR_NBLOCKS (blp);
+ register int i;
+ for (i = 0; i < nblocks; i++)
+ RELOCATE (BLOCKVECTOR_BLOCK (blp, i));
+ for (i = 0; i < nblocks; i++)
+ relocate_block (BLOCKVECTOR_BLOCK (blp, i));
+}
+
+static void
+relocate_block (bp)
+ register struct block *bp;
+{
+ register int nsyms = BLOCK_NSYMS (bp);
+ register int i;
+
+ TEXT_RELOCATE (BLOCK_START (bp));
+ TEXT_RELOCATE (BLOCK_END (bp));
+
+ /* These two should not be recursively processed.
+ The superblock need not be because all blocks are
+ processed from relocate_blockvector.
+ The function need not be because it will be processed
+ under the block which is its scope. */
+ RELOCATE (BLOCK_SUPERBLOCK (bp));
+ RELOCATE (BLOCK_FUNCTION (bp));
+
+ for (i = 0; i < nsyms; i++)
+ RELOCATE (BLOCK_SYM (bp, i));
+
+ for (i = 0; i < nsyms; i++)
+ relocate_symbol (BLOCK_SYM (bp, i));
+}
+
+static void
+relocate_symbol (sp)
+ register struct symbol *sp;
+{
+ RELOCATE (SYMBOL_NAME (sp));
+ if (SYMBOL_CLASS (sp) == LOC_BLOCK)
+ {
+ RELOCATE (SYMBOL_BLOCK_VALUE (sp));
+ /* We can assume the block that belongs to this symbol
+ is not relocated yet, since it comes after
+ the block that contains this symbol. */
+ BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp)) = sp;
+ UNRELOCATE (BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp)));
+ }
+ else if (SYMBOL_CLASS (sp) == LOC_STATIC)
+ CORE_RELOCATE (SYMBOL_VALUE (sp));
+ else if (SYMBOL_CLASS (sp) == LOC_LABEL)
+ TEXT_RELOCATE (SYMBOL_VALUE (sp));
+ RELOCATE (SYMBOL_TYPE (sp));
+}
+
+/* We cannot come up with an a priori spanning tree
+ for the network of types, since types can be used
+ for many symbols and also as components of other types.
+ Therefore, we need to be able to mark types that we
+ already have relocated (or are already in the middle of relocating)
+ as in a garbage collector. */
+
+static void
+relocate_type (tp)
+ register struct type *tp;
+{
+ register int nfields = TYPE_NFIELDS (tp);
+ register int i;
+
+ RELOCATE (TYPE_NAME (tp));
+ RELOCATE (TYPE_TARGET_TYPE (tp));
+ RELOCATE (TYPE_FIELDS (tp));
+ RELOCATE (TYPE_POINTER_TYPE (tp));
+
+ for (i = 0; i < nfields; i++)
+ {
+ RELOCATE (TYPE_FIELD_TYPE (tp, i));
+ RELOCATE (TYPE_FIELD_NAME (tp, i));
+ }
+}
+
+/* Read symsegs from file named NAME open on DESC,
+ make symtabs from them, and return a chain of them.
+ Assumes DESC is prepositioned at the end of the string table,
+ just before the symsegs if there are any. */
+
+struct symtab *
+read_symsegs (desc, name)
+ int desc;
+ char *name;
+{
+ struct symbol_root root;
+ register char *data;
+ register struct symtab *sp, *chain = 0;
+ register int len;
+
+ while (1)
+ {
+ len = myread (desc, &root, sizeof root);
+ if (len == 0 || root.format == 0)
+ break;
+ if (root.format != 1 ||
+ root.length < sizeof root)
+ error ("Invalid symbol segment format code");
+ data = (char *) xmalloc (root.length);
+ bcopy (&root, data, sizeof root);
+ len = myread (desc, data + sizeof root,
+ root.length - sizeof root);
+ sp = relocate_symtab (data);
+ sp->next = chain;
+ chain = sp;
+ }
+
+ return chain;
+}
+
+static int block_depth ();
+static void print_spaces ();
+static void print_symbol ();
+
+print_symtabs (filename)
+ char *filename;
+{
+ FILE *outfile;
+ register struct symtab *s;
+ register int i, j;
+ int len, line, blen;
+ register struct linetable *l;
+ struct blockvector *bv;
+ register struct block *b;
+ int depth;
+ struct cleanup *cleanups;
+ extern int fclose();
+
+ if (filename == 0)
+ error_no_arg ("file to write symbol data in");
+ outfile = fopen (filename, "w");
+
+ cleanups = make_cleanup (fclose, outfile);
+ immediate_quit++;
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ /* First print the line table. */
+ fprintf (outfile, "Symtab for file %s\n\n", s->filename);
+ fprintf (outfile, "Line table:\n\n");
+ l = LINETABLE (s);
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ {
+ if (l->item[i] < 0)
+ line = - l->item[i] - 1;
+ else
+ fprintf (outfile, " line %d at %x\n", ++line, l->item[i]);
+ }
+ /* Now print the block info. */
+ fprintf (outfile, "\nBlockvector:\n\n");
+ bv = BLOCKVECTOR (s);
+ len = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < len; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ depth = block_depth (b) * 2;
+ print_spaces (depth, outfile);
+ fprintf (outfile, "block #%03d (object 0x%x) ", i, b);
+ fprintf (outfile, "[0x%x..0x%x]", BLOCK_START (b), BLOCK_END (b));
+ if (BLOCK_SUPERBLOCK (b))
+ fprintf (outfile, " (under 0x%x)", BLOCK_SUPERBLOCK (b));
+ if (BLOCK_FUNCTION (b))
+ fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b)));
+ fputc ('\n', outfile);
+ blen = BLOCK_NSYMS (b);
+ for (j = 0; j < blen; j++)
+ {
+ print_symbol (BLOCK_SYM (b, j), depth + 1, outfile);
+ }
+ }
+
+ fprintf (outfile, "\n\n");
+ }
+
+ immediate_quit--;
+ do_cleanups (cleanups);
+}
+
+static void
+print_symbol (symbol, depth, outfile)
+ struct symbol *symbol;
+ int depth;
+ FILE *outfile;
+{
+ print_spaces (depth, outfile);
+ if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE)
+ {
+ fprintf (outfile, "label %s at 0x%x", SYMBOL_NAME (symbol),
+ SYMBOL_VALUE (symbol));
+ return;
+ }
+ if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE)
+ {
+ if (TYPE_NAME (SYMBOL_TYPE (symbol)))
+ {
+ type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+ }
+ else
+ {
+ fprintf (outfile, "%s %s = ",
+ (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM
+ ? "enum"
+ : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT
+ ? "struct" : "union")),
+ SYMBOL_NAME (symbol));
+ type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+ }
+ fprintf (outfile, ";\n");
+ }
+ else
+ {
+ if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF)
+ fprintf (outfile, "typedef ");
+ if (SYMBOL_TYPE (symbol))
+ {
+ type_print_1 (SYMBOL_TYPE (symbol), SYMBOL_NAME (symbol),
+ outfile, 1, depth);
+ fprintf (outfile, "; ");
+ }
+ else
+ fprintf (outfile, "%s ", SYMBOL_NAME (symbol));
+
+ switch (SYMBOL_CLASS (symbol))
+ {
+ case LOC_CONST:
+ fprintf (outfile, "const %d (0x%x),",
+ SYMBOL_VALUE (symbol), SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_CONST_BYTES:
+ fprintf (outfile, "const %d hex bytes:",
+ TYPE_LENGTH (SYMBOL_TYPE (symbol)));
+ {
+ int i;
+ for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++)
+ fprintf (outfile, " %2x", SYMBOL_VALUE_BYTES (symbol) [i]);
+ fprintf (outfile, ",");
+ }
+ break;
+
+ case LOC_STATIC:
+ fprintf (outfile, "static at 0x%x,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGISTER:
+ fprintf (outfile, "register %d,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_ARG:
+ fprintf (outfile, "arg at 0x%x,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_LOCAL:
+ fprintf (outfile, "local at 0x%x,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_TYPEDEF:
+ break;
+
+ case LOC_LABEL:
+ fprintf (outfile, "label at 0x%x", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_BLOCK:
+ fprintf (outfile, "block (object 0x%x) starting at 0x%x,",
+ SYMBOL_VALUE (symbol),
+ BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)));
+ break;
+ }
+ }
+ fprintf (outfile, "\n");
+}
+
+/* Return the nexting depth of a block within other blocks in its symtab. */
+
+static int
+block_depth (block)
+ struct block *block;
+{
+ register int i = 0;
+ while (block = BLOCK_SUPERBLOCK (block)) i++;
+ return i;
+}
+
+static
+initialize ()
+{
+ add_com ("printsyms", class_obscure, print_symtabs,
+ "Print dump of current symbol definitions to file OUTFILE.");
+}
+
+END_FILE
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d125 2
+a126 1
+ free (tv);
+@
diff --git a/gdb/RCS/symtab.c,v b/gdb/RCS/symtab.c,v
new file mode 100644
index 0000000..7ccdaac
--- /dev/null
+++ b/gdb/RCS/symtab.c,v
@@ -0,0 +1,1153 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.10.33; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.26.02.18.56; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@Original from RMS's wheaties devel sources
+@
+
+
+1.2
+log
+@Permit SYS V regular expression library as well as real Unix one.
+@
+text
+@/* Symbol table lookup for the GNU debugger, 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 "defs.h"
+#include "initialize.h"
+#include "symtab.h"
+#include "param.h"
+
+#include <stdio.h>
+#include <obstack.h>
+
+#ifdef mac_aux
+#define REGCMP
+#endif
+
+START_FILE
+
+/* Allocate an obstack to hold objects that should be freed
+ when we load a new symbol table.
+ This includes the symbols made by dbxread
+ and the types that are not permanent. */
+
+struct obstack obstack1;
+
+struct obstack *symbol_obstack = &obstack1;
+
+/* These variables point to the objects
+ representing the predefined C data types. */
+
+struct type *builtin_type_void;
+struct type *builtin_type_char;
+struct type *builtin_type_short;
+struct type *builtin_type_int;
+struct type *builtin_type_long;
+struct type *builtin_type_unsigned_char;
+struct type *builtin_type_unsigned_short;
+struct type *builtin_type_unsigned_int;
+struct type *builtin_type_unsigned_long;
+struct type *builtin_type_float;
+struct type *builtin_type_double;
+
+/* Lookup the symbol table of a source file named NAME. */
+
+struct symtab *
+lookup_symtab (name)
+ char *name;
+{
+ register struct symtab *s;
+ register char *copy;
+
+ for (s = 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 = symtab_list; s; s = s->next)
+ if (!strcmp (copy, s->filename))
+ return s;
+
+ return 0;
+}
+
+/* Lookup a typedef or primitive type named NAME,
+ visible in lexical block BLOCK.
+ If NOERR is nonzero, return zero if NAME is not suitably defined. */
+
+struct type *
+lookup_typename (name, block, noerr)
+ char *name;
+ struct block *block;
+ int noerr;
+{
+ register struct symbol *sym = lookup_symbol (name, block, VAR_NAMESPACE);
+ if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ {
+ if (!strcmp (name, "int"))
+ return builtin_type_int;
+ if (!strcmp (name, "long"))
+ return builtin_type_long;
+ if (!strcmp (name, "short"))
+ return builtin_type_short;
+ if (!strcmp (name, "char"))
+ return builtin_type_char;
+ if (!strcmp (name, "float"))
+ return builtin_type_float;
+ if (!strcmp (name, "double"))
+ return builtin_type_double;
+ if (!strcmp (name, "void"))
+ return builtin_type_void;
+
+ if (noerr)
+ return 0;
+ error ("No type named %s.", name);
+ }
+ return SYMBOL_TYPE (sym);
+}
+
+struct type *
+lookup_unsigned_typename (name)
+ char *name;
+{
+ if (!strcmp (name, "int"))
+ return builtin_type_unsigned_int;
+ if (!strcmp (name, "long"))
+ return builtin_type_unsigned_long;
+ if (!strcmp (name, "short"))
+ return builtin_type_unsigned_short;
+ if (!strcmp (name, "char"))
+ return builtin_type_unsigned_char;
+ error ("No type named unsigned %s.", name);
+}
+
+/* Lookup a structure type named "struct NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_struct (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE);
+ 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);
+ return SYMBOL_TYPE (sym);
+}
+
+/* Lookup a union type named "union NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_union (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE);
+ 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);
+ return SYMBOL_TYPE (sym);
+}
+
+/* Lookup an enum type named "enum NAME",
+ visible in lexical block BLOCK. */
+
+struct type *
+lookup_enum (name, block)
+ char *name;
+ struct block *block;
+{
+ register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE);
+ 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);
+ return SYMBOL_TYPE (sym);
+}
+
+/* Given a type TYPE, return a type of pointers to that type.
+ May need to construct such a type if this is the first use. */
+
+struct type *
+lookup_pointer_type (type)
+ struct type *type;
+{
+ register struct type *ptype = TYPE_POINTER_TYPE (type);
+ if (ptype) return ptype;
+
+ /* This is the first time anyone wanted a pointer to a TYPE. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ ptype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ ptype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (ptype, sizeof (struct type));
+ TYPE_TARGET_TYPE (ptype) = type;
+ TYPE_POINTER_TYPE (type) = ptype;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (ptype) = sizeof (char *);
+ TYPE_CODE (ptype) = TYPE_CODE_PTR;
+ return ptype;
+}
+
+/* Given a type TYPE, return a type of functions that return that type.
+ May need to construct such a type if this is the first use. */
+
+struct type *
+lookup_function_type (type)
+ struct type *type;
+{
+ register struct type *ptype = TYPE_FUNCTION_TYPE (type);
+ if (ptype) return ptype;
+
+ /* This is the first time anyone wanted a function returning a TYPE. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ ptype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ ptype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (ptype, sizeof (struct type));
+ TYPE_TARGET_TYPE (ptype) = type;
+ TYPE_FUNCTION_TYPE (type) = ptype;
+ /* New type is permanent if type returned is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
+ TYPE_LENGTH (ptype) = 1;
+ TYPE_CODE (ptype) = TYPE_CODE_FUNC;
+ TYPE_NFIELDS (ptype) = 0;
+ return ptype;
+}
+
+/* Smash TYPE to be a type of pointers to TO_TYPE.
+ If TO_TYPE is not permanent and has no pointer-type yet,
+ record TYPE as its pointer-type. */
+
+void
+smash_to_pointer_type (type, to_type)
+ struct type *type, *to_type;
+{
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (type) = sizeof (char *);
+ TYPE_CODE (type) = TYPE_CODE_PTR;
+
+ if (TYPE_POINTER_TYPE (to_type) == 0
+ && !(TYPE_FLAGS (type) & TYPE_FLAG_PERM))
+ {
+ TYPE_POINTER_TYPE (to_type) = type;
+ }
+}
+
+/* Smash TYPE to be a type of functions returning TO_TYPE.
+ If TO_TYPE is not permanent and has no function-type yet,
+ record TYPE as its function-type. */
+
+void
+smash_to_function_type (type, to_type)
+ struct type *type, *to_type;
+{
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_LENGTH (type) = 1;
+ TYPE_CODE (type) = TYPE_CODE_FUNC;
+ TYPE_NFIELDS (type) = 0;
+
+ if (TYPE_FUNCTION_TYPE (to_type) == 0
+ && !(TYPE_FLAGS (type) & TYPE_FLAG_PERM))
+ {
+ TYPE_FUNCTION_TYPE (to_type) = type;
+ }
+}
+
+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. */
+
+struct symbol *
+lookup_symbol (name, block, namespace)
+ char *name;
+ register struct block *block;
+ enum namespace namespace;
+{
+ register int i, n;
+ register struct symbol *sym;
+ register struct symtab *s;
+ struct blockvector *bv;
+
+ /* Search specified block and its superiors. */
+
+ while (block != 0)
+ {
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym) return sym;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ /* Now search all symtabs' global blocks. */
+
+ 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;
+ }
+
+ /* Now search all symtabs' per-file blocks.
+ Not strictly correct, but more useful than an error. */
+
+ 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;
+ }
+ return 0;
+}
+
+/* Look for a symbol in block BLOCK using binary search. */
+
+static struct symbol *
+lookup_block_symbol (block, name, namespace)
+ register struct block *block;
+ char *name;
+ enum namespace namespace;
+{
+ register int bot, top, inc;
+ register struct symbol *sym;
+
+ top = BLOCK_NSYMS (block);
+ bot = 0;
+
+ /* First, advance BOT to not far before
+ the first symbol whose name is NAME. */
+
+ while (1)
+ {
+ inc = (top - bot + 1);
+ /* No need to keep binary searching for the last few bits worth. */
+ if (inc < 7)
+ break;
+ inc >>= 1;
+ sym = BLOCK_SYM (block, bot + inc);
+ if (strcmp (SYMBOL_NAME (sym), name) < 0)
+ bot += inc;
+ else
+ top = bot + inc;
+ }
+
+ /* Now scan forward until we run out of symbols,
+ find one whose name is greater than NAME,
+ or find one we want.
+ If there is more than one symbol with the right name and namespace,
+ we return the first one. dbxread.c is careful to make sure
+ that if one is a register then it comes first. */
+
+ top = BLOCK_NSYMS (block);
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ inc = strcmp (SYMBOL_NAME (sym), name);
+ if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace)
+ return sym;
+ if (inc > 0)
+ return 0;
+ bot++;
+ }
+ return 0;
+}
+
+/* Return the symbol for the function which contains a specified
+ lexical block, described by a struct block BL. */
+
+struct symbol *
+block_function (bl)
+ struct block *bl;
+{
+ while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
+/* Subroutine of find_pc_line */
+
+static struct symtab *
+find_pc_symtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct block *b;
+ struct blockvector *bv;
+ register struct symtab *s;
+
+ /* Search all symtabs for one whose file contains our pc */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, 0);
+ if (BLOCK_START (b) <= pc
+ && BLOCK_END (b) > pc)
+ break;
+ }
+
+ return s;
+}
+
+/* Find the source file and line number for a given PC value.
+ Return a structure containing a symtab pointer, a line number,
+ and a pc range for the entire source line.
+ The value's .pc field is NOT the specified pc.
+ NOTCURRENT nonzero means, if specified pc is on a line boundary,
+ use the line that ends there. Otherwise, in that case, the line
+ that begins there is used. */
+
+struct symtab_and_line
+find_pc_line (pc, notcurrent)
+ CORE_ADDR pc;
+ int notcurrent;
+{
+ struct symtab *s;
+ register struct linetable *l;
+ register int len;
+ register int i, item;
+ int line;
+ struct symtab_and_line value;
+ struct blockvector *bv;
+
+ /* Info on best line seen so far, and where it starts, and its file. */
+
+ int best_line = 0;
+ CORE_ADDR best_pc = 0;
+ CORE_ADDR best_end = 0;
+ struct symtab *best_symtab = 0;
+
+ /* Store here the first line number
+ of a file which contains the line at the smallest pc after PC.
+ If we don't find a line whose range contains PC,
+ we will use a line one less than this,
+ with a range from the start of that file to the first line's pc. */
+ int alt_line = 0;
+ CORE_ADDR alt_pc = 0;
+ struct symtab *alt_symtab = 0;
+
+ /* Info on best line seen in this file. */
+
+ int prev_line;
+ CORE_ADDR prev_pc;
+
+ /* Info on first line of this file. */
+
+ int first_line;
+ CORE_ADDR first_pc;
+
+ /* If this pc is not from the current frame,
+ it is the address of the end of a call instruction.
+ Quite likely that is the start of the following statement.
+ But what we want is the statement containing the instruction.
+ Fudge the pc to make sure we get that. */
+
+ if (notcurrent) pc -= 1;
+
+ s = find_pc_symtab (pc);
+ if (s == 0)
+ {
+ value.symtab = 0;
+ value.line = 0;
+ value.pc = pc;
+ return value;
+ }
+
+ bv = BLOCKVECTOR (s);
+
+ /* Look at all the symtabs that share this blockvector.
+ They all have the same apriori range, that we found was right;
+ but they have different line tables. */
+
+ for (; s && BLOCKVECTOR (s) == bv; s = s->next)
+ {
+ /* Find the best line in this symtab. */
+ l = LINETABLE (s);
+ len = l->nitems;
+ prev_line = -1;
+ first_line = -1;
+ for (i = 0; i < len; i++)
+ {
+ item = l->item[i];
+ if (item < 0)
+ line = - item - 1;
+ else
+ {
+ 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;
+ }
+ }
+
+ /* Is this file's best line closer than the best in the other files?
+ If so, record this file, and its best line, as best so far. */
+ if (prev_line >= 0 && prev_pc > best_pc)
+ {
+ best_pc = prev_pc;
+ best_line = prev_line;
+ best_symtab = s;
+ if (i < len)
+ best_end = item;
+ else
+ best_end = 0;
+ }
+ /* Is this file's first line closer than the first lines of other files?
+ If so, record this file, and its first line, as best alternate. */
+ if (first_line >= 0 && first_pc > pc
+ && (alt_pc == 0 || first_pc < alt_pc))
+ {
+ alt_pc = first_pc;
+ alt_line = first_line;
+ alt_symtab = s;
+ }
+ }
+ if (best_symtab == 0)
+ {
+ value.symtab = alt_symtab;
+ value.line = alt_line - 1;
+ value.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0));
+ value.end = alt_pc;
+ }
+ else
+ {
+ value.symtab = best_symtab;
+ value.line = best_line;
+ value.pc = best_pc;
+ value.end = (best_end ? best_end
+ : (alt_pc ? alt_pc
+ : BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0))));
+ }
+ return value;
+}
+
+/* Find the range of pc values in a line.
+ Store the starting pc of the line into *STARTPTR
+ and the ending pc (start of next line) into *ENDPTR.
+ Returns 1 to indicate success.
+ Returns 0 if could not find the specified line. */
+
+int
+find_line_pc_range (symtab, thisline, startptr, endptr)
+ struct symtab *symtab;
+ int thisline;
+ CORE_ADDR *startptr, *endptr;
+{
+ register struct linetable *l;
+ register int i, line, item;
+ int len;
+ register CORE_ADDR prev_pc;
+ CORE_ADDR last_pc;
+
+ if (symtab == 0)
+ return 0;
+
+ l = LINETABLE (symtab);
+ len = l->nitems;
+ prev_pc = -1;
+ for (i = 0; i < len; i++)
+ {
+ item = l->item[i];
+ if (item < 0)
+ line = - item - 1;
+ else
+ {
+ line++;
+ /* As soon as we find a line following the specified one
+ we know the end pc and can return. */
+ if (line > thisline)
+ {
+ /* If we have not seen an entry for the specified line,
+ assume that means the specified line has zero bytes. */
+ *startptr = prev_pc == -1 ? item : prev_pc;
+ *endptr = item;
+ return 1;
+ }
+ /* If we see an entry for the specified line,
+ it gives the beginning. */
+ if (line == thisline)
+ prev_pc = item;
+ last_pc = item;
+ }
+ }
+ if (prev_pc != -1)
+ {
+ /* If we found the specified line but no later line, it's file's last.
+ Its range is from line's pc to file's end pc. */
+ *startptr = last_pc;
+ *endptr = BLOCK_END (BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), 0));
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Find the PC value for a given source file and line number.
+ Returns zero for invalid line number.
+ The source file is specified with a struct symtab. */
+
+CORE_ADDR
+find_line_pc (symtab, line)
+ struct symtab *symtab;
+ int line;
+{
+ register struct linetable *l;
+ register int len;
+ register int i;
+ register int item;
+ register int nextline = -1;
+
+ if (line <= 0)
+ return 0;
+
+ l = LINETABLE (symtab);
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ {
+ item = l->item[i];
+ if (item < 0)
+ nextline = - item - 1;
+ else
+ {
+ nextline++;
+ if (line <= nextline)
+ return item;
+ }
+ }
+ return 0;
+}
+
+int
+find_pc_line_pc_range (pc, startptr, endptr)
+ CORE_ADDR pc;
+ CORE_ADDR *startptr, *endptr;
+{
+ struct symtab_and_line sal;
+ sal = find_pc_line (pc, 0);
+ *startptr = sal.pc;
+ *endptr = sal.end;
+ return sal.symtab != 0;
+}
+
+/* Parse a string that specifies a line number.
+ Pass the address of a char * variable; that variable will be
+ advanced over the characters actually parsed.
+
+ The string can be:
+
+ LINENUM -- that line number in current file. PC returned is 0.
+ FILE:LINENUM -- that line in that file. PC returned is 0.
+ FUNCTION -- line number of openbrace of that function.
+ PC returned is the start of the function.
+ FILE:FUNCTION -- likewise, but prefer functions in that file.
+ *EXPR -- line in which address EXPR appears.
+
+ FUNCTION may be an undebuggable function found in misc_function_vector.
+
+ If the argument FUNFIRSTLINE is nonzero, we want the first line
+ of real code inside a function when a function is specified.
+
+ DEFAULT_SYMTAB specifies the file to use if none is specified.
+ It defaults to current_source_symtab.
+ DEFAULT_LINE specifies the line number to use for relative
+ line numbers (that start with signs). Defaults to current_source_line.
+
+ Note that it is possible to return zero for the symtab
+ if no file is validly specified. Callers must check that.
+ Also, the line number returned may be invalid. */
+
+struct symtab_and_line
+decode_line_1 (argptr, funfirstline, default_symtab, default_line)
+ char **argptr;
+ int funfirstline;
+ struct symtab *default_symtab;
+ int default_line;
+{
+ struct symtab_and_line value;
+ register char *p, *p1;
+ register struct symtab *s;
+ register struct symbol *sym;
+ register CORE_ADDR pc;
+ register int i;
+ char *copy;
+
+ /* Defaults have defaults. */
+
+ if (default_symtab == 0)
+ {
+ default_symtab = current_source_symtab;
+ default_line = current_source_line;
+ }
+
+ /* See if arg is *PC */
+
+ if (**argptr == '*')
+ {
+ (*argptr)++;
+ pc = parse_and_eval_address_1 (argptr);
+ value = find_pc_line (pc, 0);
+ value.pc = pc;
+ return value;
+ }
+
+ /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
+
+ s = 0;
+
+ for (p = *argptr; *p; p++)
+ {
+ if (p[0] == ':' || p[0] == ' ' || p[0] == '\t')
+ break;
+ }
+ while (p[0] == ' ' || p[0] == '\t') p++;
+
+ if (p[0] == ':')
+ {
+ /* Extract the file name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Find that file's data. */
+ s = lookup_symtab (copy);
+ if (s == 0)
+ {
+ if (symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ error ("No source file named %s.", copy);
+ }
+
+ /* Discard the file name from the arg. */
+ p = p1 + 1;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ }
+
+ /* S is specified file's symtab, or 0 if no file specified.
+ arg no longer contains the file name. */
+
+ /* Check whether arg is all digits (and sign) */
+
+ p = *argptr;
+ if (*p == '-' || *p == '+') p++;
+ while (*p >= '0' && *p <= '9')
+ p++;
+
+ if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ','))
+ {
+ /* We found a token consisting of all digits -- at least one digit. */
+ enum sign {none, plus, minus} sign = none;
+
+ if (**argptr == '+')
+ sign = plus, (*argptr)++;
+ else if (**argptr == '-')
+ sign = minus, (*argptr)++;
+ value.line = atoi (*argptr);
+ switch (sign)
+ {
+ case plus:
+ if (p == *argptr)
+ value.line = 5;
+ if (s == 0)
+ value.line = default_line + value.line;
+ break;
+ case minus:
+ if (p == *argptr)
+ value.line = 15;
+ if (s == 0)
+ value.line = default_line - value.line;
+ else
+ value.line = 1;
+ break;
+ }
+
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ if (s == 0)
+ s = default_symtab;
+ value.symtab = s;
+ value.pc = 0;
+ return value;
+ }
+
+ /* Arg token is not digits => try it as a function name
+ Find the next token (everything up to end or next whitespace). */
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',') p++;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = 0;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ /* Look up that token as a function.
+ If file specified, use that file's per-file block to start with. */
+
+ sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0,
+ VAR_NAMESPACE);
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ value = find_pc_line (pc, 0);
+ value.pc = (value.end && value.pc != pc) ? value.end : pc;
+ return value;
+ }
+
+ if (sym)
+ error ("%s is not a function.", copy);
+
+ for (i = 0; i < misc_function_count; i++)
+ if (!strcmp (misc_function_vector[i].name, copy))
+ {
+ value.symtab = 0;
+ value.line = 0;
+ value.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (value.pc);
+ return value;
+ }
+
+ if (symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ error ("Function %s not defined.", copy);
+}
+
+struct symtab_and_line
+decode_line_spec (string, funfirstline)
+ char *string;
+ int funfirstline;
+{
+ struct symtab_and_line sal;
+ if (string == 0)
+ error ("Empty line specification.");
+ sal = decode_line_1 (&string, funfirstline,
+ current_source_symtab, current_source_line);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sal;
+}
+
+static void
+sources_info ()
+{
+ register struct symtab *s;
+ register int column = 0;
+
+ if (symtab_list == 0)
+ {
+ printf ("No symbol table is loaded.\n");
+ return;
+ }
+ printf ("Source files for which symbol table is known:\n");
+ 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++;
+ }
+ }
+ printf ("\n");
+}
+
+/* List all symbols (if REGEXP is 0) or all symbols matching REGEXP.
+ If CLASS is zero, list all symbols except functions and type names.
+ If CLASS is 1, list only functions.
+ If CLASS is 2, list only type names. */
+
+#define MORE \
+{ print_count++; \
+ if (print_count >= 21) \
+ { printf ("--Type Return to print more--"); \
+ print_count = 0; \
+ fflush (stdout); \
+ read_line (); } }
+
+static void
+list_symbols (regexp, class)
+ char *regexp;
+ int class;
+{
+ register struct symtab *s;
+ register struct blockvector *bv;
+ struct blockvector *prev_bv = 0;
+ register struct block *b;
+ register int i, j;
+ register struct symbol *sym;
+ char *val = 0;
+ int found_in_file;
+ static char *classnames[]
+ = {"variable", "function", "type"};
+ int print_count = 0;
+#ifdef REGCMP
+ extern char *regcmp(), *regex(), *loc1;
+#endif
+
+ if (regexp) {
+#ifdef REGCMP
+ val = regcmp(regexp, (char *)0);
+ if (val == 0)
+ error ("Invalid regexp: %s", regexp);
+#else
+ if (val = (char *) re_comp (regexp))
+ error ("Invalid regexp: %s", val);
+#endif
+ }
+
+ printf (regexp
+ ? "All %ss matching regular expression \"%s\":\n"
+ : "All defined %ss:\n",
+ classnames[class],
+ regexp);
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ found_in_file = 0;
+ bv = BLOCKVECTOR (s);
+ /* Often many files share a blockvector.
+ Scan each blockvector only once so that
+ we don't get every symbol many times.
+ It happens that the first symtab in the list
+ for any given blockvector is the main file. */
+ if (bv != prev_bv)
+ for (i = 0; i < 2; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ for (j = 0; j < BLOCK_NSYMS (b); j++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, j);
+ if (regexp) {
+#ifdef REGCMP
+ if (!regex(val, SYMBOL_NAME (sym)))
+ continue;
+#else
+ if (!re_exec (SYMBOL_NAME (sym)))
+ continue;
+#endif
+ }
+ if ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_BLOCK)
+ || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF))
+ {
+ if (!found_in_file)
+ {
+ printf ("\nFile %s:\n", s->filename);
+ print_count += 2;
+ }
+ found_in_file = 1;
+ MORE;
+ if (class != 2 && i == 1)
+ printf ("static ");
+ if (class == 2
+ && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE)
+ printf ("typedef ");
+
+ type_print (SYMBOL_TYPE (sym),
+ (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ ? "" : SYMBOL_NAME (sym)),
+ stdout, 0);
+ if (class == 2
+ && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE
+ && (TYPE_NAME ((SYMBOL_TYPE (sym))) == 0
+ || 0 != strcmp (TYPE_NAME ((SYMBOL_TYPE (sym))),
+ SYMBOL_NAME (sym))))
+ printf (" %s", SYMBOL_NAME (sym));
+ printf (";\n");
+ }
+ }
+ }
+ prev_bv = bv;
+ }
+#ifdef REGCMP
+ if (val)
+ (void)free(val);
+#endif
+}
+
+static void
+variables_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 0);
+}
+
+static void
+functions_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 1);
+}
+
+static void
+types_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 2);
+}
+
+/* Initialize the standard C scalar types. */
+
+static
+struct type *
+init_type (code, length, uns, name)
+ enum type_code code;
+ int length, uns;
+ char *name;
+{
+ register struct type *type;
+
+ type = (struct type *) xmalloc (sizeof (struct type));
+ bzero (type, sizeof *type);
+ TYPE_CODE (type) = code;
+ TYPE_LENGTH (type) = length;
+ TYPE_FLAGS (type) = uns ? TYPE_FLAG_UNSIGNED : 0;
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+ TYPE_NFIELDS (type) = 0;
+ TYPE_NAME (type) = name;
+
+ return type;
+}
+
+static
+initialize ()
+{
+ add_info ("variables", variables_info,
+ "All global and static variable names, or those matching REGEXP.");
+ add_info ("functions", functions_info,
+ "All function names, or those matching REGEXP.");
+ add_info ("types", types_info,
+ "All types names, or those matching REGEXP.");
+ add_info ("sources", sources_info,
+ "Source files in the program.");
+
+ obstack_init (symbol_obstack);
+
+ builtin_type_void = init_type (TYPE_CODE_VOID, 0, 0, "void");
+
+ builtin_type_float = init_type (TYPE_CODE_FLT, sizeof (float), 0, "float");
+ builtin_type_double = init_type (TYPE_CODE_FLT, sizeof (double), 0, "double");
+
+ builtin_type_char = init_type (TYPE_CODE_INT, sizeof (char), 0, "char");
+ builtin_type_short = init_type (TYPE_CODE_INT, sizeof (short), 0, "short");
+ builtin_type_long = init_type (TYPE_CODE_INT, sizeof (long), 0, "long");
+ builtin_type_int = init_type (TYPE_CODE_INT, sizeof (int), 0, "int");
+
+ builtin_type_unsigned_char = init_type (TYPE_CODE_INT, sizeof (char), 1, "unsigned char");
+ builtin_type_unsigned_short = init_type (TYPE_CODE_INT, sizeof (short), 1, "unsigned short");
+ builtin_type_unsigned_long = init_type (TYPE_CODE_INT, sizeof (long), 1, "unsigned long");
+ builtin_type_unsigned_int = init_type (TYPE_CODE_INT, sizeof (int), 1, "unsigned int");
+}
+
+END_FILE
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d29 4
+d933 1
+a933 1
+ char *val;
+d938 3
+d942 6
+a947 1
+ if (regexp)
+d950 2
+d976 10
+a985 2
+ if ((regexp == 0 || re_exec (SYMBOL_NAME (sym)))
+ && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+d988 1
+a988 1
+ || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)))
+d1019 4
+@
diff --git a/gdb/RCS/utils.c,v b/gdb/RCS/utils.c,v
new file mode 100644
index 0000000..3f7a836
--- /dev/null
+++ b/gdb/RCS/utils.c,v
@@ -0,0 +1,461 @@
+head 1.2;
+access ;
+symbols RMS-has:1.2;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 88.01.26.05.11.12; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 88.01.21.05.11.11; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@From RMS's development sources on wheaties, 20Jan88
+@
+
+
+1.2
+log
+@Avoid using TIOCFLUSH if it is not defined.
+@
+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 <stdio.h>
+#include <sys/ioctl.h>
+#include "defs.h"
+
+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);
+ }
+}
+
+/* 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 TIOCFLUSH
+ ioctl (fileno (stdout), TIOCFLUSH, 0);
+#endif
+ error ("Quit");
+}
+
+/* Control C comes here */
+
+void
+request_quit ()
+{
+ quit_flag = 1;
+ 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;
+ }
+}
+
+void
+printchar (ch, stream)
+ unsigned char ch;
+ FILE *stream;
+{
+ 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 == '"' || c == '\'')
+ fputc ('\\', stream);
+ fputc (c, stream);
+ }
+}
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d194 1
+d196 1
+@