aboutsummaryrefslogtreecommitdiff
path: root/gdb/RCS
diff options
context:
space:
mode:
authorgdb-3.1 <gdb@fsf.org>1989-01-31 17:56:40 +0000
committerPedro Alves <palves@redhat.com>2012-06-03 15:36:31 +0100
commite91b87a36830d061ef87d67be5f309e4d4ed918f (patch)
tree3408ea913a9cccd51c9b7d0b3bc7d7897cac8a5b /gdb/RCS
parentbb7592f01006b09c846831a9fb9c306307ba34f6 (diff)
downloadgdb-e91b87a36830d061ef87d67be5f309e4d4ed918f.zip
gdb-e91b87a36830d061ef87d67be5f309e4d4ed918f.tar.gz
gdb-e91b87a36830d061ef87d67be5f309e4d4ed918f.tar.bz2
gdb-3.1
Diffstat (limited to 'gdb/RCS')
-rw-r--r--gdb/RCS/Makefile,v367
-rw-r--r--gdb/RCS/blockframe.c,v606
-rw-r--r--gdb/RCS/coffread.c,v2047
-rwxr-xr-xgdb/RCS/config.gdb,v229
-rw-r--r--gdb/RCS/core.c,v651
-rw-r--r--gdb/RCS/dbxread.c,v4610
-rw-r--r--gdb/RCS/default-dep.c,v731
-rw-r--r--gdb/RCS/findvar.c,v584
-rw-r--r--gdb/RCS/gdb.texinfo,v3009
-rw-r--r--gdb/RCS/gdbcore.h,v105
-rw-r--r--gdb/RCS/inflow.c,v636
-rw-r--r--gdb/RCS/infrun.c,v1855
-rw-r--r--gdb/RCS/m-aux.h,v591
-rw-r--r--gdb/RCS/m-hp9k320.h,v607
-rw-r--r--gdb/RCS/m-sparc.h,v747
-rw-r--r--gdb/RCS/m68k-pinsn.c,v824
-rw-r--r--gdb/RCS/main.c,v1348
-rwxr-xr-xgdb/RCS/munch,v75
-rw-r--r--gdb/RCS/printcmd.c,v1707
-rw-r--r--gdb/RCS/remote.c,v662
-rw-r--r--gdb/RCS/source.c,v990
-rw-r--r--gdb/RCS/sparc-dep.c,v1091
-rw-r--r--gdb/RCS/stack.c,v882
-rw-r--r--gdb/RCS/utils.c,v726
-rw-r--r--gdb/RCS/valprint.c,v1117
-rw-r--r--gdb/RCS/values.c,v1047
26 files changed, 27844 insertions, 0 deletions
diff --git a/gdb/RCS/Makefile,v b/gdb/RCS/Makefile,v
new file mode 100644
index 0000000..fd71c1c
--- /dev/null
+++ b/gdb/RCS/Makefile,v
@@ -0,0 +1,367 @@
+head 1.4;
+access ;
+symbols ;
+locks ; strict;
+comment @# @;
+
+
+1.4
+date 89.03.27.21.28.33; author gnu; state Exp;
+branches ;
+next 1.3;
+
+1.3
+date 89.03.27.18.33.31; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.03.13.19.02.58; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.09.03.15.53; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.4
+log
+@More general support for ALLOCA and other local library routines;
+other minor cleanup.
+@
+text
+@# On HPUX, you need to add -Ihp-include to CFLAGS.
+# The headers in the directory hp-include override system headers
+# and tell GDB to use BSD executable file format.
+# You must also define REGEX & REGEX1 below and ALLOCA & ALLOCA1 (get
+# alloca.c from the emacs distribution) to the CLIBS.
+# If you compile GDB with GCC on HPUX, you must make sure that the "nm" used
+# in "munch" is GNU's nm. This is because gcc uses a different .o
+# file format than the native HPUX compiler.
+
+# On USG (System V) machines, you must make sure to setup REGEX &
+# REGEX1 to point at regex.o and use the USG version of CLIBS.
+# If your system has a broken alloca() -- most do -- then get
+# alloca.c from the GNU Emacs distribution and set ALLOCA & ALLOCA1.
+# Also, if you compile gdb with a compiler which uses the coff
+# encapsulation feature (this is a function of the compiler used, NOT
+# of the m-?.h file selected by config.gdb), you must make sure that
+# the GNU nm is the one that is used by munch.
+
+# On Sunos 4.0 machines, make sure to compile *without* shared
+# libraries if you want to run gdb on itself. Make sure to compile
+# any program on which you want to run gdb without shared libraries.
+
+# If you are compiling with GCC, make sure that either 1) You use the
+# -traditional flag, or 2) You have the fixed include files where GCC
+# can reach them. Otherwise the ioctl calls in inflow.c will be
+# incorrectly compiled. The "fixincludes" script in the gcc
+# distribution will probably fix your include files up.
+
+CC=cc
+SHELL=/bin/sh
+
+# Set this up with gcc if you have gnu ld and the loader will print out
+# line numbers for undefinded refs.
+CC-LD=${CC}
+
+# -I. for "#include <obstack.h>". Possibly regex.h also.
+#CFLAGS = -g -pg -I. -O
+CFLAGS = -I. -g
+#LDFLAGS = -pg -g
+LDFLAGS = -g
+
+# define this to be "obstack.o" if you don't have the obstack library installed
+# you must at the same time define OBSTACK1 as "obstack.o"
+# so that the dependencies work right. Similarly with REGEX and "regex.o".
+# You must define REGEX and REGEX1 on USG machines.
+# If your system is missing alloca(), or, more likely, it's there but it
+# doesn't work, define ALLOCA and ALLOCA1.
+OBSTACK = obstack.o
+OBSTACK1 = obstack.o
+REGEX = regex.o
+REGEX1 = regex.o
+ALLOCA = alloca.o
+ALLOCA1 = alloca.o
+ADD_FILES = $(OBSTACK) $(REGEX) $(ALLOCA) $(GNU_MALLOC)
+ADD_DEPS = $(OBSTACK1) $(REGEX1) $(ALLOCA1) $(GNU_MALLOC)
+
+#
+# define this to be "malloc.o" if you want to use the gnu malloc routine
+# (useful for debugging memory allocation problems in gdb). Otherwise, leave
+# it blank.
+GNU_MALLOC =
+#GNU_MALLOC = malloc.o
+
+# Flags to be used in compiling malloc.o
+# Specify range checking for storage allocation.
+MALLOC_FLAGS =
+#MALLOC_FLAGS = ${CFLAGS} -Drcheck -Dbotch=fatal -DMSTATS
+
+# for BSD
+CLIBS = $(ADD_FILES)
+# for USG
+#CLIBS= $(ADD_FILES) -lPW
+
+SFILES = blockframe.c breakpoint.c coffread.c command.c core.c dbxread.c \
+ environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \
+ kdb-start.c main.c printcmd.c \
+ remote.c source.c stack.c standalone.c stuff.c symmisc.c symtab.c \
+ utils.c valarith.c valops.c valprint.c values.c version.c expread.y \
+ xgdb.c
+
+DEPFILES = convex-dep.c umax-dep.c gould-dep.c default-dep.c sun3-dep.c \
+ sparc-dep.c hp9k320-dep.c news-dep.c i386-dep.c
+
+PINSNS = gld-pinsn.c i386-pinsn.c sparc-pinsn.c vax-pinsn.c m68k-pinsn.c \
+ ns32k-pinsn.c
+
+HFILES = command.h defs.h environ.h expression.h frame.h getpagesize.h \
+ inferior.h symseg.h symtab.h value.h wait.h \
+ a.out.encap.h a.out.gnu.h stab.gnu.h
+
+OPCODES = m68k-opcode.h pn-opcode.h sparc-opcode.h npl-opcode.h vax-opcode.h \
+ ns32k-opcode.h
+
+MFILES = m-hp9k320.h m-i386.h m-i386gas.h m-isi.h m-merlin.h m-news.h \
+ m-npl.h m-pn.h m-sparc.h m-sun2.h m-sun3.h m-sun2os4.h \
+ m-sun3os4.h m-sun4os4.h m-umax.h m-vax.h
+
+POSSLIBS = obstack.h obstack.c regex.c regex.h malloc.c
+
+TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c
+
+OTHERS = Makefile createtags munch config.gdb ChangeLog README TAGS \
+ gdb.texinfo .gdbinit COPYING expread.tab.c stab.def hp-include
+
+TAGFILES = ${SFILES} ${DEPFILES} ${PINSNS} ${HFILES} ${OPCODES} ${MFILES} \
+ ${POSSLIBS}
+TARFILES = ${TAGFILES} ${OTHERS}
+
+OBS = main.o blockframe.o breakpoint.o findvar.o stack.o source.o \
+ values.o eval.o valops.o valarith.o valprint.o printcmd.o \
+ symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o \
+ command.o utils.o expread.o expprint.o pinsn.o environ.o version.o
+
+TSOBS = core.o inflow.o dep.o
+
+NTSOBS = standalone.o
+
+TSSTART = /lib/crt0.o
+
+NTSSTART = kdb-start.o
+
+gdb : $(OBS) $(TSOBS) $(ADD_DEPS)
+ -rm -f init.c
+ ./munch $(OBS) $(TSOBS) > init.c
+ ${CC-LD} $(LDFLAGS) -o gdb init.c $(OBS) $(TSOBS) $(CLIBS)
+
+xgdb : $(OBS) $(TSOBS) xgdb.o $(ADD_DEPS)
+ -rm -f init.c
+ ./munch $(OBS) $(TSOBS) xgdb.o > init.c
+ $(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \
+ -lXaw -lXt -lX11 $(CLIBS)
+
+kdb : $(NTSSTART) $(OBS) $(NTSOBS) $(ADD_DEPS)
+ -rm -f init.c
+ ./munch $(OBS) $(NTSOBS) > init.c
+ $(CC-LD) $(LDFLAGS) -c init.c $(CLIBS)
+ ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o -lc $(CLIBS)
+
+# If it can figure out the appropriate order, createtags will make sure
+# that the proper m-*, *-dep, *-pinsn, and *-opcode files come first
+# in the tags list. It will attempt to do the same for dbxread.c and
+# coffread.c. This makes using M-. on machine dependent routines much
+# easier.
+#
+TAGS: ${TAGFILES}
+ createtags ${TAGFILES}
+tags: TAGS
+
+gdb.tar: ${TARFILES}
+ rm -f gdb.tar
+ mkdir dist-gdb
+ cd dist-gdb ; for i in ${TARFILES} ; do ln -s ../$$i . ; done
+ tar chf gdb.tar dist-gdb
+ rm -rf dist-gdb
+
+gdb.tar.Z: gdb.tar
+ compress gdb.tar
+
+clean:
+ -rm -f ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX}
+ -rm -f init.c init.o
+ -rm -f gdb
+
+realclean: clean
+ -rm -f expread.tab.c tags TAGS
+
+xgdb.o : xgdb.c defs.h param.h symtab.h frame.h
+ $(CC) -c $(CFLAGS) xgdb.c -o $@@
+
+expread.tab.c : expread.y
+ @@echo 'Expect 101 shift/reduce conflicts and 1 reduce/reduce conflict.'
+ yacc expread.y
+ mv y.tab.c expread.tab.c
+
+expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h
+ $(CC) -c ${CFLAGS} expread.tab.c
+ mv expread.tab.o expread.o
+
+#
+# Only useful if you are using the gnu malloc routines.
+#
+malloc.o : malloc.c
+ ${CC} -c ${MALLOC_FLAGS} malloc.c
+
+#
+# dep.o depends on ALL the dep files since we don't know which one
+# is really being used.
+#
+dep.o : ${DEPFILES} defs.h param.h frame.h inferior.h obstack.h \
+ a.out.encap.h
+
+# pinsn.o depends on ALL the opcode printers
+# since we don't know which one is really being used.
+pinsn.o : ${PINSNS} defs.h param.h symtab.h obstack.h symseg.h frame.h \
+ ${OPCODES}
+
+#
+# The rest of this is a standard dependencies list (hand edited output of
+# cpp -M). It does not include dependencies of .o files on .c files.
+#
+blockframe.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
+breakpoint.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
+coffread.o : defs.h param.h
+command.o : command.h defs.h
+core.o : defs.h param.h a.out.encap.h
+dbxread.o : param.h defs.h symtab.h obstack.h symseg.h a.out.encap.h \
+ stab.gnu.h
+environ.o : environ.h
+eval.o : defs.h param.h symtab.h obstack.h symseg.h value.h expression.h
+expprint.o : defs.h symtab.h obstack.h symseg.h param.h expression.h
+findvar.o : defs.h param.h symtab.h obstack.h symseg.h frame.h value.h
+infcmd.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \
+ environ.h value.h
+inflow.o : defs.h param.h frame.h inferior.h
+infrun.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \
+ wait.h
+kdb-start.o : defs.h param.h
+main.o : defs.h command.h param.h
+malloc.o : getpagesize.h
+obstack.o : obstack.h
+printcmd.o : defs.h param.h frame.h symtab.h obstack.h symseg.h value.h \
+ expression.h
+regex.o : regex.h
+remote.o : defs.h param.h frame.h inferior.h wait.h
+source.o : defs.h symtab.h obstack.h symseg.h param.h
+stack.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
+standalone.o : defs.h param.h symtab.h obstack.h symseg.h frame.h \
+ inferior.h wait.h
+symmisc.o : defs.h symtab.h obstack.h symseg.h obstack.h
+symtab.o : defs.h symtab.h obstack.h symseg.h param.h obstack.h
+utils.o : defs.h param.h
+valarith.o : defs.h param.h symtab.h obstack.h symseg.h value.h expression.h
+valops.o : defs.h param.h symtab.h obstack.h symseg.h value.h frame.h \
+ inferior.h
+valprint.o : defs.h param.h symtab.h obstack.h symseg.h value.h
+values.o : defs.h param.h symtab.h obstack.h symseg.h value.h
+
+robotussin.h : getpagesize.h
+symtab.h : obstack.h symseg.h
+a.out.encap.h : a.out.gnu.h
+@
+
+
+1.3
+log
+@A/UX changes. Use cc, use local regex.o, use local alloca.o
+@
+text
+@d4 2
+a5 2
+# You must also define REGEX & REGEX1 below and add alloca.o (from
+# the emacs distribution) to the CLIBS.
+d12 2
+d26 2
+a27 1
+# incorrectly compiled.
+d46 2
+d52 4
+d70 1
+a70 1
+#CLIBS = $(OBSTACK) $(REGEX) $(GNU_MALLOC)
+d72 1
+a72 1
+CLIBS= $(OBSTACK) $(REGEX) $(GNU_MALLOC) alloca.o
+d122 1
+a122 1
+gdb : $(OBS) $(TSOBS) $(OBSTACK1) $(REGEX1) ${GNU_MALLOC}
+d127 1
+a127 1
+xgdb : $(OBS) $(TSOBS) xgdb.o $(OBSTACK1) $(REGEX1) ${GNU_MALLOC}
+d133 1
+a133 1
+kdb : $(NTSSTART) $(OBS) $(NTSOBS) $(OBSTACK1) $(REGEX1) ${GNU_MALLOC}
+d161 1
+a161 1
+ -rm -f init.c
+d165 1
+a165 1
+ -rm -f expread.tab.c
+@
+
+
+1.2
+log
+@All rm's to rm -f's.
+@
+text
+@d26 1
+a26 1
+CC=gcc
+d45 2
+a46 2
+REGEX =
+REGEX1 =
+d61 1
+a61 1
+CLIBS = $(OBSTACK) $(REGEX) $(GNU_MALLOC)
+d63 1
+a63 1
+#CLIBS= $(OBSTACK) $(REGEX) $(GNU_MALLOC) -lPW
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d26 1
+a26 1
+CC=/bin/cc
+d114 1
+a114 1
+ -rm init.c
+d119 1
+a119 1
+ -rm init.c
+d125 1
+a125 1
+ -rm init.c
+d151 3
+a153 3
+ -rm ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX}
+ -rm init.c
+ -rm gdb
+d156 1
+a156 1
+ -rm expread.tab.c
+@
diff --git a/gdb/RCS/blockframe.c,v b/gdb/RCS/blockframe.c,v
new file mode 100644
index 0000000..fc64e2f
--- /dev/null
+++ b/gdb/RCS/blockframe.c,v
@@ -0,0 +1,606 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.3
+date 89.03.16.21.09.52; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.02.09.23.21.53; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.09.15.15.16; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@Don't stop the stack trace until the "next frame pointer" is zero.
+@
+text
+@/* Get info from stack frames;
+ convert between frames, blocks, functions and pc values.
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+
+/* Address of end of first object file.
+ This file is assumed to be a startup file
+ and frames with pc's inside it
+ are treated as nonexistent. */
+
+CORE_ADDR first_object_file_end;
+
+/* Address of innermost stack frame (contents of FP register) */
+
+static FRAME current_frame;
+
+struct block *block_for_pc ();
+CORE_ADDR get_pc_function_start ();
+
+/*
+ * Cache for frame addresses already read by gdb. Valid only while
+ * inferior is stopped. Control variables for the frame cache should
+ * be local to this module.
+ */
+struct obstack frame_cache_obstack;
+
+/* Return the innermost (currently executing) stack frame. */
+
+FRAME
+get_current_frame ()
+{
+ /* We assume its address is kept in a general register;
+ param.h says which register. */
+
+ return current_frame;
+}
+
+void
+set_current_frame (frame)
+ FRAME frame;
+{
+ current_frame = frame;
+}
+
+FRAME
+create_new_frame (addr, pc)
+ FRAME_ADDR addr;
+ CORE_ADDR pc;
+{
+ struct frame_info *fci; /* Same type as FRAME */
+
+ fci = (struct frame_info *)
+ obstack_alloc (&frame_cache_obstack,
+ sizeof (struct frame_info));
+
+ /* Arbitrary frame */
+ fci->next = (struct frame_info *) 0;
+ fci->prev = (struct frame_info *) 0;
+ fci->frame = addr;
+ fci->next_frame = 0; /* Since arbitrary */
+ fci->pc = pc;
+
+#ifdef INIT_EXTRA_FRAME_INFO
+ INIT_EXTRA_FRAME_INFO (fci);
+#endif
+
+ return fci;
+}
+
+/* Return the frame that called FRAME.
+ If FRAME is the original frame (it has no caller), return 0. */
+
+FRAME
+get_prev_frame (frame)
+ FRAME frame;
+{
+ /* We're allowed to know that FRAME and "struct frame_info *" are
+ the same */
+ return get_prev_frame_info (frame);
+}
+
+/*
+ * Flush the entire frame cache.
+ */
+void
+flush_cached_frames ()
+{
+ /* Since we can't really be sure what the first object allocated was */
+ obstack_free (&frame_cache_obstack, 0);
+ obstack_init (&frame_cache_obstack);
+
+ current_frame = (struct frame_info *) 0; /* Invalidate cache */
+}
+
+/* Return a structure containing various interesting information
+ about a specified stack frame. */
+/* How do I justify including this function? Well, the FRAME
+ identifier format has gone through several changes recently, and
+ it's not completely inconceivable that it could happen again. If
+ it does, have this routine around will help */
+
+struct frame_info *
+get_frame_info (frame)
+ FRAME frame;
+{
+ return frame;
+}
+
+/* Return a structure containing various interesting information
+ about the frame that called NEXT_FRAME. */
+
+struct frame_info *
+get_prev_frame_info (next_frame)
+ FRAME next_frame;
+{
+ FRAME_ADDR address;
+ struct frame_info *prev;
+ int fromleaf = 0;
+
+ /* If we are within "start" right now, don't go any higher. */
+ /* This truncates stack traces of things at sigtramp() though,
+ because sigtramp() doesn't have a normal return PC, it has
+ garbage or a small value (seen: 3) in the return PC slot.
+ It's VITAL to see where the signal occurred, so punt this. */
+#if 0
+ if (next_frame && next_frame->pc < first_object_file_end)
+ return 0;
+#endif
+
+ /* If the requested entry is in the cache, return it.
+ Otherwise, figure out what the address should be for the entry
+ we're about to add to the cache. */
+
+ if (!next_frame)
+ {
+ if (!current_frame)
+ error ("No frame is currently selected.");
+
+ return current_frame;
+ }
+ else
+ {
+ /* If we have the prev one, return it */
+ if (next_frame->prev)
+ return next_frame->prev;
+
+ /* There is a questionable, but probably always correct
+ assumption being made here. The assumption is that if
+ functions on a specific machine has a FUNCTION_START_OFFSET,
+ then this is used by the function call instruction for some
+ purpose. If the function call instruction has this much hair
+ in it, it probably also sets up the frame pointer
+ automatically (ie. we'll never have what I am calling a
+ "leaf node", one which shares a frame pointer with it's
+ calling function). This is true on a vax. The only other
+ way to find this out would be to setup a seperate macro
+ "FUNCTION_HAS_FRAME_POINTER", which would often be equivalent
+ to SKIP_PROLOGUE modifying a pc value. */
+
+#if FUNCTION_START_OFFSET == 0
+ if (!(next_frame->next))
+ {
+ /* Innermost */
+ CORE_ADDR func_start, after_prologue;
+
+ func_start = (get_pc_function_start (next_frame->pc) +
+ FUNCTION_START_OFFSET);
+ after_prologue = func_start;
+ SKIP_PROLOGUE (after_prologue);
+ if (after_prologue == func_start)
+ {
+ fromleaf = 1;
+ address = next_frame->frame;
+ }
+ }
+#endif
+
+ if (!fromleaf)
+ {
+ /* Two macros defined in param.h specify the machine-dependent
+ actions to be performed here. */
+ /* First, get the frame's chain-pointer.
+ If that is zero, the frame is the outermost frame. */
+ address = FRAME_CHAIN (next_frame);
+ if (!FRAME_CHAIN_VALID (address, next_frame))
+ return 0;
+
+ /* If frame has a caller, combine the chain pointer and
+ the frame's own address to get the address of the caller. */
+ address = FRAME_CHAIN_COMBINE (address, next_frame);
+ }
+ }
+
+ prev = (struct frame_info *)
+ obstack_alloc (&frame_cache_obstack,
+ sizeof (struct frame_info));
+
+ if (next_frame)
+ next_frame->prev = prev;
+ prev->next = next_frame;
+ prev->prev = (struct frame_info *) 0;
+ prev->frame = address;
+ prev->next_frame = prev->next ? prev->next->frame : 0;
+
+#ifdef INIT_EXTRA_FRAME_INFO
+ INIT_EXTRA_FRAME_INFO(prev);
+#endif
+
+ /* This entry is in the frame queue now, which is good since
+ FRAME_SAVED_PC may use that queue to figure out it's value
+ (see m-sparc.h). We want the pc saved in the inferior frame. */
+ prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) :
+ next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ());
+
+ return prev;
+}
+
+CORE_ADDR
+get_frame_pc (frame)
+ FRAME frame;
+{
+ struct frame_info *fi;
+ fi = get_frame_info (frame);
+ return fi->pc;
+}
+
+/* Find the addresses in which registers are saved in FRAME. */
+
+void
+get_frame_saved_regs (frame_info_addr, saved_regs_addr)
+ struct frame_info *frame_info_addr;
+ struct frame_saved_regs *saved_regs_addr;
+{
+#if 1
+ FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr);
+#else
+ {
+ register int regnum;
+ register int regmask;
+ register CORE_ADDR next_addr;
+ register CORE_ADDR pc;
+ int nextinsn;
+ bzero (&*saved_regs_addr, sizeof *saved_regs_addr);
+ if ((frame_info_addr)->pc >= ((frame_info_addr)->frame
+ - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4)
+ && (frame_info_addr)->pc <= (frame_info_addr)->frame)
+ {
+ next_addr = (frame_info_addr)->frame;
+ pc = (frame_info_addr)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4;
+ }
+ else
+ {
+ pc = get_pc_function_start ((frame_info_addr)->pc);
+ /* Verify we have a link a6 instruction next;
+ if not we lose. If we win, find the address above the saved
+ regs using the amount of storage from the link instruction. */
+ if (044016 == read_memory_integer (pc, 2))
+ {
+ next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 4);
+ pc += 4;
+ }
+ else if (047126 == read_memory_integer (pc, 2))
+ {
+ next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 2);
+ pc+=2;
+ }
+ else goto lose;
+
+ /* If have an addal #-n, sp next, adjust next_addr. */
+ if ((0177777 & read_memory_integer (pc, 2)) == 0157774)
+ {
+ next_addr += read_memory_integer (pc += 2, 4);
+ pc += 4;
+ }
+ }
+ /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */
+ regmask = read_memory_integer (pc + 2, 2);
+
+ /* But before that can come an fmovem. Check for it. */
+ nextinsn = 0xffff & read_memory_integer (pc, 2);
+ if (0xf227 == nextinsn
+ && (regmask & 0xff00) == 0xe000)
+ {
+ pc += 4; /* Regmask's low bit is for register fp7, the first pushed */
+ for (regnum = FP0_REGNUM + 7;
+ regnum >= FP0_REGNUM;
+ regnum--, regmask >>= 1)
+ if (regmask & 1)
+ (*saved_regs_addr).regs[regnum] = (next_addr -= 12);
+ regmask = read_memory_integer (pc + 2, 2);
+ }
+ if (0044327 == read_memory_integer (pc, 2))
+ {
+ pc += 4; /* Regmask's low bit is for register 0, the first written */
+ for (regnum = 0; regnum < 16; regnum++, regmask >>= 1)
+ if (regmask & 1)
+ (*saved_regs_addr).regs[regnum] = (next_addr += 4) - 4;
+ }
+ else if (0044347 == read_memory_integer (pc, 2))
+ { pc += 4; /* Regmask's low bit is for register 15, the first pushed */
+ for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1)
+ if (regmask & 1)
+ (*saved_regs_addr).regs[regnum] = (next_addr -= 4); }
+ else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2)))
+ { regnum = 0xf & read_memory_integer (pc, 2); pc += 2;
+ (*saved_regs_addr).regs[regnum] = (next_addr -= 4); }
+ /* fmovemx to index of sp may follow. */
+ regmask = read_memory_integer (pc + 2, 2);
+ nextinsn = 0xffff & read_memory_integer (pc, 2);
+ if (0xf236 == nextinsn
+ && (regmask & 0xff00) == 0xf000)
+ {
+ pc += 10; /* Regmask's low bit is for register fp0, the first written */
+ for (regnum = FP0_REGNUM + 7;
+ regnum >= FP0_REGNUM;
+ regnum--, regmask >>= 1)
+ if (regmask & 1)
+ (*saved_regs_addr).regs[regnum] = (next_addr += 12) - 12;
+ regmask = read_memory_integer (pc + 2, 2);
+ }
+ /* clrw -(sp); movw ccr,-(sp) may follow. */
+ if (0x426742e7 == read_memory_integer (pc, 4))
+ (*saved_regs_addr).regs[PS_REGNUM] = (next_addr -= 4);
+ lose: ;
+ (*saved_regs_addr).regs[SP_REGNUM] = (frame_info_addr)->frame + 8;
+ (*saved_regs_addr).regs[FP_REGNUM] = (frame_info_addr)->frame;
+ (*saved_regs_addr).regs[PC_REGNUM] = (frame_info_addr)->frame + 4;
+ }
+#endif
+}
+
+/* Return the innermost lexical block in execution
+ in a specified stack frame. The frame address is assumed valid. */
+
+struct block *
+get_frame_block (frame)
+ FRAME frame;
+{
+ struct frame_info *fi;
+
+ fi = get_frame_info (frame);
+ return block_for_pc (fi->pc);
+}
+
+struct block *
+get_current_block ()
+{
+ return block_for_pc (read_pc ());
+}
+
+CORE_ADDR
+get_pc_function_start (pc)
+ CORE_ADDR pc;
+{
+ register struct block *bl = block_for_pc (pc);
+ register struct symbol *symbol;
+ if (bl == 0 || (symbol = block_function (bl)) == 0)
+ {
+ register int misc_index = find_pc_misc_function (pc);
+ if (misc_index >= 0)
+ return misc_function_vector[misc_index].address;
+ return 0;
+ }
+ bl = SYMBOL_BLOCK_VALUE (symbol);
+ return BLOCK_START (bl);
+}
+
+/* Return the symbol for the function executing in frame FRAME. */
+
+struct symbol *
+get_frame_function (frame)
+ FRAME frame;
+{
+ register struct block *bl = get_frame_block (frame);
+ if (bl == 0)
+ return 0;
+ return block_function (bl);
+}
+
+/* Return the innermost lexical block containing the specified pc value,
+ or 0 if there is none. */
+
+extern struct symtab *psymtab_to_symtab ();
+
+struct block *
+block_for_pc (pc)
+ register CORE_ADDR pc;
+{
+ register struct block *b;
+ register int bot, top, half;
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ struct blockvector *bl;
+
+ /* First search all symtabs for one whose file contains our pc */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bl = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bl, 0);
+ if (BLOCK_START (b) <= pc
+ && BLOCK_END (b) > pc)
+ break;
+ }
+
+ if (s == 0)
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ {
+ if (ps->textlow <= pc
+ && ps->texthigh > pc)
+ {
+ s = psymtab_to_symtab (ps);
+ bl = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bl, 0);
+ break;
+ }
+ }
+
+ if (s == 0)
+ return 0;
+
+ /* Then search that symtab for the smallest block that wins. */
+ /* Use binary search to find the last block that starts before PC. */
+
+ bot = 0;
+ top = BLOCKVECTOR_NBLOCKS (bl);
+
+ while (top - bot > 1)
+ {
+ half = (top - bot + 1) >> 1;
+ b = BLOCKVECTOR_BLOCK (bl, bot + half);
+ if (BLOCK_START (b) <= pc)
+ bot += half;
+ else
+ top = bot + half;
+ }
+
+ /* Now search backward for a block that ends after PC. */
+
+ while (bot >= 0)
+ {
+ b = BLOCKVECTOR_BLOCK (bl, bot);
+ if (BLOCK_END (b) > pc)
+ return b;
+ bot--;
+ }
+
+ return 0;
+}
+
+/* Return the function containing pc value PC.
+ Returns 0 if function is not known. */
+
+struct symbol *
+find_pc_function (pc)
+ CORE_ADDR pc;
+{
+ register struct block *b = block_for_pc (pc);
+ if (b == 0)
+ return 0;
+ return block_function (b);
+}
+
+/* Find the misc function whose address is the largest
+ while being less than PC. Return its index in misc_function_vector.
+ Returns -1 if PC is not in suitable range. */
+
+int
+find_pc_misc_function (pc)
+ register CORE_ADDR pc;
+{
+ register int lo = 0;
+ register int hi = misc_function_count-1;
+ register int new;
+ register int distance;
+
+ /* Note that the last thing in the vector is always _etext. */
+
+ /* Above statement is not *always* true - fix for case where there are */
+ /* no misc functions at all (ie no symbol table has been read). */
+ if (hi < 0) return -1; /* no misc functions recorded */
+
+ /* trivial reject range test */
+ if (pc < misc_function_vector[0].address ||
+ pc > misc_function_vector[hi].address)
+ return -1;
+
+ do {
+ new = (lo + hi) >> 1;
+ distance = misc_function_vector[new].address - pc;
+ if (distance == 0)
+ return new; /* an exact match */
+ else if (distance > 0)
+ hi = new;
+ else
+ lo = new;
+ } while (hi-lo != 1);
+
+ /* if here, we had no exact match, so return the lower choice */
+ return lo;
+}
+
+/* Return the innermost stack frame executing inside of the specified block,
+ or zero if there is no such frame. */
+
+FRAME
+block_innermost_frame (block)
+ struct block *block;
+{
+ struct frame_info *fi;
+ register FRAME frame;
+ register CORE_ADDR start = BLOCK_START (block);
+ register CORE_ADDR end = BLOCK_END (block);
+
+ frame = 0;
+ while (1)
+ {
+ frame = get_prev_frame (frame);
+ if (frame == 0)
+ return 0;
+ fi = get_frame_info (frame);
+ if (fi->pc >= start && fi->pc < end)
+ return frame;
+ }
+}
+
+void
+_initialize_blockframe ()
+{
+ obstack_init (&frame_cache_obstack);
+}
+@
+
+
+1.2
+log
+@Avoid fatal error for simple user error
+@
+text
+@d142 5
+d149 1
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d152 1
+a152 1
+ fatal ("get_prev_frame_info: Called before cache primed");
+@
diff --git a/gdb/RCS/coffread.c,v b/gdb/RCS/coffread.c,v
new file mode 100644
index 0000000..9c45395
--- /dev/null
+++ b/gdb/RCS/coffread.c,v
@@ -0,0 +1,2047 @@
+head 1.5;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.5
+date 89.03.27.18.38.25; author gnu; state Exp;
+branches ;
+next 1.4;
+
+1.4
+date 89.03.27.18.37.20; author gnu; state Exp;
+branches ;
+next 1.3;
+
+1.3
+date 89.03.27.18.36.15; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.02.10.01.38.05; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.10.01.32.45; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.5
+log
+@Remake A/UX changes.
+@
+text
+@/* Read coff symbol tables and convert to internal format, for GDB.
+ Design and support routines derived from dbxread.c, and UMAX COFF
+ specific routines written 9/1/87 by David D. Johnson, Brown University.
+ Revised 11/27/87 ddj@@cs.brown.edu
+ Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "param.h"
+#ifdef COFF_FORMAT
+#include "symtab.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <a.out.h>
+#include <stdio.h>
+#include <obstack.h>
+#include <sys/param.h>
+#include <sys/file.h>
+
+/* Avoid problems with A/UX predefine */
+#undef aux
+
+static void add_symbol_to_list ();
+static void read_coff_symtab ();
+static void patch_opaque_types ();
+static struct type *decode_function_type ();
+static struct type *decode_type ();
+static struct type *decode_base_type ();
+static struct type *read_enum_type ();
+static struct type *read_struct_type ();
+static void finish_block ();
+static struct blockvector *make_blockvector ();
+static struct symbol *process_coff_symbol ();
+static int init_stringtab ();
+static void free_stringtab ();
+static char *getfilename ();
+static char *getsymname ();
+static int init_lineno ();
+static void enter_linenos ();
+
+extern void free_all_symtabs ();
+extern void free_all_psymtabs ();
+
+
+/* Name of source file whose symbol data we are now processing.
+ This comes from a symbol named ".file". */
+
+static char *last_source_file;
+
+/* Core address of start and end of text of current source file.
+ This comes from a ".text" symbol where x_nlinno > 0. */
+
+static CORE_ADDR cur_src_start_addr;
+static CORE_ADDR cur_src_end_addr;
+
+/* End of the text segment of the executable file,
+ as found in the symbol _etext. */
+
+static CORE_ADDR end_of_text_addr;
+
+/* The addresses of the symbol table stream and number of symbols
+ of the object file we are reading (as copied into core). */
+
+static FILE *nlist_stream_global;
+static int nlist_nsyms_global;
+
+/* The file and text section headers of the symbol file */
+
+static FILHDR file_hdr;
+static SCNHDR text_hdr;
+
+/* The index in the symbol table of the last coff symbol that was processed. */
+
+static int symnum;
+
+/* Vector of types defined so far, indexed by their coff symnum. */
+
+static struct typevector *type_vector;
+
+/* Number of elements allocated for type_vector currently. */
+
+static int type_vector_length;
+
+/* Vector of line number information. */
+
+static struct linetable *line_vector;
+
+/* Index of next entry to go in line_vector_index. */
+
+static int line_vector_index;
+
+/* Last line number recorded in the line vector. */
+
+static int prev_line_number;
+
+/* Number of elements allocated for line_vector currently. */
+
+static int line_vector_length;
+
+/* Chain of typedefs of pointers to empty struct/union types.
+ They are chained thru the SYMBOL_VALUE. */
+
+#define HASHSIZE 127
+static struct symbol *opaque_type_chain[HASHSIZE];
+
+/* Record the symbols defined for each context in a list.
+ We don't create a struct block for the context until we
+ know how long to make it. */
+
+struct pending
+{
+ struct pending *next;
+ struct symbol *symbol;
+};
+
+/* Here are the three lists that symbols are put on. */
+
+struct pending *file_symbols; /* static at top level, and types */
+
+struct pending *global_symbols; /* global functions and variables */
+
+struct pending *local_symbols; /* everything local to lexical context */
+
+/* List of unclosed lexical contexts
+ (that will become blocks, eventually). */
+
+struct context_stack
+{
+ struct context_stack *next;
+ struct pending *locals;
+ struct pending_block *old_blocks;
+ struct symbol *name;
+ CORE_ADDR start_addr;
+ int depth;
+};
+
+struct context_stack *context_stack;
+
+/* Nonzero if within a function (so symbols should be local,
+ if nothing says specifically). */
+
+int within_function;
+
+/* List of blocks already made (lexical contexts already closed).
+ This is used at the end to make the blockvector. */
+
+struct pending_block
+{
+ struct pending_block *next;
+ struct block *block;
+};
+
+struct pending_block *pending_blocks;
+
+extern CORE_ADDR first_object_file_end; /* From blockframe.c */
+
+/* File name symbols were loaded from. */
+
+static char *symfile;
+
+/* Look up a coff type-number index. Return the address of the slot
+ where the type for that index is stored.
+ The type-number is in INDEX.
+
+ This can be used for finding the type associated with that index
+ or for associating a new type with the index. */
+
+static struct type **
+coff_lookup_type (index)
+ register int index;
+{
+ if (index >= type_vector_length)
+ {
+ int old_vector_length = type_vector_length;
+
+ type_vector_length *= 2;
+ if (type_vector_length < index) {
+ type_vector_length = index * 2;
+ }
+ type_vector = (struct typevector *)
+ xrealloc (type_vector, sizeof (struct typevector)
+ + type_vector_length * sizeof (struct type *));
+ bzero (&type_vector->type[ old_vector_length ],
+ (type_vector_length - old_vector_length) * sizeof(struct type *));
+ }
+ return &type_vector->type[index];
+}
+
+/* Make sure there is a type allocated for type number index
+ and return the type object.
+ This can create an empty (zeroed) type object. */
+
+static struct type *
+coff_alloc_type (index)
+ int index;
+{
+ register struct type **type_addr = coff_lookup_type (index);
+ register struct type *type = *type_addr;
+
+ /* If we are referring to a type not known at all yet,
+ allocate an empty type for it.
+ We will fill it in later if we find out how. */
+ if (type == 0)
+ {
+ type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ bzero (type, sizeof (struct type));
+ *type_addr = type;
+ }
+ return type;
+}
+
+/* maintain the lists of symbols and blocks */
+
+/* Add a symbol to one of the lists of symbols. */
+static void
+add_symbol_to_list (symbol, listhead)
+ struct symbol *symbol;
+ struct pending **listhead;
+{
+ register struct pending *link
+ = (struct pending *) xmalloc (sizeof (struct pending));
+
+ link->next = *listhead;
+ link->symbol = symbol;
+ *listhead = link;
+}
+
+/* Take one of the lists of symbols and make a block from it.
+ Put the block on the list of pending blocks. */
+
+static void
+finish_block (symbol, listhead, old_blocks, start, end)
+ struct symbol *symbol;
+ struct pending **listhead;
+ struct pending_block *old_blocks;
+ CORE_ADDR start, end;
+{
+ register struct pending *next, *next1;
+ register struct block *block;
+ register struct pending_block *pblock;
+ struct pending_block *opblock;
+ register int i;
+
+ /* Count the length of the list of symbols. */
+
+ for (next = *listhead, i = 0; next; next = next->next, i++);
+
+ block = (struct block *)
+ obstack_alloc (symbol_obstack, sizeof (struct block) + (i - 1) * sizeof (struct symbol *));
+
+ /* Copy the symbols into the block. */
+
+ BLOCK_NSYMS (block) = i;
+ for (next = *listhead; next; next = next->next)
+ BLOCK_SYM (block, --i) = next->symbol;
+
+ BLOCK_START (block) = start;
+ BLOCK_END (block) = end;
+ BLOCK_SUPERBLOCK (block) = 0; /* Filled in when containing block is made */
+
+ /* Put the block in as the value of the symbol that names it. */
+
+ if (symbol)
+ {
+ SYMBOL_BLOCK_VALUE (symbol) = block;
+ BLOCK_FUNCTION (block) = symbol;
+ }
+ else
+ BLOCK_FUNCTION (block) = 0;
+
+ /* Now free the links of the list, and empty the list. */
+
+ for (next = *listhead; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+ *listhead = 0;
+
+ /* Install this block as the superblock
+ of all blocks made since the start of this scope
+ that don't have superblocks yet. */
+
+ opblock = 0;
+ for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
+ {
+ if (BLOCK_SUPERBLOCK (pblock->block) == 0)
+ BLOCK_SUPERBLOCK (pblock->block) = block;
+ opblock = pblock;
+ }
+
+ /* Record this block on the list of all blocks in the file.
+ Put it after opblock, or at the beginning if opblock is 0.
+ This puts the block in the list after all its subblocks. */
+
+ pblock = (struct pending_block *) xmalloc (sizeof (struct pending_block));
+ pblock->block = block;
+ if (opblock)
+ {
+ pblock->next = opblock->next;
+ opblock->next = pblock;
+ }
+ else
+ {
+ pblock->next = pending_blocks;
+ pending_blocks = pblock;
+ }
+}
+
+static struct blockvector *
+make_blockvector ()
+{
+ register struct pending_block *next, *next1;
+ register struct blockvector *blockvector;
+ register int i;
+
+ /* Count the length of the list of blocks. */
+
+ for (next = pending_blocks, i = 0; next; next = next->next, i++);
+
+ blockvector = (struct blockvector *)
+ obstack_alloc (symbol_obstack, sizeof (struct blockvector) + (i - 1) * sizeof (struct block *));
+
+ /* Copy the blocks into the blockvector.
+ This is done in reverse order, which happens to put
+ the blocks into the proper order (ascending starting address).
+ finish_block has hair to insert each block into the list
+ after its subblocks in order to make sure this is true. */
+
+ BLOCKVECTOR_NBLOCKS (blockvector) = i;
+ for (next = pending_blocks; next; next = next->next)
+ BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
+
+ /* Now free the links of the list, and empty the list. */
+
+ for (next = pending_blocks; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+ pending_blocks = 0;
+
+ return blockvector;
+}
+
+/* Manage the vector of line numbers. */
+
+static
+record_line (line, pc)
+ int line;
+ CORE_ADDR pc;
+{
+ struct linetable_entry *e;
+ /* Make sure line vector is big enough. */
+
+ if (line_vector_index + 2 >= line_vector_length)
+ {
+ line_vector_length *= 2;
+ line_vector = (struct linetable *)
+ xrealloc (line_vector, sizeof (struct linetable)
+ + (line_vector_length
+ * sizeof (struct linetable_entry)));
+ }
+
+ e = line_vector->item + line_vector_index++;
+ e->line = line; e->pc = pc;
+}
+
+/* Start a new symtab for a new source file.
+ This is called when a COFF ".file" symbol is seen;
+ it indicates the start of data for one original source file. */
+
+static void
+start_symtab ()
+{
+ file_symbols = 0;
+ global_symbols = 0;
+ context_stack = 0;
+ within_function = 0;
+ last_source_file = 0;
+
+ /* Initialize the source file information for this file. */
+
+ line_vector_index = 0;
+ line_vector_length = 1000;
+ prev_line_number = -2; /* Force first line number to be explicit */
+ line_vector = (struct linetable *)
+ xmalloc (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry));
+}
+
+/* Save the vital information for use when closing off the current file.
+ NAME is the file name the symbols came from, START_ADDR is the first
+ text address for the file, and SIZE is the number of bytes of text. */
+
+static void
+complete_symtab (name, start_addr, size)
+ char *name;
+ CORE_ADDR start_addr;
+ unsigned int size;
+{
+ last_source_file = savestring (name, strlen (name));
+ cur_src_start_addr = start_addr;
+ cur_src_end_addr = start_addr + size;
+}
+
+/* Finish the symbol definitions for one main source file,
+ close off all the lexical contexts for that file
+ (creating struct block's for them), then make the
+ struct symtab for that file and put it in the list of all such. */
+
+static void
+end_symtab ()
+{
+ register struct symtab *symtab;
+ register struct context_stack *cstk;
+ register struct blockvector *blockvector;
+ register struct linetable *lv;
+
+ /* Finish the lexical context of the last function in the file. */
+
+ if (context_stack)
+ {
+ cstk = context_stack;
+ context_stack = 0;
+ /* Make a block for the local symbols within. */
+ finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+ cstk->start_addr, cur_src_end_addr);
+ free (cstk);
+ }
+
+ /* Ignore a file that has no functions with real debugging info. */
+ if (pending_blocks == 0 && file_symbols == 0 && global_symbols == 0)
+ {
+ free (line_vector);
+ line_vector = 0;
+ line_vector_length = -1;
+ last_source_file = 0;
+ return;
+ }
+
+ /* Create the two top-level blocks for this file. */
+ finish_block (0, &file_symbols, 0, cur_src_start_addr, cur_src_end_addr);
+ finish_block (0, &global_symbols, 0, cur_src_start_addr, cur_src_end_addr);
+
+ /* Create the blockvector that points to all the file's blocks. */
+ blockvector = make_blockvector ();
+
+ /* Now create the symtab object for this source file. */
+ symtab = (struct symtab *) xmalloc (sizeof (struct symtab));
+ symtab->free_ptr = 0;
+
+ /* Fill in its components. */
+ symtab->blockvector = blockvector;
+ symtab->free_code = free_linetable;
+ symtab->filename = last_source_file;
+ lv = line_vector;
+ lv->nitems = line_vector_index;
+ symtab->linetable = (struct linetable *)
+ xrealloc (lv, (sizeof (struct linetable)
+ + lv->nitems * sizeof (struct linetable_entry)));
+ symtab->nlines = 0;
+ symtab->line_charpos = 0;
+
+ /* Link the new symtab into the list of such. */
+ symtab->next = symtab_list;
+ symtab_list = symtab;
+
+ /* Reinitialize for beginning of new file. */
+ line_vector = 0;
+ line_vector_length = -1;
+ last_source_file = 0;
+}
+
+/* Accumulate the misc functions in bunches of 127.
+ At the end, copy them all into one newly allocated structure. */
+
+#define MISC_BUNCH_SIZE 127
+
+struct misc_bunch
+{
+ struct misc_bunch *next;
+ struct misc_function contents[MISC_BUNCH_SIZE];
+};
+
+/* Bunch currently being filled up.
+ The next field points to chain of filled bunches. */
+
+static struct misc_bunch *misc_bunch;
+
+/* Number of slots filled in current bunch. */
+
+static int misc_bunch_index;
+
+/* Total number of misc functions recorded so far. */
+
+static int misc_count;
+
+static void
+init_misc_functions ()
+{
+ misc_count = 0;
+ misc_bunch = 0;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+}
+
+static void
+record_misc_function (name, address)
+ char *name;
+ CORE_ADDR address;
+{
+ register struct misc_bunch *new;
+
+ if (misc_bunch_index == MISC_BUNCH_SIZE)
+ {
+ new = (struct misc_bunch *) xmalloc (sizeof (struct misc_bunch));
+ misc_bunch_index = 0;
+ new->next = misc_bunch;
+ misc_bunch = new;
+ }
+ misc_bunch->contents[misc_bunch_index].name = savestring (name, strlen (name));
+ misc_bunch->contents[misc_bunch_index].address = address;
+ misc_bunch_index++;
+ misc_count++;
+}
+
+/* if we see a function symbol, we do record_misc_function.
+ * however, if it turns out the next symbol is '.bf', then
+ * we call here to undo the misc definition
+ */
+static void
+unrecord_misc_function ()
+{
+ if (misc_bunch_index == 0)
+ error ("Internal error processing symbol table, at symbol %d.",
+ symnum);
+ misc_bunch_index--;
+ misc_count--;
+}
+
+
+static int
+compare_misc_functions (fn1, fn2)
+ struct misc_function *fn1, *fn2;
+{
+ /* Return a signed result based on unsigned comparisons
+ so that we sort into unsigned numeric order. */
+ if (fn1->address < fn2->address)
+ return -1;
+ if (fn1->address > fn2->address)
+ return 1;
+ return 0;
+}
+
+static void
+discard_misc_bunches ()
+{
+ register struct misc_bunch *next;
+
+ while (misc_bunch)
+ {
+ next = misc_bunch->next;
+ free (misc_bunch);
+ misc_bunch = next;
+ }
+}
+
+static void
+condense_misc_bunches ()
+{
+ register int i, j;
+ register struct misc_bunch *bunch;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ misc_function_vector
+ = (struct misc_function *)
+ xmalloc (misc_count * sizeof (struct misc_function));
+
+ j = 0;
+ bunch = misc_bunch;
+ while (bunch)
+ {
+ for (i = 0; i < misc_bunch_index; i++)
+ {
+ register char *tmp;
+
+ misc_function_vector[j] = bunch->contents[i];
+ tmp = misc_function_vector[j].name;
+ misc_function_vector[j].name = (tmp[0] == '_' ? tmp + offset : tmp);
+ j++;
+ }
+ bunch = bunch->next;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+ }
+
+ misc_function_count = j;
+
+ /* Sort the misc functions by address. */
+
+ qsort (misc_function_vector, j, sizeof (struct misc_function),
+ compare_misc_functions);
+}
+
+/* Call sort_syms to sort alphabetically
+ the symbols of each block of each symtab. */
+
+static int
+compare_symbols (s1, s2)
+ struct symbol **s1, **s2;
+{
+ /* Names that are less should come first. */
+ register int namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
+ if (namediff != 0) return namediff;
+ /* For symbols of the same name, registers should come first. */
+ return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
+ - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
+}
+
+static void
+sort_syms ()
+{
+ register struct symtab *s;
+ register int i, nbl;
+ register struct blockvector *bv;
+ register struct block *b;
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bv = BLOCKVECTOR (s);
+ nbl = BLOCKVECTOR_NBLOCKS (bv);
+ for (i = 0; i < nbl; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ if (BLOCK_SHOULD_SORT (b))
+ qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ sizeof (struct symbol *), compare_symbols);
+ }
+ }
+}
+
+/* This is the symbol-file command. Read the file, analyze its symbols,
+ and add a struct symtab to symtab_list. */
+
+void
+symbol_file_command (name)
+ char *name;
+{
+ int desc;
+ int num_symbols;
+ int num_sections;
+ int symtab_offset;
+ extern void close ();
+ register int val;
+ struct cleanup *old_chain;
+
+ dont_repeat ();
+
+ if (name == 0)
+ {
+ if (symtab_list && !query ("Discard symbol table? ", 0))
+ error ("Not confirmed.");
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ return;
+ }
+
+ if (symtab_list && !query ("Load new symbol table from \"%s\"? ", name))
+ error ("Not confirmed.");
+
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+
+ {
+ char *absolute_name;
+
+ desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name);
+ if (desc < 0)
+ perror_with_name (name);
+ else
+ name = absolute_name;
+ }
+
+ old_chain = make_cleanup (close, desc);
+ make_cleanup (free_current_contents, &name);
+
+ if ((num_symbols = read_file_hdr (desc, &file_hdr)) < 0)
+ error ("File \"%s\" not in executable format.", name);
+
+ if (num_symbols == 0)
+ {
+ free_all_symtabs ();
+ printf ("%s does not have a symbol-table.\n", name);
+ fflush (stdout);
+ return;
+ }
+
+ printf ("Reading symbol data from %s...", name);
+ fflush (stdout);
+
+ /* Throw away the old symbol table. */
+
+ free_all_symtabs ();
+ free_all_psymtabs (); /* Make sure that partial_symtab_list */
+ /* is 0 also. */
+
+ num_sections = file_hdr.f_nscns;
+ symtab_offset = file_hdr.f_symptr;
+
+ if (read_section_hdr (desc, _TEXT, &text_hdr, num_sections) < 0)
+ error ("\"%s\": can't read text section header", name);
+
+ /* Read the line number table, all at once. */
+
+ val = init_lineno (desc, text_hdr.s_lnnoptr, text_hdr.s_nlnno);
+ if (val < 0)
+ error ("\"%s\": error reading line numbers\n", name);
+
+ /* Now read the string table, all at once. */
+
+ val = init_stringtab (desc, symtab_offset + num_symbols * SYMESZ);
+ if (val < 0)
+ {
+ free_all_symtabs ();
+ printf ("\"%s\": can't get string table", name);
+ fflush (stdout);
+ return;
+ }
+ make_cleanup (free_stringtab, 0);
+
+ /* Position to read the symbol table. Do not read it all at once. */
+ val = lseek (desc, (long)symtab_offset, 0);
+ if (val < 0)
+ perror_with_name (name);
+
+ init_misc_functions ();
+ make_cleanup (discard_misc_bunches, 0);
+
+ /* Now that the executable file is positioned at symbol table,
+ process it and define symbols accordingly. */
+
+ read_coff_symtab (desc, num_symbols);
+
+ patch_opaque_types ();
+
+ /* Sort symbols alphabetically within each block. */
+
+ sort_syms ();
+
+ /* Go over the misc functions and install them in vector. */
+
+ condense_misc_bunches ();
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+ /* Make a default for file to list. */
+
+ select_source_symtab (symtab_list);
+
+ symfile = savestring (name, strlen (name));
+
+ do_cleanups (old_chain);
+
+ printf ("done.\n");
+ fflush (stdout);
+}
+
+/* Return name of file symbols were loaded from, or 0 if none.. */
+
+char *
+get_sym_file ()
+{
+ return symfile;
+}
+
+/* Simplified internal version of coff symbol table information */
+
+struct coff_symbol {
+ char *c_name;
+ int c_symnum; /* symbol number of this entry */
+ int c_nsyms; /* 1 if syment only, 2 if syment + auxent */
+ long c_value;
+ int c_sclass;
+ int c_secnum;
+ unsigned int c_type;
+};
+
+/* Given pointers to a symbol table in coff style exec file,
+ analyze them and create struct symtab's describing the symbols.
+ NSYMS is the number of symbols in the symbol table.
+ We read them one at a time using read_one_sym (). */
+
+static void
+read_coff_symtab (desc, nsyms)
+ int desc;
+ int nsyms;
+{
+ int newfd; /* Avoid multiple closes on same desc */
+ FILE *stream;
+ register struct context_stack *new;
+ struct coff_symbol coff_symbol;
+ register struct coff_symbol *cs = &coff_symbol;
+ static SYMENT main_sym;
+ static AUXENT main_aux;
+ struct coff_symbol fcn_cs_saved;
+ static SYMENT fcn_sym_saved;
+ static AUXENT fcn_aux_saved;
+
+ int num_object_files = 0;
+ int next_file_symnum = -1;
+ char *filestring;
+ int depth;
+ int fcn_first_line;
+ int fcn_last_line;
+ int fcn_start_addr;
+ long fcn_line_ptr;
+ struct cleanup *old_chain;
+ int fclose();
+
+ newfd = dup (desc);
+ if (newfd == -1)
+ fatal ("Too many open files");
+ stream = fdopen (newfd, "r");
+
+ old_chain = make_cleanup (free_all_symtabs, 0);
+ make_cleanup (fclose, stream);
+ nlist_stream_global = stream;
+ nlist_nsyms_global = nsyms;
+ last_source_file = 0;
+ bzero (opaque_type_chain, sizeof opaque_type_chain);
+
+ type_vector_length = 160;
+ type_vector = (struct typevector *)
+ xmalloc (sizeof (struct typevector)
+ + type_vector_length * sizeof (struct type *));
+ bzero (type_vector->type, type_vector_length * sizeof (struct type *));
+
+ start_symtab ();
+
+ symnum = 0;
+ while (symnum < nsyms)
+ {
+ QUIT; /* Make this command interruptable. */
+ read_one_sym (cs, &main_sym, &main_aux);
+
+ if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE)
+ {
+ CORE_ADDR last_file_end = cur_src_end_addr;
+
+ if (last_source_file)
+ end_symtab ();
+
+ start_symtab ();
+ complete_symtab ("_globals_", 0, first_object_file_end);
+ /* done with all files, everything from here on out is globals */
+ }
+
+ /* Special case for file with type declarations only, no text. */
+ if (!last_source_file && cs->c_type != T_NULL && cs->c_secnum == N_DEBUG)
+ complete_symtab (filestring, 0, 0);
+
+ /* Typedefs should not be treated as symbol definitions. */
+ if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF)
+ {
+ /* record as misc function. if we get '.bf' next,
+ * then we undo this step
+ */
+ record_misc_function (cs->c_name, cs->c_value);
+
+ fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr;
+ fcn_start_addr = cs->c_value;
+ fcn_cs_saved = *cs;
+ fcn_sym_saved = main_sym;
+ fcn_aux_saved = main_aux;
+ continue;
+ }
+
+ switch (cs->c_sclass)
+ {
+ case C_EFCN:
+ case C_EXTDEF:
+ case C_ULABEL:
+ case C_USTATIC:
+ case C_LINE:
+ case C_ALIAS:
+ case C_HIDDEN:
+ printf ("Bad n_sclass = %d\n", cs->c_sclass);
+ break;
+
+ case C_FILE:
+ /*
+ * c_value field contains symnum of next .file entry in table
+ * or symnum of first global after last .file.
+ */
+ next_file_symnum = cs->c_value;
+ filestring = getfilename (&main_aux);
+ /*
+ * Complete symbol table for last object file
+ * containing debugging information.
+ */
+ if (last_source_file)
+ {
+ end_symtab ();
+ start_symtab ();
+ }
+ num_object_files++;
+ break;
+
+ case C_STAT:
+ if (cs->c_name[0] == '.') {
+ if (strcmp (cs->c_name, _TEXT) == 0) {
+ if (num_object_files == 1) {
+ /* last address of startup file */
+ first_object_file_end = cs->c_value +
+ main_aux.x_scn.x_scnlen;
+ }
+ /* for some reason the old code didn't do
+ * this if this section entry had
+ * main_aux.x_scn.x_nlinno equal to 0
+ */
+ complete_symtab (filestring, cs->c_value,
+ main_aux.x_scn.x_scnlen);
+ }
+ /* flush rest of '.' symbols */
+ break;
+ }
+ /* fall in for static symbols that don't start with '.' */
+ case C_EXT:
+ if (cs->c_sclass == C_EXT &&
+ cs->c_secnum == N_ABS &&
+ strcmp (cs->c_name, _ETEXT) == 0)
+ end_of_text_addr = cs->c_value;
+ if (cs->c_type == T_NULL) {
+ if (cs->c_secnum <= 1) { /* text or abs */
+ record_misc_function (cs->c_name, cs->c_value);
+ break;
+ } else {
+ cs->c_type = T_INT;
+ }
+ }
+ (void) process_coff_symbol (cs, &main_aux);
+ break;
+
+ case C_FCN:
+ if (strcmp (cs->c_name, ".bf") == 0)
+ {
+ unrecord_misc_function ();
+
+ within_function = 1;
+
+ /* value contains address of first non-init type code */
+ /* main_aux.x_sym.x_misc.x_lnsz.x_lnno
+ contains line number of '{' } */
+ fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+
+ new = (struct context_stack *)
+ xmalloc (sizeof (struct context_stack));
+ new->depth = depth = 0;
+ new->next = 0;
+ context_stack = new;
+ new->locals = 0;
+ new->old_blocks = pending_blocks;
+ new->start_addr = fcn_start_addr;
+ fcn_cs_saved.c_name = getsymname (&fcn_sym_saved);
+ new->name = process_coff_symbol (&fcn_cs_saved,
+ &fcn_aux_saved);
+ }
+ else if (strcmp (cs->c_name, ".ef") == 0)
+ {
+ /* the value of .ef is the address of epilogue code;
+ * not useful for gdb
+ */
+ /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno
+ contains number of lines to '}' */
+ fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+ enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line);
+ new = context_stack;
+
+ if (new == 0)
+ error ("Invalid symbol data; .bf/.ef/.bb/.eb symbol mismatch, at symbol %d.",
+ symnum);
+
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr,
+ fcn_cs_saved.c_value +
+ fcn_aux_saved.x_sym.x_misc.x_fsize);
+ context_stack = 0;
+ within_function = 0;
+ free (new);
+ }
+ break;
+
+ case C_BLOCK:
+ if (strcmp (cs->c_name, ".bb") == 0)
+ {
+ new = (struct context_stack *)
+ xmalloc (sizeof (struct context_stack));
+ depth++;
+ new->depth = depth;
+ new->next = context_stack;
+ context_stack = new;
+ new->locals = local_symbols;
+ new->old_blocks = pending_blocks;
+ new->start_addr = cs->c_value;
+ new->name = 0;
+ local_symbols = 0;
+ }
+ else if (strcmp (cs->c_name, ".eb") == 0)
+ {
+ new = context_stack;
+ if (new == 0 || depth != new->depth)
+ error ("Invalid symbol data: .bb/.eb symbol mismatch at symbol %d.",
+ symnum);
+ if (local_symbols && context_stack->next)
+ {
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr, cs->c_value);
+ }
+ depth--;
+ local_symbols = new->locals;
+ context_stack = new->next;
+ free (new);
+ }
+ break;
+
+ default:
+ (void) process_coff_symbol (cs, &main_aux);
+ break;
+ }
+ }
+
+ if (last_source_file)
+ end_symtab ();
+ fclose (stream);
+ discard_cleanups (old_chain);
+}
+
+/* Routines for reading headers and symbols from executable. */
+
+/* Read COFF file header, check magic number,
+ and return number of symbols. */
+read_file_hdr (chan, file_hdr)
+ int chan;
+ FILHDR *file_hdr;
+{
+ lseek (chan, 0L, 0);
+ if (myread (chan, (char *)file_hdr, FILHSZ) < 0)
+ return -1;
+
+ switch (file_hdr->f_magic)
+ {
+#ifdef NS32GMAGIC
+ case NS32GMAGIC:
+ case NS32SMAGIC:
+#endif
+#ifdef I386MAGIC
+ case I386MAGIC:
+#endif
+ return file_hdr->f_nsyms;
+
+
+ default:
+#ifdef BADMAG
+ if (BADMAG(file_hdr))
+ return -1;
+ else
+ return file_hdr->f_nsyms;
+#else
+ return -1;
+#endif
+ }
+}
+
+read_aout_hdr (chan, aout_hdr, size)
+ int chan;
+ AOUTHDR *aout_hdr;
+ int size;
+{
+ lseek (chan, (long)FILHSZ, 0);
+ if (size != sizeof (AOUTHDR))
+ return -1;
+ if (myread (chan, (char *)aout_hdr, size) != size)
+ return -1;
+ return 0;
+}
+
+read_section_hdr (chan, section_name, section_hdr, nsects)
+ register int chan;
+ register char *section_name;
+ SCNHDR *section_hdr;
+ register int nsects;
+{
+ register int i;
+
+ if (lseek (chan, FILHSZ + sizeof (AOUTHDR), 0) < 0)
+ return -1;
+
+ for (i = 0; i < nsects; i++)
+ {
+ if (myread (chan, (char *)section_hdr, SCNHSZ) < 0)
+ return -1;
+ if (strncmp (section_hdr->s_name, section_name, 8) == 0)
+ return 0;
+ }
+ return -1;
+}
+
+read_one_sym (cs, sym, aux)
+ register struct coff_symbol *cs;
+ register SYMENT *sym;
+ register AUXENT *aux;
+{
+ cs->c_symnum = symnum;
+ fread ((char *)sym, SYMESZ, 1, nlist_stream_global);
+ cs->c_nsyms = (sym->n_numaux & 0xff) + 1;
+ if (cs->c_nsyms == 2)
+ {
+ /* doc for coff says there is either no aux entry or just one */
+ fread ((char *)aux, AUXESZ, 1, nlist_stream_global);
+ }
+ else if (cs->c_nsyms > 2)
+ error ("more than one aux symbol table entry at symnum=%d\n", symnum);
+
+ cs->c_name = getsymname (sym);
+ cs->c_value = sym->n_value;
+ cs->c_sclass = (sym->n_sclass & 0xff);
+ cs->c_secnum = sym->n_scnum;
+ cs->c_type = (unsigned) sym->n_type;
+
+ symnum += cs->c_nsyms;
+}
+
+/* Support for string table handling */
+
+static char *stringtab = NULL;
+
+static int
+init_stringtab (chan, offset)
+ int chan;
+ long offset;
+{
+ long buffer;
+ int val;
+
+ if (stringtab)
+ {
+ free (stringtab);
+ stringtab = NULL;
+ }
+
+ if (lseek (chan, offset, 0) < 0)
+ return -1;
+
+ val = myread (chan, (char *)&buffer, sizeof buffer);
+
+ /* If no string table is needed, then the file may end immediately
+ after the symbols. Just return with `stringtab' set to null. */
+ if (val != sizeof buffer || buffer == 0)
+ return 0;
+
+ stringtab = (char *) xmalloc (buffer);
+ if (stringtab == NULL)
+ return -1;
+
+ bcopy (&buffer, stringtab, sizeof buffer);
+
+ val = myread (chan, stringtab + sizeof buffer, buffer - sizeof buffer);
+ if (val != buffer - sizeof buffer || stringtab[buffer - 1] != '\0')
+ return -1;
+
+ return 0;
+}
+
+static void
+free_stringtab ()
+{
+ if (stringtab)
+ free (stringtab);
+ stringtab = NULL;
+}
+
+static char *
+getsymname (symbol_entry)
+ SYMENT *symbol_entry;
+{
+ static char buffer[SYMNMLEN+1];
+ char *result;
+
+ if (symbol_entry->n_zeroes == 0)
+ {
+ result = stringtab + symbol_entry->n_offset;
+ }
+ else
+ {
+ strncpy (buffer, symbol_entry->n_name, SYMNMLEN);
+ buffer[SYMNMLEN] = '\0';
+ result = buffer;
+ }
+ return result;
+}
+
+static char *
+getfilename (aux_entry)
+ AUXENT *aux_entry;
+{
+ static char buffer[BUFSIZ];
+ register char *temp;
+ char *result;
+ extern char *rindex ();
+
+#ifndef COFF_NO_LONG_FILE_NAMES
+ if (aux_entry->x_file.x_foff != 0)
+ strcpy (buffer, stringtab + aux_entry->x_file.x_foff);
+ else
+#endif
+ {
+ strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN);
+ buffer[FILNMLEN] = '\0';
+ }
+ result = buffer;
+ if ((temp = rindex (result, '/')) != NULL)
+ result = temp + 1;
+ return (result);
+}
+
+/* Support for line number handling */
+static char *linetab = NULL;
+static long linetab_offset;
+static int linetab_count;
+
+static int
+init_lineno (chan, offset, count)
+ int chan;
+ long offset;
+ int count;
+{
+ int val;
+
+ if (lseek (chan, offset, 0) < 0)
+ return -1;
+
+ if (linetab)
+ free (linetab);
+ linetab = (char *) xmalloc (count * LINESZ);
+
+ val = myread (chan, linetab, count * LINESZ);
+ if (val != count * LINESZ)
+ return -1;
+
+ linetab_offset = offset;
+ linetab_count = count;
+ return 0;
+}
+
+static void
+enter_linenos (file_offset, first_line, last_line)
+ long file_offset;
+ register int first_line;
+ register int last_line;
+{
+ register char *rawptr = &linetab[file_offset - linetab_offset];
+ register struct lineno *lptr;
+
+ /* skip first line entry for each function */
+ rawptr += LINESZ;
+ /* line numbers start at one for the first line of the function */
+ first_line--;
+
+ for (lptr = (struct lineno *)rawptr;
+ lptr->l_lnno && lptr->l_lnno <= last_line;
+ rawptr += LINESZ, lptr = (struct lineno *)rawptr)
+ {
+ record_line (first_line + lptr->l_lnno, lptr->l_addr.l_paddr);
+ }
+}
+
+static int
+hashname (name)
+ char *name;
+{
+ register char *p = name;
+ register int total = p[0];
+ register int c;
+
+ c = p[1];
+ total += c << 2;
+ if (c)
+ {
+ c = p[2];
+ total += c << 4;
+ if (c)
+ total += p[3] << 6;
+ }
+
+ return total % HASHSIZE;
+}
+
+static void
+patch_type (type, real_type)
+ struct type *type;
+ struct type *real_type;
+{
+ register struct type *target = TYPE_TARGET_TYPE (type);
+ register struct type *real_target = TYPE_TARGET_TYPE (real_type);
+ int field_size = TYPE_NFIELDS (real_target) * sizeof (struct field);
+
+ TYPE_LENGTH (target) = TYPE_LENGTH (real_target);
+ TYPE_NFIELDS (target) = TYPE_NFIELDS (real_target);
+ TYPE_FIELDS (target) = (struct field *)
+ obstack_alloc (symbol_obstack, field_size);
+
+ bcopy (TYPE_FIELDS (real_target), TYPE_FIELDS (target), field_size);
+
+ if (TYPE_NAME (real_target))
+ {
+ if (TYPE_NAME (target))
+ free (TYPE_NAME (target));
+ TYPE_NAME (target) = concat (TYPE_NAME (real_target), "", "");
+ }
+}
+
+/* Patch up all appropriate typdef symbols in the opaque_type_chains
+ so that they can be used to print out opaque data structures properly */
+
+static void
+patch_opaque_types ()
+{
+ struct symtab *s;
+
+ /* Look at each symbol in the per-file block of each symtab. */
+ for (s = symtab_list; s; s = s->next)
+ {
+ register struct block *b;
+ register int i;
+
+ /* Go through the per-file symbols only */
+ b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1);
+ for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--)
+ {
+ register struct symbol *real_sym;
+
+ /* Find completed typedefs to use to fix opaque ones.
+ Remove syms from the chain when their types are stored,
+ but search the whole chain, as there may be several syms
+ from different files with the same name. */
+ real_sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF &&
+ SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE &&
+ TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0)
+ {
+ register char *name = SYMBOL_NAME (real_sym);
+ register int hash = hashname (name);
+ register struct symbol *sym, *prev;
+
+ prev = 0;
+ for (sym = opaque_type_chain[hash]; sym;)
+ {
+ if (name[0] == SYMBOL_NAME (sym)[0] &&
+ !strcmp (name + 1, SYMBOL_NAME (sym) + 1))
+ {
+ if (prev)
+ SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym);
+ else
+ opaque_type_chain[hash]
+ = (struct symbol *) SYMBOL_VALUE (sym);
+
+ patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym));
+
+ if (prev)
+ sym = (struct symbol *) SYMBOL_VALUE (prev);
+ else
+ sym = opaque_type_chain[hash];
+ }
+ else
+ {
+ prev = sym;
+ sym = (struct symbol *) SYMBOL_VALUE (sym);
+ }
+ }
+ }
+ }
+ }
+}
+
+static struct symbol *
+process_coff_symbol (cs, aux)
+ register struct coff_symbol *cs;
+ register AUXENT *aux;
+{
+ register struct symbol *sym
+ = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+ char *name;
+ char *dot;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ bzero (sym, sizeof (struct symbol));
+ name = cs->c_name;
+ name = (name[0] == '_' ? name + offset : name);
+ SYMBOL_NAME (sym) = obstack_copy0 (symbol_obstack, name, strlen (name));
+
+ /* default assumptions */
+ SYMBOL_VALUE (sym) = cs->c_value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+ if (ISFCN (cs->c_type))
+ {
+ SYMBOL_TYPE (sym) =
+ lookup_function_type (decode_function_type (cs, cs->c_type, aux));
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ if (cs->c_sclass == C_STAT)
+ add_symbol_to_list (sym, &file_symbols);
+ else if (cs->c_sclass == C_EXT)
+ add_symbol_to_list (sym, &global_symbols);
+ }
+ else
+ {
+ SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux);
+ switch (cs->c_sclass)
+ {
+ case C_NULL:
+ break;
+
+ case C_AUTO:
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case C_EXT:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ case C_STAT:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ if (within_function) {
+ /* Static symbol of local scope */
+ add_symbol_to_list (sym, &local_symbols);
+ }
+ else {
+ /* Static symbol at top level of file */
+ add_symbol_to_list (sym, &file_symbols);
+ }
+ break;
+
+ case C_REG:
+ case C_REGPARM:
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case C_LABEL:
+ break;
+
+ case C_ARG:
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ add_symbol_to_list (sym, &local_symbols);
+ /* If PCC says a parameter is a short or a char,
+ it is really an int. */
+ if (SYMBOL_TYPE (sym) == builtin_type_char
+ || SYMBOL_TYPE (sym) == builtin_type_short)
+ SYMBOL_TYPE (sym) = builtin_type_int;
+ else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char
+ || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+ SYMBOL_TYPE (sym) = builtin_type_unsigned_int;
+ break;
+
+ case C_TPDEF:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+ /* If type has no name, give it one */
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+ && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = concat (SYMBOL_NAME (sym), "", "");
+
+ /* Keep track of any type which points to empty structured type,
+ so it can be filled from a definition from another file */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR &&
+ TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0)
+ {
+ register int i = hashname (SYMBOL_NAME (sym));
+
+ SYMBOL_VALUE (sym) = (int) opaque_type_chain[i];
+ opaque_type_chain[i] = sym;
+ }
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case C_STRTAG:
+ case C_UNTAG:
+ case C_ENTAG:
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+ && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = concat ("",
+ (cs->c_sclass == C_ENTAG
+ ? "enum "
+ : (cs->c_sclass == C_STRTAG
+ ? "struct " : "union ")),
+ SYMBOL_NAME (sym));
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return sym;
+}
+
+/* Decode a coff type specifier;
+ return the type that is meant. */
+
+static
+struct type *
+decode_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register AUXENT *aux;
+{
+ register struct type *type = 0;
+ register int n;
+ unsigned int new_c_type;
+
+ if (c_type & ~N_BTMASK)
+ {
+ new_c_type = DECREF (c_type);
+ if (ISPTR (c_type))
+ {
+ type = decode_type (cs, new_c_type, aux);
+ type = lookup_pointer_type (type);
+ }
+ else if (ISFCN (c_type))
+ {
+ type = decode_type (cs, new_c_type, aux);
+ type = lookup_function_type (type);
+ }
+ else if (ISARY (c_type))
+ {
+ int i, n;
+ register unsigned short *dim;
+ struct type *base_type;
+
+ /* Define an array type. */
+ /* auxent refers to array, not base type */
+ if (aux->x_sym.x_tagndx == 0)
+ cs->c_nsyms = 1;
+
+ /* shift the indices down */
+ dim = &aux->x_sym.x_fcnary.x_ary.x_dimen[0];
+ i = 1;
+ n = dim[0];
+ for (i = 0; *dim && i < DIMNUM - 1; i++, dim++)
+ *dim = *(dim + 1);
+ *dim = 0;
+
+ type = (struct type *)
+ obstack_alloc (symbol_obstack, sizeof (struct type));
+ bzero (type, sizeof (struct type));
+
+ base_type = decode_type (cs, new_c_type, aux);
+
+ TYPE_CODE (type) = TYPE_CODE_ARRAY;
+ TYPE_TARGET_TYPE (type) = base_type;
+ TYPE_LENGTH (type) = n * TYPE_LENGTH (base_type);
+ }
+ return type;
+ }
+
+ /* Reference to existing type */
+ if (cs->c_nsyms > 1 && aux->x_sym.x_tagndx != 0)
+ {
+ type = coff_alloc_type (aux->x_sym.x_tagndx);
+ return type;
+ }
+
+ return decode_base_type (cs, BTYPE (c_type), aux);
+}
+
+/* Decode a coff type specifier for function definition;
+ return the type that the function returns. */
+
+static
+struct type *
+decode_function_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register AUXENT *aux;
+{
+ if (aux->x_sym.x_tagndx == 0)
+ cs->c_nsyms = 1; /* auxent refers to function, not base type */
+
+ return decode_type (cs, DECREF (cs->c_type), aux);
+}
+
+/* basic C types */
+
+static
+struct type *
+decode_base_type (cs, c_type, aux)
+ register struct coff_symbol *cs;
+ unsigned int c_type;
+ register AUXENT *aux;
+{
+ struct type *type;
+
+ switch (c_type)
+ {
+ case T_NULL:
+ /* shows up with "void (*foo)();" structure members */
+ return builtin_type_void;
+
+ case T_ARG:
+ /* shouldn't show up here */
+ break;
+
+ case T_CHAR:
+ return builtin_type_char;
+
+ case T_SHORT:
+ return builtin_type_short;
+
+ case T_INT:
+ return builtin_type_int;
+
+ case T_LONG:
+ return builtin_type_long;
+
+ case T_FLOAT:
+ return builtin_type_float;
+
+ case T_DOUBLE:
+ return builtin_type_double;
+
+ case T_STRUCT:
+ if (cs->c_nsyms != 2)
+ {
+ /* anonymous structure type */
+ type = coff_alloc_type (cs->c_symnum);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ TYPE_NAME (type) = concat ("struct ", "<opaque>", "");
+ TYPE_LENGTH (type) = 0;
+ TYPE_FIELDS (type) = 0;
+ TYPE_NFIELDS (type) = 0;
+ }
+ else
+ {
+ type = read_struct_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx);
+ }
+ return type;
+
+ case T_UNION:
+ if (cs->c_nsyms != 2)
+ {
+ /* anonymous union type */
+ type = coff_alloc_type (cs->c_symnum);
+ TYPE_NAME (type) = concat ("union ", "<opaque>", "");
+ TYPE_LENGTH (type) = 0;
+ TYPE_FIELDS (type) = 0;
+ TYPE_NFIELDS (type) = 0;
+ }
+ else
+ {
+ type = read_struct_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx);
+ }
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ return type;
+
+ case T_ENUM:
+ return read_enum_type (cs->c_symnum,
+ aux->x_sym.x_misc.x_lnsz.x_size,
+ aux->x_sym.x_fcnary.x_fcn.x_endndx);
+
+ case T_MOE:
+ /* shouldn't show up here */
+ break;
+
+ case T_UCHAR:
+ return builtin_type_unsigned_char;
+
+ case T_USHORT:
+ return builtin_type_unsigned_short;
+
+ case T_UINT:
+ return builtin_type_unsigned_int;
+
+ case T_ULONG:
+ return builtin_type_unsigned_long;
+ }
+ printf ("unexpected type %d at symnum %d\n", c_type, cs->c_symnum);
+ return builtin_type_void;
+}
+
+/* This page contains subroutines of read_type. */
+
+/* Read the description of a structure (or union type)
+ and return an object describing the type. */
+
+static struct type *
+read_struct_type (index, length, lastsym)
+ int index;
+ int length;
+ int lastsym;
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+ struct field field;
+ };
+
+ register struct type *type;
+ register struct nextfield *list = 0;
+ struct nextfield *new;
+ int nfields = 0;
+ register int n;
+ char *name;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+ struct coff_symbol member_sym;
+ register struct coff_symbol *ms = &member_sym;
+ SYMENT sub_sym;
+ AUXENT sub_aux;
+ int done = 0;
+
+ type = coff_alloc_type (index);
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ TYPE_LENGTH (type) = length;
+
+ while (!done && symnum < lastsym && symnum < nlist_nsyms_global)
+ {
+ read_one_sym (ms, &sub_sym, &sub_aux);
+ name = ms->c_name;
+ name = (name[0] == '_' ? name + offset : name);
+
+ switch (ms->c_sclass)
+ {
+ case C_MOS:
+ case C_MOU:
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Save the data. */
+ list->field.name = savestring (name, strlen (name));
+ list->field.type = decode_type (ms, ms->c_type, &sub_aux);
+ list->field.bitpos = 8 * ms->c_value;
+ list->field.bitsize = 0;
+ nfields++;
+ break;
+
+ case C_FIELD:
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Save the data. */
+ list->field.name = savestring (name, strlen (name));
+ list->field.type = decode_type (ms, ms->c_type, &sub_aux);
+ list->field.bitpos = ms->c_value;
+ list->field.bitsize = sub_aux.x_sym.x_misc.x_lnsz.x_size;
+ nfields++;
+ break;
+
+ case C_EOS:
+ done = 1;
+ break;
+ }
+ }
+ /* Now create the vector of fields, and record how big it is. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (symbol_obstack, sizeof (struct field) * nfields);
+
+ /* Copy the saved-up fields into the field vector. */
+
+ for (n = nfields; list; list = list->next)
+ TYPE_FIELD (type, --n) = list->field;
+
+ return type;
+}
+
+/* Read a definition of an enumeration type,
+ and create and return a suitable type object.
+ Also defines the symbols that represent the values of the type. */
+
+static struct type *
+read_enum_type (index, length, lastsym)
+ int index;
+ int length;
+ int lastsym;
+{
+ register struct symbol *sym;
+ register struct type *type;
+ int nsyms = 0;
+ struct pending **symlist;
+ struct coff_symbol member_sym;
+ register struct coff_symbol *ms = &member_sym;
+ SYMENT sub_sym;
+ AUXENT sub_aux;
+ struct pending *osyms, *syms;
+ register int n;
+ char *name;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ type = coff_alloc_type (index);
+ if (within_function)
+ symlist = &local_symbols;
+ else
+ symlist = &file_symbols;
+ osyms = *symlist;
+
+ while (symnum < lastsym && symnum < nlist_nsyms_global)
+ {
+ read_one_sym (ms, &sub_sym, &sub_aux);
+ name = ms->c_name;
+ name = (name[0] == '_' ? name + offset : name);
+
+ switch (ms->c_sclass)
+ {
+ case C_MOE:
+ sym = (struct symbol *) xmalloc (sizeof (struct symbol));
+ bzero (sym, sizeof (struct symbol));
+
+ SYMBOL_NAME (sym) = savestring (name, strlen (name));
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (sym) = ms->c_value;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ break;
+
+ case C_EOS:
+ break;
+ }
+ }
+
+ /* Now fill in the fields of the type-structure. */
+
+ TYPE_LENGTH (type) = sizeof (int);
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *)
+ obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the values and put them into the type.
+ The symbols can be found in the symlist that we put them on
+ to cause them to be defined. osyms contains the old value
+ of that symlist; everything up to there was defined by us. */
+
+ for (syms = *symlist, n = nsyms; syms != osyms; syms = syms->next)
+ {
+ SYMBOL_TYPE (syms->symbol) = type;
+ TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (syms->symbol);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (syms->symbol);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ }
+ return type;
+}
+
+/* This function is really horrible, but to avoid it, there would need
+ to be more filling in of forward references. THIS SHOULD BE MOVED
+ OUT OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED. */
+int
+fill_in_vptr_fieldno (type)
+ struct type *type;
+{
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ TYPE_VPTR_FIELDNO (type) =
+ fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1));
+ return TYPE_VPTR_FIELDNO (type);
+}
+
+/* partial symbol tables are not implemented in coff, therefore
+ block_for_pc() (and others) will never decide to call this. */
+
+extern struct symtab *
+psymtab_to_symtab ()
+{
+ fatal ("error: Someone called psymtab_to_symtab\n");
+}
+
+/* These will stay zero all the time */
+struct partial_symbol *global_psymbols, *static_psymbols;
+
+_initialize_coff ()
+{
+ symfile = 0;
+
+ static_psymbols = global_psymbols = (struct partial_symbol *) 0;
+
+ add_com ("symbol-file", class_files, symbol_file_command,
+ "Load symbol table (in coff format) from executable file FILE.");
+}
+
+
+#endif /* COFF_FORMAT */
+
+@
+
+
+1.4
+log
+@Avoid A/UX change (#undef aux) for sending in to FSF.
+@
+text
+@d40 3
+@
+
+
+1.3
+log
+@A/UX and USG changes. If BADMAG defined, use it. Avoid <sys/fcntl.h>.
+Declare fclose(). #undef aux which we use as a var.
+@
+text
+@a39 3
+/* Avoid problems with A/UX predefine */
+#undef aux
+
+@
+
+
+1.2
+log
+@If discarding the symbol table, discard its name too, so "info files"
+will give the right answer.
+@
+text
+@d31 1
+a31 1
+#include <sys/fcntl.h>
+d40 3
+d847 1
+a847 1
+
+d1093 6
+d1100 1
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d5 1
+a5 1
+ Copyright (C) 1987, 1988 Free Software Foundation, Inc.
+d684 3
+@
diff --git a/gdb/RCS/config.gdb,v b/gdb/RCS/config.gdb,v
new file mode 100755
index 0000000..b569f62
--- /dev/null
+++ b/gdb/RCS/config.gdb,v
@@ -0,0 +1,229 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @@;
+
+
+1.2
+date 89.03.27.18.38.55; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.13.19.14.24; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Add A/UX option (config.gdb aux).
+@
+text
+@#!/bin/sh
+
+#
+# Shell script to create proper links to machine-dependent files in
+# preparation for compiling gdb.
+#
+# Usage: config.gdb machine [operating-system]
+#
+# If config.gdb succeeds, it leaves its status in config.status.
+# If config.gdb fails after disturbing the status quo,
+# config.status is removed.
+#
+
+progname=$0
+
+case $# in
+1)
+ machine=$1
+ os="none"
+ ;;
+2)
+ machine=$1
+ os=$2
+ ;;
+*)
+ echo "Usage: $progname machine [operating-system]"
+ echo "Available machine types:"
+ echo m-*.h | sed 's/m-//g' | sed 's/\.h//g'
+ if [ -r config.status ]
+ then
+ cat config.status
+ fi
+ exit 1
+ ;;
+esac
+
+paramfile=m-${machine}.h
+pinsnfile=${machine}-pinsn.c
+opcodefile=${machine}-opcode.h
+if [ -r ${machine}-dep.c ]
+then
+ depfile=${machine}-dep.c
+else
+ depfile=default-dep.c
+fi
+
+#
+# Special cases.
+# If a file is not needed, set the filename to 'skip' and it will be
+# ignored.
+#
+case $machine in
+aux)
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ ;;
+vax)
+ pinsnfile=vax-pinsn.c
+ opcodefile=vax-opcode.h
+ ;;
+hp9k320)
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ ;;
+isi)
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ ;;
+i386)
+ echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile"
+ opcodefile=skip
+ ;;
+i386gas)
+ echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile"
+ echo "Use of the coff encapsulation features also requires the GNU binutils utilities"
+ echo "to be ahead of their System V counterparts in your path."
+ pinsnfile=i386-pinsn.c
+ depfile=i386-dep.c
+ opcodefile=skip
+ ;;
+merlin)
+ pinsnfile=ns32k-pinsn.c
+ opcodefile=ns32k-opcode.h
+ ;;
+news)
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ ;;
+npl)
+ pinsnfile=gld-pinsn.c
+ ;;
+pn)
+ pinsnfile=gld-pinsn.c
+ ;;
+sun2)
+ case $os in
+ os4|sunos4)
+ paramfile=m-sun2os4.h
+ ;;
+ os2|sunos2)
+ paramfile=m-sun2os2.h
+ esac
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ ;;
+sun2os2)
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ ;;
+sun2os4)
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ ;;
+sun3)
+ case $os in
+ os4|sunos4)
+ paramfile=m-sun3os4.h
+ esac
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ ;;
+sun3os4)
+ pinsnfile=m68k-pinsn.c
+ opcodefile=m68k-opcode.h
+ depfile=sun3-dep.c
+ ;;
+sun4os4)
+ pinsnfile=sparc-pinsn.c
+ opcodefile=sparc-opcode.h
+ depfile=sparc-dep.c
+ ;;
+umax)
+ pinsnfile=ns32k-pinsn.c
+ opcodefile=ns32k-opcode.h
+ ;;
+sparc|sun4)
+ case $os in
+ os4|sunos4)
+ paramfile=m-sun4os4.h
+ esac
+ pinsnfile=sparc-pinsn.c
+ opcodefile=sparc-opcode.h
+ depfile=sparc-dep.c
+ paramfile=m-sparc.h
+ ;;
+test)
+ paramfile=one
+ pinsnfile=three
+ opcodefile=four
+ ;;
+*)
+ echo "Unknown machine type: \`$machine'"
+ echo "Available types:"
+ echo m-*.h | sed 's/m-//g' | sed 's/\.h//g'
+ exit 1
+esac
+
+files="$paramfile $pinsnfile $opcodefile $depfile"
+links="param.h pinsn.c opcode.h dep.c"
+
+while [ -n "$files" ]
+do
+ # set file to car of files, files to cdr of files
+ set $files; file=$1; shift; files=$*
+ set $links; link=$1; shift; links=$*
+
+ if [ "$file" != skip ]
+ then
+ if [ ! -r $file ]
+ then
+ echo "$progname: cannot create a link \`$link',"
+ echo "since the file \`$file' does not exist."
+ exit 1
+ fi
+
+ rm -f $link config.status
+ # Make a symlink if possible, otherwise try a hard link
+ ln -s $file $link 2>/dev/null || ln $file $link
+
+ if [ ! -r $link ]
+ then
+ echo "$progname: unable to link \`$link' to \`$file'."
+ exit 1
+ fi
+ echo "Linked \`$link' to \`$file'."
+ fi
+done
+
+echo "Links are now set up for use with a $machine." \
+ | tee config.status
+exit 0
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d53 4
+@
diff --git a/gdb/RCS/core.c,v b/gdb/RCS/core.c,v
new file mode 100644
index 0000000..f63081d
--- /dev/null
+++ b/gdb/RCS/core.c,v
@@ -0,0 +1,651 @@
+head 1.4;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.4
+date 89.03.27.18.39.18; author gnu; state Exp;
+branches ;
+next 1.3;
+
+1.3
+date 89.02.10.01.39.45; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.02.09.23.22.33; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.09.22.49.56; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.4
+log
+@Unisoft Assholes changes for user.ps. Avoid sys/fcntl.h.
+@
+text
+@/* Work with core dump and executable files, for GDB.
+ Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "param.h"
+#include "gdbcore.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+#include <a.out.h>
+#endif
+
+#ifndef N_MAGIC
+#ifdef COFF_FORMAT
+#define N_MAGIC(exec) ((exec).magic)
+#else
+#define N_MAGIC(exec) ((exec).a_magic)
+#endif
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#ifdef UNISOFT_ASSHOLES
+#define PMMU
+#define NEW_PMMU
+#include <sys/seg.h> /* Required for user.ps */
+#include <sys/time.h> /* '' */
+#include <sys/mmu.h> /* '' */
+#include <sys/reg.h>
+#define mc68881 /* Required to get float in user.ps */
+#endif
+
+#ifdef UMAX_CORE
+#include <sys/ptrace.h>
+#else
+#include <sys/user.h>
+#endif
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(hdr) 0
+#endif /* no N_TXTADDR */
+
+#ifndef N_DATADDR
+#define N_DATADDR(hdr) hdr.a_text
+#endif /* no N_DATADDR */
+
+#ifndef COFF_FORMAT
+#define AOUTHDR struct exec
+#endif
+
+extern char *sys_siglist[];
+
+extern core_file_command (), exec_file_command ();
+
+/* Hook for `exec_file_command' command to call. */
+
+void (*exec_file_display_hook) ();
+
+/* File names of core file and executable file. */
+
+char *corefile;
+char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+int corechan;
+int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+CORE_ADDR data_start;
+CORE_ADDR data_end;
+CORE_ADDR stack_start;
+CORE_ADDR stack_end;
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+CORE_ADDR text_start;
+CORE_ADDR text_end;
+
+CORE_ADDR exec_data_start;
+CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+int stack_offset;
+
+#ifdef COFF_FORMAT
+/* various coff data structures */
+
+FILHDR file_hdr;
+SCNHDR text_hdr;
+SCNHDR data_hdr;
+
+#endif /* not COFF_FORMAT */
+
+/* a.out header saved in core file. */
+
+AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+AOUTHDR exec_aouthdr;
+
+void validate_files ();
+unsigned int register_addr ();
+
+/* Call this to specify the hook for exec_file_command to call back.
+ This is called from the x-window display code. */
+
+void
+specify_exec_file_hook (hook)
+ void (*hook) ();
+{
+ exec_file_display_hook = hook;
+}
+
+/* The exec file must be closed before running an inferior.
+ If it is needed again after the inferior dies, it must
+ be reopened. */
+
+void
+close_exec_file ()
+{
+ if (execchan >= 0)
+ close (execchan);
+ execchan = -1;
+}
+
+void
+reopen_exec_file ()
+{
+ if (execchan < 0 && execfile != 0)
+ {
+ char *filename = concat (execfile, "", "");
+ exec_file_command (filename, 0);
+ free (filename);
+ }
+}
+
+/* If we have both a core file and an exec file,
+ print a warning if they don't go together.
+ This should really check that the core file came
+ from that exec file, but I don't know how to do it. */
+
+void
+validate_files ()
+{
+ if (execfile != 0 && corefile != 0)
+ {
+ struct stat st_core;
+
+ fstat (corechan, &st_core);
+
+ if (N_MAGIC (core_aouthdr) != 0
+ && bcmp (&core_aouthdr, &exec_aouthdr, sizeof core_aouthdr))
+ printf ("Warning: core file does not match specified executable file.\n");
+ else if (exec_mtime > st_core.st_mtime)
+ printf ("Warning: exec file is newer than core file.\n");
+ }
+}
+
+/* Return the name of the executable file as a string.
+ ERR nonzero means get error if there is none specified;
+ otherwise return 0 in that case. */
+
+char *
+get_exec_file (err)
+ int err;
+{
+ if (err && execfile == 0)
+ error ("No executable file specified.\n\
+Use the \"exec-file\" and \"symbol-file\" commands.");
+ return execfile;
+}
+
+int
+have_core_file_p ()
+{
+ return corefile != 0;
+}
+
+static void
+files_info ()
+{
+ char *symfile;
+ extern char *get_sym_file ();
+
+ if (execfile)
+ printf ("Executable file \"%s\".\n", execfile);
+ else
+ printf ("No executable file\n");
+
+ if (corefile)
+ printf ("Core dump file \"%s\".\n", corefile);
+ else
+ printf ("No core dump file\n");
+
+ if (have_inferior_p ())
+ printf ("Using the running image of the program, rather than these files.\n");
+
+ symfile = get_sym_file ();
+ if (symfile != 0)
+ printf ("Symbols from \"%s\".\n", symfile);
+
+ if (! have_inferior_p ())
+ {
+ if (execfile)
+ {
+ printf ("Text segment in executable from 0x%x to 0x%x.\n",
+ text_start, text_end);
+ printf ("Data segment in executable from 0x%x to 0x%x.\n",
+ exec_data_start, exec_data_end);
+ if (corefile)
+ printf("(But since we have a core file, we're using...)\n");
+ }
+ if (corefile)
+ {
+ printf ("Data segment in core file from 0x%x to 0x%x.\n",
+ data_start, data_end);
+ printf ("Stack segment in core file from 0x%x to 0x%x.\n",
+ stack_start, stack_end);
+ }
+ }
+}
+
+/* Read "memory data" from core file and/or executable file.
+ Returns zero if successful, 1 if xfer_core_file failed, errno value if
+ ptrace failed. */
+
+int
+read_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ if (have_inferior_p ())
+ return read_inferior_memory (memaddr, myaddr, len);
+ else
+ return xfer_core_file (memaddr, myaddr, len);
+}
+
+/* Write LEN bytes of data starting at address MYADDR
+ into debugged program memory at address MEMADDR.
+ Returns zero if successful, or an errno value if ptrace failed. */
+
+int
+write_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ if (have_inferior_p ())
+ return write_inferior_memory (memaddr, myaddr, len);
+ else
+ error ("Can write memory only when program being debugged is running.");
+}
+
+/* Read from the program's memory (except for inferior processes).
+ This function is misnamed, since it only reads, never writes; and
+ since it will use the core file and/or executable file as necessary.
+
+ It should be extended to write as well as read, FIXME, for patching files.
+
+ Return 0 if address could be read, 1 if not. */
+
+int
+xfer_core_file (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ register int val;
+ int xferchan;
+ char **xferfile;
+ int fileptr;
+ int returnval = 0;
+
+ while (len > 0)
+ {
+ xferfile = 0;
+ xferchan = 0;
+
+ /* Determine which file the next bunch of addresses reside in,
+ and where in the file. Set the file's read/write pointer
+ to point at the proper place for the desired address
+ and set xferfile and xferchan for the correct file.
+
+ If desired address is nonexistent, leave them zero.
+
+ i is set to the number of bytes that can be handled
+ along with the next address.
+
+ We put the most likely tests first for efficiency. */
+
+ /* Note that if there is no core file
+ data_start and data_end are equal. */
+ if (memaddr >= data_start && memaddr < data_end)
+ {
+ i = min (len, data_end - memaddr);
+ fileptr = memaddr - data_start + data_offset;
+ xferfile = &corefile;
+ xferchan = corechan;
+ }
+ /* Note that if there is no core file
+ stack_start and stack_end are equal. */
+ else if (memaddr >= stack_start && memaddr < stack_end)
+ {
+ i = min (len, stack_end - memaddr);
+ fileptr = memaddr - stack_start + stack_offset;
+ xferfile = &corefile;
+ xferchan = corechan;
+ }
+ else if (corechan < 0
+ && memaddr >= exec_data_start && memaddr < exec_data_end)
+ {
+ i = min (len, exec_data_end - memaddr);
+ fileptr = memaddr - exec_data_start + exec_data_offset;
+ xferfile = &execfile;
+ xferchan = execchan;
+ }
+ else if (memaddr >= text_start && memaddr < text_end)
+ {
+ i = min (len, text_end - memaddr);
+ fileptr = memaddr - text_start + text_offset;
+ xferfile = &execfile;
+ xferchan = execchan;
+ }
+ else if (memaddr < text_start)
+ {
+ i = min (len, text_start - memaddr);
+ }
+ else if (memaddr >= text_end
+ && memaddr < (corechan >= 0? data_start : exec_data_start))
+ {
+ i = min (len, data_start - memaddr);
+ }
+ else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end)
+ && memaddr < stack_start)
+ {
+ i = min (len, stack_start - memaddr);
+ }
+ else if (memaddr >= stack_end && stack_end != 0)
+ {
+ i = min (len, - memaddr);
+ }
+ else
+ {
+ /* Address did not classify into one of the known ranges.
+ This could be because data_start != exec_data_start
+ or data_end similarly. */
+ abort();
+ }
+
+ /* Now we know which file to use.
+ Set up its pointer and transfer the data. */
+ if (xferfile)
+ {
+ if (*xferfile == 0)
+ if (xferfile == &execfile)
+ error ("No program file to examine.");
+ else
+ error ("No core dump file or running program to examine.");
+ val = lseek (xferchan, fileptr, 0);
+ if (val < 0)
+ perror_with_name (*xferfile);
+ val = myread (xferchan, myaddr, i);
+ if (val < 0)
+ perror_with_name (*xferfile);
+ }
+ /* If this address is for nonexistent memory,
+ read zeros if reading, or do nothing if writing.
+ (FIXME we never write.) */
+ else
+ {
+ bzero (myaddr, i);
+ returnval = 1;
+ }
+
+ memaddr += i;
+ myaddr += i;
+ len -= i;
+ }
+ return returnval;
+}
+
+/* My replacement for the read system call.
+ Used like `read' but keeps going if `read' returns too soon. */
+
+int
+myread (desc, addr, len)
+ int desc;
+ char *addr;
+ int len;
+{
+ register int val;
+ int orglen = len;
+
+ while (len > 0)
+ {
+ val = read (desc, addr, len);
+ if (val < 0)
+ return val;
+ if (val == 0)
+ return orglen - len;
+ len -= val;
+ addr += val;
+ }
+ return orglen;
+}
+
+#ifdef REGISTER_U_ADDR
+
+/* Return the address in the core dump or inferior of register REGNO.
+ BLOCKEND is the address of the end of the user structure. */
+
+unsigned int
+register_addr (regno, blockend)
+ int regno;
+ int blockend;
+{
+ int addr;
+
+ if (regno < 0 || regno >= NUM_REGS)
+ error ("Invalid register number %d.", regno);
+
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+#endif /* REGISTER_U_ADDR */
+
+void
+_initialize_core()
+{
+ corechan = -1;
+ execchan = -1;
+ corefile = 0;
+ execfile = 0;
+ exec_file_display_hook = 0;
+
+ text_start = 0;
+ text_end = 0;
+ data_start = 0;
+ data_end = 0;
+ exec_data_start = 0;
+ exec_data_end = 0;
+ stack_start = STACK_END_ADDR;
+ stack_end = STACK_END_ADDR;
+
+ add_com ("core-file", class_files, core_file_command,
+ "Use FILE as core dump for examining memory and registers.\n\
+No arg means have no core file.");
+ add_com ("exec-file", class_files, exec_file_command,
+ "Use FILE as program for getting contents of pure memory.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+is searched for a command of that name.\n\
+No arg means have no executable file.");
+ add_info ("files", files_info, "Names of files being debugged.");
+}
+
+@
+
+
+1.3
+log
+@Fix up "info files" some more, to give more information.
+Rearrange the tests in xfer_core_file to avoid dependencies
+between data_start and exec_data_start, and for efficiency
+and add an abort() to test correctness. (If you take out
+never mind...)
+@
+text
+@d27 1
+a27 1
+#include <sys/fcntl.h>
+d50 10
+@
+
+
+1.2
+log
+@Create gdbcore.h for externally visible variables;
+spiff up the "info files" output to make it easier to read and more
+informative.
+@
+text
+@d250 4
+d257 4
+a260 7
+ printf ("Data segment in core file from 0x%x to 0x%x.\nStack segment in core file from 0x%x to 0x%x.\n",
+ data_start, data_end, stack_start, stack_end);
+ }
+ else if (execfile)
+ {
+ printf ("Data segment in executable from 0x%x to 0x%x.\n",
+ exec_data_start, exec_data_end);
+d297 3
+a299 1
+/* Return 0 if address could be read, 1 if not. */
+d301 4
+d327 1
+d329 1
+d331 3
+a333 1
+ along with the next address. */
+a334 17
+ if (memaddr < text_start)
+ {
+ i = min (len, text_start - memaddr);
+ }
+ else if (memaddr >= text_end && memaddr < data_start)
+ {
+ i = min (len, data_start - memaddr);
+ }
+ else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end)
+ && memaddr < stack_start)
+ {
+ i = min (len, stack_start - memaddr);
+ }
+ else if (memaddr >= stack_end && stack_end != 0)
+ {
+ i = min (len, - memaddr);
+ }
+d337 1
+a337 1
+ else if (memaddr >= data_start && memaddr < data_end)
+d368 25
+d411 2
+a412 1
+ read zeros if reading, or do nothing if writing. */
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d2 1
+a2 1
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+d23 1
+d35 1
+d43 1
+d231 4
+a234 1
+ if (corefile == 0)
+a235 2
+ else
+ printf ("Core dump file \"%s\".\n", corefile);
+d242 1
+a242 1
+ printf ("Symbols loaded from \"%s\".\n", symfile);
+d248 1
+a248 1
+ printf ("Text segment from 0x%x to 0x%x.\n",
+d253 1
+a253 1
+ printf ("Data segment from 0x%x to 0x%x.\nStack segment from 0x%x to 0x%x.\n",
+d256 1
+a256 1
+ else
+@
diff --git a/gdb/RCS/dbxread.c,v b/gdb/RCS/dbxread.c,v
new file mode 100644
index 0000000..eb9d1cd
--- /dev/null
+++ b/gdb/RCS/dbxread.c,v
@@ -0,0 +1,4610 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.3
+date 89.03.27.18.41.32; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.02.10.01.38.34; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.10.01.30.11; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@Avoid sys/fcntl.h.
+@
+text
+@/* Read dbx symbol tables and convert to internal format, for GDB.
+ Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "param.h"
+
+#ifdef READ_DBX_FORMAT
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#define L_SET 0
+#define L_INCR 1
+#endif
+
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#include "stab.gnu.h"
+#else
+#include <a.out.h>
+#include <stab.h>
+#endif
+
+/*
+ * Define specifically gnu symbols here.
+ */
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition. */
+#ifndef N_INDR
+#define N_INDR 0xa
+#endif
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ element's value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+#ifndef N_SETA
+#define N_SETA 0x14 /* Absolute set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETT
+#define N_SETT 0x16 /* Text set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETD
+#define N_SETD 0x18 /* Data set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETB
+#define N_SETB 0x1A /* Bss set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+/* Macros dealing with the set element symbols defined in a.out.h */
+#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT))
+#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS)
+
+#ifndef N_SETV
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+#endif /* This is output from LD. */
+
+#ifndef N_WARNING
+#define N_WARNING 0x1E /* Warning message to print if file included */
+#endif /* This is input to ld */
+
+#ifndef __GNU_STAB__
+
+/* Line number for the data section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_DSLINE
+#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
+#endif
+
+/* Line number for the bss section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_BSLINE
+#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
+#endif
+
+#endif /* not __GNU_STAB__ */
+
+#include <stdio.h>
+#include <obstack.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "defs.h"
+#include "symtab.h"
+
+#ifndef COFF_FORMAT
+#define AOUTHDR struct exec
+#endif
+
+static void add_symbol_to_list ();
+static void read_dbx_symtab ();
+static void process_one_symbol ();
+static void free_all_psymbols ();
+static struct type *read_type ();
+static struct type *read_range_type ();
+static struct type *read_enum_type ();
+static struct type *read_struct_type ();
+static struct type *read_array_type ();
+static long read_number ();
+static void finish_block ();
+static struct blockvector *make_blockvector ();
+static struct symbol *define_symbol ();
+static void start_subfile ();
+static int hashname ();
+static void hash_symsegs ();
+
+extern struct symtab *read_symsegs ();
+extern void free_all_symtabs ();
+extern void free_all_psymtabs ();
+extern void free_inclink_symtabs ();
+
+/* C++ */
+static struct type **read_args();
+
+/* Macro to determine which symbols to ignore when reading the first symbol
+ of a file. Some machines override this definition. */
+#ifdef N_NSYMS
+#ifndef IGNORE_SYMBOL
+/* This code is used on Ultrix systems. Ignore it */
+#define IGNORE_SYMBOL(type) (type == N_NSYMS)
+#endif
+#else
+#ifndef IGNORE_SYMBOL
+/* Don't ignore any symbols. */
+#define IGNORE_SYMBOL(type) (0)
+#endif
+#endif /* not N_NSYMS */
+
+/* Macro for number of symbol table entries (in usual a.out format).
+ Some machines override this definition. */
+#ifndef NUMBER_OF_SYMBOLS
+#ifdef COFF_HEADER
+#define NUMBER_OF_SYMBOLS \
+ ((COFF_HEADER(hdr) ? hdr.coffhdr.filehdr.f_nsyms : hdr.a_syms) / \
+ sizeof (struct nlist))
+#else
+#define NUMBER_OF_SYMBOLS (hdr.a_syms / sizeof (struct nlist))
+#endif
+#endif
+
+/* Macro for file-offset of symbol table (in usual a.out format). */
+#ifndef SYMBOL_TABLE_OFFSET
+#define SYMBOL_TABLE_OFFSET N_SYMOFF (hdr)
+#endif
+
+/* Macro for file-offset of string table (in usual a.out format). */
+#ifndef STRING_TABLE_OFFSET
+#define STRING_TABLE_OFFSET (N_SYMOFF (hdr) + hdr.a_syms)
+#endif
+
+/* Macro to store the length of the string table data in INTO. */
+#ifndef READ_STRING_TABLE_SIZE
+#define READ_STRING_TABLE_SIZE(INTO) \
+{ val = myread (desc, &INTO, sizeof INTO); \
+ if (val < 0) perror_with_name (name); }
+#endif
+
+/* Macro to declare variables to hold the file's header data. */
+#ifndef DECLARE_FILE_HEADERS
+#define DECLARE_FILE_HEADERS AOUTHDR hdr
+#endif
+
+/* Macro to read the header data from descriptor DESC and validate it.
+ NAME is the file name, for error messages. */
+#ifndef READ_FILE_HEADERS
+#ifdef HEADER_SEEK_FD
+#define READ_FILE_HEADERS(DESC, NAME) \
+{ HEADER_SEEK_FD (DESC); \
+ val = myread (DESC, &hdr, sizeof hdr); \
+ if (val < 0) perror_with_name (NAME); \
+ if (N_BADMAG (hdr)) \
+ error ("File \"%s\" not in executable format.", NAME); }
+#else
+#define READ_FILE_HEADERS(DESC, NAME) \
+{ val = myread (DESC, &hdr, sizeof hdr); \
+ if (val < 0) perror_with_name (NAME); \
+ if (N_BADMAG (hdr)) \
+ error ("File \"%s\" not in executable format.", NAME); }
+#endif
+#endif
+
+/* Macro for size of text segment */
+#ifndef SIZE_OF_TEXT_SEGMENT
+#define SIZE_OF_TEXT_SEGMENT hdr.a_text
+#endif
+
+/* Macro for name of symbol to indicate a file compiled with gcc. */
+#ifndef GCC_COMPILED_FLAG_SYMBOL
+#define GCC_COMPILED_FLAG_SYMBOL "gcc_compiled."
+#endif
+
+/* Chain of symtabs made from reading the file's symsegs.
+ These symtabs do not go into symtab_list themselves,
+ but the information is copied from them when appropriate
+ to make the symtabs that will exist permanently. */
+
+static struct symtab *symseg_chain;
+
+/* Symseg symbol table for the file whose data we are now processing.
+ It is one of those in symseg_chain. Or 0, for a compilation that
+ has no symseg. */
+
+static struct symtab *current_symseg;
+
+/* Name of source file whose symbol data we are now processing.
+ This comes from a symbol of type N_SO. */
+
+static char *last_source_file;
+
+/* Core address of start of text of current source file.
+ This too comes from the N_SO symbol. */
+
+static CORE_ADDR last_source_start_addr;
+
+/* End of the text segment of the executable file,
+ as found in the symbol _etext. */
+
+static CORE_ADDR end_of_text_addr;
+
+/* The list of sub-source-files within the current individual compilation.
+ Each file gets its own symtab with its own linetable and associated info,
+ but they all share one blockvector. */
+
+struct subfile
+{
+ struct subfile *next;
+ char *name;
+ struct linetable *line_vector;
+ int line_vector_length;
+ int line_vector_index;
+ int prev_line_number;
+};
+
+static struct subfile *subfiles;
+
+static struct subfile *current_subfile;
+
+/* Count symbols as they are processed, for error messages. */
+
+static int symnum;
+
+/* Vector of types defined so far, indexed by their dbx type numbers.
+ (In newer sun systems, dbx uses a pair of numbers in parens,
+ as in "(SUBFILENUM,NUMWITHINSUBFILE)". Then these numbers must be
+ translated through the type_translations hash table to get
+ the index into the type vector.) */
+
+static struct typevector *type_vector;
+
+/* Number of elements allocated for type_vector currently. */
+
+static int type_vector_length;
+
+/* Vector of line number information. */
+
+static struct linetable *line_vector;
+
+/* Index of next entry to go in line_vector_index. */
+
+static int line_vector_index;
+
+/* Last line number recorded in the line vector. */
+
+static int prev_line_number;
+
+/* Number of elements allocated for line_vector currently. */
+
+static int line_vector_length;
+
+/* Hash table of global symbols whose values are not known yet.
+ They are chained thru the SYMBOL_VALUE, since we don't
+ have the correct data for that slot yet. */
+
+#define HASHSIZE 127
+static struct symbol *global_sym_chain[HASHSIZE];
+
+/* Record the symbols defined for each context in a list.
+ We don't create a struct block for the context until we
+ know how long to make it. */
+
+#define PENDINGSIZE 100
+
+struct pending
+{
+ struct pending *next;
+ int nsyms;
+ struct symbol *symbol[PENDINGSIZE];
+};
+
+/* List of free `struct pending' structures for reuse. */
+struct pending *free_pendings;
+
+/* Here are the three lists that symbols are put on. */
+
+struct pending *file_symbols; /* static at top level, and types */
+
+struct pending *global_symbols; /* global functions and variables */
+
+struct pending *local_symbols; /* everything local to lexical context */
+
+/* Stack representing unclosed lexical contexts
+ (that will become blocks, eventually). */
+
+struct context_stack
+{
+ struct pending *locals;
+ struct pending_block *old_blocks;
+ struct symbol *name;
+ CORE_ADDR start_addr;
+ int depth;
+};
+
+struct context_stack *context_stack;
+
+/* Index of first unused entry in context stack. */
+int context_stack_depth;
+
+/* Currently allocated size of context stack. */
+
+int context_stack_size;
+
+/* Nonzero if within a function (so symbols should be local,
+ if nothing says specifically). */
+
+int within_function;
+
+/* List of blocks already made (lexical contexts already closed).
+ This is used at the end to make the blockvector. */
+
+struct pending_block
+{
+ struct pending_block *next;
+ struct block *block;
+};
+
+struct pending_block *pending_blocks;
+
+extern CORE_ADDR first_object_file_end; /* From blockframe.c */
+
+/* File name symbols were loaded from. */
+
+static char *symfile;
+
+/* Low and high symbol values (inclusive) for the global variable
+ entries in the symbol file. */
+
+static int first_global_sym, last_global_sym;
+
+/* Partial symbol list for all of the global and static symbols found
+ in a file */
+
+struct partial_symbol *global_psymbols, *static_psymbols;
+int global_psymbols_allocated, static_psymbols_allocated;
+
+/* Position for next psymbol to be added */
+
+struct partial_symbol *next_ps_global, *next_ps_static;
+
+/* Global variable which, when set, indicates that we are processing a
+ .o file compiled with gcc */
+
+static unsigned char processing_gcc_compilation;
+
+static int
+xxmalloc (n)
+{
+ int v = malloc (n);
+ if (v == 0)
+ abort ();
+ return v;
+}
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
+ (and add a null character at the end in the copy).
+ Returns the address of the copy. */
+
+static char *
+obsavestring (ptr, size)
+ char *ptr;
+ int size;
+{
+ register char *p = (char *) obstack_alloc (symbol_obstack, size + 1);
+ /* Open-coded bcopy--saves function call time.
+ These strings are usually short. */
+ {
+ register char *p1 = ptr;
+ register char *p2 = p;
+ char *end = ptr + size;
+ while (p1 != end)
+ *p2++ = *p1++;
+ }
+ p[size] = 0;
+ return p;
+}
+
+/* Concatenate strings S1, S2 and S3; return the new string.
+ Space is found in the symbol_obstack. */
+
+static char *
+obconcat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ register char *val = (char *) obstack_alloc (symbol_obstack, len);
+ strcpy (val, s1);
+ strcat (val, s2);
+ strcat (val, s3);
+ return val;
+}
+
+/* Support for Sun changes to dbx symbol format */
+
+/* For each identified header file, we have a table of types defined
+ in that header file.
+
+ header_files maps header file names to their type tables.
+ It is a vector of n_header_files elements.
+ Each element describes one header file.
+ It contains a vector of types.
+
+ Sometimes it can happen that the same header file produces
+ different results when included in different places.
+ This can result from conditionals or from different
+ things done before including the file.
+ When this happens, there are multiple entries for the file in this table,
+ one entry for each distinct set of results.
+ The entries are distinguished by the INSTANCE field.
+ The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is
+ used to match header-file references to their corresponding data. */
+
+struct header_file
+{
+ char *name; /* Name of header file */
+ int instance; /* Numeric code distinguishing instances
+ of one header file that produced
+ different results when included.
+ It comes from the N_BINCL or N_EXCL. */
+ struct type **vector; /* Pointer to vector of types */
+ int length; /* Allocated length (# elts) of that vector */
+};
+
+static struct header_file *header_files;
+
+static int n_header_files;
+
+static int n_allocated_header_files;
+
+/* During initial symbol readin, we need to have a structure to keep
+ track of which psymtabs have which bincls in them. This structure
+ is used during readin to setup the list of dependencies within each
+ partial symbol table. */
+
+struct header_file_location
+{
+ char *name; /* Name of header file */
+ int instance; /* See above */
+ struct partial_symtab *pst; /* Partial symtab that has the
+ BINCL/EINCL defs for this file */
+};
+
+/* The actual list and controling variables */
+static struct header_file_location *bincl_list, *next_bincl;
+static int bincls_allocated;
+
+/* Within each object file, various header files are assigned numbers.
+ A type is defined or referred to with a pair of numbers
+ (FILENUM,TYPENUM) where FILENUM is the number of the header file
+ and TYPENUM is the number within that header file.
+ TYPENUM is the index within the vector of types for that header file.
+
+ FILENUM == 1 is special; it refers to the main source of the object file,
+ and not to any header file. FILENUM != 1 is interpreted by looking it up
+ in the following table, which contains indices in header_files. */
+
+static int *this_object_header_files;
+
+static int n_this_object_header_files;
+
+static int n_allocated_this_object_header_files;
+
+/* When a header file is getting special overriding definitions
+ for one source file, record here the header_files index
+ of its normal definition vector.
+ At other times, this is -1. */
+
+static int header_file_prev_index;
+
+/* At the start of reading dbx symbols, allocate our tables. */
+
+static void
+init_header_files ()
+{
+ n_allocated_header_files = 10;
+ header_files = (struct header_file *) xxmalloc (10 * sizeof (struct header_file));
+ n_header_files = 0;
+
+ n_allocated_this_object_header_files = 10;
+ this_object_header_files = (int *) xxmalloc (10 * sizeof (int));
+}
+
+/* At the end of reading dbx symbols, free our tables. */
+
+static void
+free_header_files ()
+{
+ register int i;
+ for (i = 0; i < n_header_files; i++)
+ free (header_files[i].name);
+ if (header_files) free (header_files);
+ if (this_object_header_files)
+ free (this_object_header_files);
+}
+
+/* Called at the start of each object file's symbols.
+ Clear out the mapping of header file numbers to header files. */
+
+static void
+new_object_header_files ()
+{
+ /* Leave FILENUM of 0 free for builtin types and this file's types. */
+ n_this_object_header_files = 1;
+ header_file_prev_index = -1;
+}
+
+/* Add header file number I for this object file
+ at the next successive FILENUM. */
+
+static void
+add_this_object_header_file (i)
+ int i;
+{
+ if (n_this_object_header_files == n_allocated_this_object_header_files)
+ {
+ n_allocated_this_object_header_files *= 2;
+ this_object_header_files
+ = (int *) xrealloc (this_object_header_files,
+ n_allocated_this_object_header_files * sizeof (int));
+ }
+
+ this_object_header_files[n_this_object_header_files++] = i;
+}
+
+/* Add to this file an "old" header file, one already seen in
+ a previous object file. NAME is the header file's name.
+ INSTANCE is its instance code, to select among multiple
+ symbol tables for the same header file. */
+
+static void
+add_old_header_file (name, instance)
+ char *name;
+ int instance;
+{
+ register struct header_file *p = header_files;
+ register int i;
+
+ for (i = 0; i < n_header_files; i++)
+ if (!strcmp (p[i].name, name) && instance == p[i].instance)
+ {
+ add_this_object_header_file (i);
+ return;
+ }
+ error ("Invalid symbol data: \"repeated\" header file that hasn't been seen before, at symtab pos %d.",
+ symnum);
+}
+
+/* Add to this file a "new" header file: definitions for its types follow.
+ NAME is the header file's name.
+ Most often this happens only once for each distinct header file,
+ but not necessarily. If it happens more than once, INSTANCE has
+ a different value each time, and references to the header file
+ use INSTANCE values to select among them.
+
+ dbx output contains "begin" and "end" markers for each new header file,
+ but at this level we just need to know which files there have been;
+ so we record the file when its "begin" is seen and ignore the "end". */
+
+static void
+add_new_header_file (name, instance)
+ char *name;
+ int instance;
+{
+ register int i;
+ register struct header_file *p = header_files;
+ header_file_prev_index = -1;
+
+#if 0
+ /* This code was used before I knew about the instance codes.
+ My first hypothesis is that it is not necessary now
+ that instance codes are handled. */
+
+ /* Has this header file a previous definition?
+ If so, make a new entry anyway so that this use in this source file
+ gets a separate entry. Later source files get the old entry.
+ Record here the index of the old entry, so that any type indices
+ not previously defined can get defined in the old entry as
+ well as in the new one. */
+
+ for (i = 0; i < n_header_files; i++)
+ if (!strcmp (p[i].name, name))
+ {
+ header_file_prev_index = i;
+ }
+
+#endif
+
+ /* Make sure there is room for one more header file. */
+
+ if (n_header_files == n_allocated_header_files)
+ {
+ n_allocated_header_files *= 2;
+ header_files = (struct header_file *)
+ xrealloc (header_files,
+ (n_allocated_header_files
+ * sizeof (struct header_file)));
+ }
+
+ /* Create an entry for this header file. */
+
+ i = n_header_files++;
+ header_files[i].name = savestring (name, strlen(name));
+ header_files[i].instance = instance;
+ header_files[i].length = 10;
+ header_files[i].vector
+ = (struct type **) xxmalloc (10 * sizeof (struct type *));
+ bzero (header_files[i].vector, 10 * sizeof (struct type *));
+
+ add_this_object_header_file (i);
+}
+
+/* Look up a dbx type-number pair. Return the address of the slot
+ where the type for that number-pair is stored.
+ The number-pair is in TYPENUMS.
+
+ This can be used for finding the type associated with that pair
+ or for associating a new type with the pair. */
+
+static struct type **
+dbx_lookup_type (typenums)
+ int typenums[2];
+{
+ register int filenum = typenums[0], index = typenums[1];
+
+ if (filenum < 0 || filenum >= n_this_object_header_files)
+ error ("Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+ filenum, index, symnum);
+
+ if (filenum == 0)
+ {
+ /* Type is defined outside of header files.
+ Find it in this object file's type vector. */
+ if (index >= type_vector_length)
+ {
+ type_vector_length *= 2;
+ type_vector = (struct typevector *)
+ xrealloc (type_vector,
+ (sizeof (struct typevector)
+ + type_vector_length * sizeof (struct type *)));
+ bzero (&type_vector->type[type_vector_length / 2],
+ type_vector_length * sizeof (struct type *) / 2);
+ }
+ return &type_vector->type[index];
+ }
+ else
+ {
+ register int real_filenum = this_object_header_files[filenum];
+ register struct header_file *f;
+
+ if (real_filenum >= n_header_files)
+ abort ();
+
+ f = &header_files[real_filenum];
+
+ if (index >= f->length)
+ {
+ f->length *= 2;
+ f->vector = (struct type **)
+ xrealloc (f->vector, f->length * sizeof (struct type *));
+ bzero (&f->vector[f->length / 2],
+ f->length * sizeof (struct type *) / 2);
+ }
+ return &f->vector[index];
+ }
+}
+
+/* Make sure there is a type allocated for type numbers TYPENUMS
+ and return the type object.
+ This can create an empty (zeroed) type object. */
+
+static struct type *
+dbx_alloc_type (typenums)
+ int typenums[2];
+{
+ register struct type **type_addr = dbx_lookup_type (typenums);
+ register struct type *type = *type_addr;
+
+ /* If we are referring to a type not known at all yet,
+ allocate an empty type for it.
+ We will fill it in later if we find out how. */
+ if (type == 0)
+ {
+ type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ bzero (type, sizeof (struct type));
+ TYPE_VPTR_FIELDNO (type) = -1;
+ *type_addr = type;
+ }
+ return type;
+}
+
+#if 0
+static struct type **
+explicit_lookup_type (real_filenum, index)
+ int real_filenum, index;
+{
+ register struct header_file *f = &header_files[real_filenum];
+
+ if (index >= f->length)
+ {
+ f->length *= 2;
+ f->vector = (struct type **)
+ xrealloc (f->vector, f->length * sizeof (struct type *));
+ bzero (&f->vector[f->length / 2],
+ f->length * sizeof (struct type *) / 2);
+ }
+ return &f->vector[index];
+}
+#endif
+
+/* maintain the lists of symbols and blocks */
+
+/* Add a symbol to one of the lists of symbols. */
+static void
+add_symbol_to_list (symbol, listhead)
+ struct symbol *symbol;
+ struct pending **listhead;
+{
+ /* We keep PENDINGSIZE symbols in each link of the list.
+ If we don't have a link with room in it, add a new link. */
+ if (*listhead == 0 || (*listhead)->nsyms == PENDINGSIZE)
+ {
+ register struct pending *link;
+ if (free_pendings)
+ {
+ link = free_pendings;
+ free_pendings = link->next;
+ }
+ else
+ link = (struct pending *) xxmalloc (sizeof (struct pending));
+
+ link->next = *listhead;
+ *listhead = link;
+ link->nsyms = 0;
+ }
+
+ (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
+}
+
+/* At end of reading syms, or in case of quit,
+ really free as many `struct pending's as we can easily find. */
+
+static void
+really_free_pendings ()
+{
+ struct pending *next, *next1;
+ struct pending_block *bnext, *bnext1;
+
+ for (next = free_pendings; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+ free_pendings = 0;
+
+ for (bnext = pending_blocks; bnext; bnext = bnext1)
+ {
+ bnext1 = bnext->next;
+ free (bnext);
+ }
+ pending_blocks = 0;
+
+ for (next = file_symbols; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+ for (next = global_symbols; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+}
+
+/* Take one of the lists of symbols and make a block from it.
+ Keep the order the symbols have in the list (reversed from the input file).
+ Put the block on the list of pending blocks. */
+
+static void
+finish_block (symbol, listhead, old_blocks, start, end)
+ struct symbol *symbol;
+ struct pending **listhead;
+ struct pending_block *old_blocks;
+ CORE_ADDR start, end;
+{
+ register struct pending *next, *next1;
+ register struct block *block;
+ register struct pending_block *pblock;
+ struct pending_block *opblock;
+ register int i;
+
+ /* Count the length of the list of symbols. */
+
+ for (next = *listhead, i = 0; next; i += next->nsyms, next = next->next);
+
+ block = (struct block *) obstack_alloc (symbol_obstack,
+ (sizeof (struct block)
+ + ((i - 1)
+ * sizeof (struct symbol *))));
+
+ /* Copy the symbols into the block. */
+
+ BLOCK_NSYMS (block) = i;
+ for (next = *listhead; next; next = next->next)
+ {
+ register int j;
+ for (j = next->nsyms - 1; j >= 0; j--)
+ BLOCK_SYM (block, --i) = next->symbol[j];
+ }
+
+ BLOCK_START (block) = start;
+ BLOCK_END (block) = end;
+ BLOCK_SUPERBLOCK (block) = 0; /* Filled in when containing block is made */
+ BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
+
+ /* Put the block in as the value of the symbol that names it. */
+
+ if (symbol)
+ {
+ SYMBOL_BLOCK_VALUE (symbol) = block;
+ BLOCK_FUNCTION (block) = symbol;
+ }
+ else
+ BLOCK_FUNCTION (block) = 0;
+
+ /* Now "free" the links of the list, and empty the list. */
+
+ for (next = *listhead; next; next = next1)
+ {
+ next1 = next->next;
+ next->next = free_pendings;
+ free_pendings = next;
+ }
+ *listhead = 0;
+
+ /* Install this block as the superblock
+ of all blocks made since the start of this scope
+ that don't have superblocks yet. */
+
+ opblock = 0;
+ for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
+ {
+ if (BLOCK_SUPERBLOCK (pblock->block) == 0)
+ BLOCK_SUPERBLOCK (pblock->block) = block;
+ opblock = pblock;
+ }
+
+ /* Record this block on the list of all blocks in the file.
+ Put it after opblock, or at the beginning if opblock is 0.
+ This puts the block in the list after all its subblocks. */
+
+ /* Allocate in the symbol_obstack to save time.
+ It wastes a little space. */
+ pblock = (struct pending_block *)
+ obstack_alloc (symbol_obstack,
+ sizeof (struct pending_block));
+ pblock->block = block;
+ if (opblock)
+ {
+ pblock->next = opblock->next;
+ opblock->next = pblock;
+ }
+ else
+ {
+ pblock->next = pending_blocks;
+ pending_blocks = pblock;
+ }
+}
+
+static struct blockvector *
+make_blockvector ()
+{
+ register struct pending_block *next, *next1;
+ register struct blockvector *blockvector;
+ register int i;
+
+ /* Count the length of the list of blocks. */
+
+ for (next = pending_blocks, i = 0; next; next = next->next, i++);
+
+ blockvector = (struct blockvector *)
+ obstack_alloc (symbol_obstack,
+ (sizeof (struct blockvector)
+ + (i - 1) * sizeof (struct block *)));
+
+ /* Copy the blocks into the blockvector.
+ This is done in reverse order, which happens to put
+ the blocks into the proper order (ascending starting address).
+ finish_block has hair to insert each block into the list
+ after its subblocks in order to make sure this is true. */
+
+ BLOCKVECTOR_NBLOCKS (blockvector) = i;
+ for (next = pending_blocks; next; next = next->next)
+ BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
+
+#if 0 /* Now we make the links in the obstack, so don't free them. */
+ /* Now free the links of the list, and empty the list. */
+
+ for (next = pending_blocks; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+#endif
+ pending_blocks = 0;
+
+ return blockvector;
+}
+
+/* Manage the vector of line numbers. */
+
+static void
+record_line (line, pc)
+ int line;
+ CORE_ADDR pc;
+{
+ struct linetable_entry *e;
+ /* Ignore the dummy line number in libg.o */
+
+ if (line == 0xffff)
+ return;
+
+ /* Make sure line vector is big enough. */
+
+ if (line_vector_index + 1 >= line_vector_length)
+ {
+ line_vector_length *= 2;
+ line_vector = (struct linetable *)
+ xrealloc (line_vector,
+ (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry)));
+ current_subfile->line_vector = line_vector;
+ }
+
+ e = line_vector->item + line_vector_index++;
+ e->line = line; e->pc = pc;
+}
+
+/* Start a new symtab for a new source file.
+ This is called when a dbx symbol of type N_SO is seen;
+ it indicates the start of data for one original source file. */
+
+static void
+start_symtab (name, start_addr)
+ char *name;
+ CORE_ADDR start_addr;
+{
+ register struct symtab *s;
+
+ last_source_file = name;
+ last_source_start_addr = start_addr;
+ file_symbols = 0;
+ global_symbols = 0;
+ within_function = 0;
+
+ /* Context stack is initially empty, with room for 10 levels. */
+ context_stack
+ = (struct context_stack *) xxmalloc (10 * sizeof (struct context_stack));
+ context_stack_size = 10;
+ context_stack_depth = 0;
+
+ new_object_header_files ();
+
+ for (s = symseg_chain; s; s = s->next)
+ if (s->ldsymoff == symnum * sizeof (struct nlist))
+ break;
+ current_symseg = s;
+ if (s != 0)
+ return;
+
+ type_vector_length = 160;
+ type_vector = (struct typevector *)
+ xxmalloc (sizeof (struct typevector)
+ + type_vector_length * sizeof (struct type *));
+ bzero (type_vector->type, type_vector_length * sizeof (struct type *));
+
+ /* Initialize the list of sub source files with one entry
+ for this file (the top-level source file). */
+
+ subfiles = 0;
+ current_subfile = 0;
+ start_subfile (name);
+
+ /* Set default for compiler to pcc; assume that we aren't processing
+ a gcc compiled file until proved otherwise. */
+
+ processing_gcc_compilation = 0;
+}
+
+/* Handle an N_SOL symbol, which indicates the start of
+ code that came from an included (or otherwise merged-in)
+ source file with a different name. */
+
+static void
+start_subfile (name)
+ char *name;
+{
+ register struct subfile *subfile;
+
+ /* Save the current subfile's line vector data. */
+
+ if (current_subfile)
+ {
+ current_subfile->line_vector_index = line_vector_index;
+ current_subfile->line_vector_length = line_vector_length;
+ current_subfile->prev_line_number = prev_line_number;
+ }
+
+ /* See if this subfile is already known as a subfile of the
+ current main source file. */
+
+ for (subfile = subfiles; subfile; subfile = subfile->next)
+ {
+ if (!strcmp (subfile->name, name))
+ {
+ line_vector = subfile->line_vector;
+ line_vector_index = subfile->line_vector_index;
+ line_vector_length = subfile->line_vector_length;
+ prev_line_number = subfile->prev_line_number;
+ current_subfile = subfile;
+ return;
+ }
+ }
+
+ /* This subfile is not known. Add an entry for it. */
+
+ line_vector_index = 0;
+ line_vector_length = 1000;
+ prev_line_number = -2; /* Force first line number to be explicit */
+ line_vector = (struct linetable *)
+ xxmalloc (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry));
+
+ /* Make an entry for this subfile in the list of all subfiles
+ of the current main source file. */
+
+ subfile = (struct subfile *) xxmalloc (sizeof (struct subfile));
+ subfile->next = subfiles;
+ subfile->name = savestring (name, strlen (name));
+ subfile->line_vector = line_vector;
+ subfiles = subfile;
+ current_subfile = subfile;
+}
+
+/* Finish the symbol definitions for one main source file,
+ close off all the lexical contexts for that file
+ (creating struct block's for them), then make the struct symtab
+ for that file and put it in the list of all such.
+
+ END_ADDR is the address of the end of the file's text. */
+
+static void
+end_symtab (end_addr)
+ CORE_ADDR end_addr;
+{
+ register struct symtab *symtab;
+ register struct blockvector *blockvector;
+ register struct subfile *subfile;
+ register struct linetable *lv;
+ struct subfile *nextsub;
+
+ if (current_symseg != 0)
+ {
+ last_source_file = 0;
+ current_symseg = 0;
+ return;
+ }
+
+ /* Finish the lexical context of the last function in the file;
+ pop the context stack. */
+
+ if (context_stack_depth > 0)
+ {
+ register struct context_stack *cstk;
+ context_stack_depth--;
+ cstk = &context_stack[context_stack_depth];
+ /* Make a block for the local symbols within. */
+ finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+ cstk->start_addr, end_addr);
+ }
+
+ /* Finish defining all the blocks of this symtab. */
+ finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr);
+ finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr);
+ blockvector = make_blockvector ();
+
+ current_subfile->line_vector_index = line_vector_index;
+
+ /* Now create the symtab objects proper, one for each subfile. */
+ /* (The main file is one of them.) */
+
+ for (subfile = subfiles; subfile; subfile = nextsub)
+ {
+ symtab = (struct symtab *) xxmalloc (sizeof (struct symtab));
+ symtab->free_ptr = 0;
+
+ /* Fill in its components. */
+ symtab->blockvector = blockvector;
+ type_vector->length = type_vector_length;
+ symtab->typevector = type_vector;
+ symtab->free_code = free_linetable;
+ if (subfile->next == 0)
+ symtab->free_ptr = (char *) type_vector;
+
+ symtab->filename = subfile->name;
+ lv = subfile->line_vector;
+ lv->nitems = subfile->line_vector_index;
+ symtab->linetable = (struct linetable *)
+ xrealloc (lv, (sizeof (struct linetable)
+ + lv->nitems * sizeof (struct linetable_entry)));
+ symtab->nlines = 0;
+ symtab->line_charpos = 0;
+
+ /* Link the new symtab into the list of such. */
+ symtab->next = symtab_list;
+ symtab_list = symtab;
+
+ nextsub = subfile->next;
+ free (subfile);
+ }
+
+ type_vector = 0;
+ type_vector_length = -1;
+ line_vector = 0;
+ line_vector_length = -1;
+ last_source_file = 0;
+}
+
+#ifdef N_BINCL
+
+/* Handle the N_BINCL and N_EINCL symbol types
+ that act like N_SOL for switching source files
+ (different subfiles, as we call them) within one object file,
+ but using a stack rather than in an arbitrary order. */
+
+struct subfile_stack
+{
+ struct subfile_stack *next;
+ char *name;
+ int prev_index;
+};
+
+struct subfile_stack *subfile_stack;
+
+static void
+push_subfile ()
+{
+ register struct subfile_stack *tem
+ = (struct subfile_stack *) xxmalloc (sizeof (struct subfile_stack));
+
+ tem->next = subfile_stack;
+ subfile_stack = tem;
+ if (current_subfile == 0 || current_subfile->name == 0)
+ abort ();
+ tem->name = current_subfile->name;
+ tem->prev_index = header_file_prev_index;
+}
+
+static char *
+pop_subfile ()
+{
+ register char *name;
+ register struct subfile_stack *link = subfile_stack;
+
+ if (link == 0)
+ abort ();
+
+ name = link->name;
+ subfile_stack = link->next;
+ header_file_prev_index = link->prev_index;
+ free (link);
+
+ return name;
+}
+#endif /* Have N_BINCL */
+
+/* Accumulate the misc functions in bunches of 127.
+ At the end, copy them all into one newly allocated structure. */
+
+#define MISC_BUNCH_SIZE 127
+
+struct misc_bunch
+{
+ struct misc_bunch *next;
+ struct misc_function contents[MISC_BUNCH_SIZE];
+};
+
+/* Bunch currently being filled up.
+ The next field points to chain of filled bunches. */
+
+static struct misc_bunch *misc_bunch;
+
+/* Number of slots filled in current bunch. */
+
+static int misc_bunch_index;
+
+/* Total number of misc functions recorded so far. */
+
+static int misc_count;
+
+static void
+init_misc_functions ()
+{
+ misc_count = 0;
+ misc_bunch = 0;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+}
+
+static void
+record_misc_function (name, address)
+ char *name;
+ CORE_ADDR address;
+{
+ register struct misc_bunch *new;
+
+ if (misc_bunch_index == MISC_BUNCH_SIZE)
+ {
+ new = (struct misc_bunch *) xxmalloc (sizeof (struct misc_bunch));
+ misc_bunch_index = 0;
+ new->next = misc_bunch;
+ misc_bunch = new;
+ }
+ misc_bunch->contents[misc_bunch_index].name = name;
+ misc_bunch->contents[misc_bunch_index].address = address;
+ misc_bunch_index++;
+ misc_count++;
+}
+
+static int
+compare_misc_functions (fn1, fn2)
+ struct misc_function *fn1, *fn2;
+{
+ /* Return a signed result based on unsigned comparisons
+ so that we sort into unsigned numeric order. */
+ if (fn1->address < fn2->address)
+ return -1;
+ if (fn1->address > fn2->address)
+ return 1;
+ return 0;
+}
+
+static void
+discard_misc_bunches ()
+{
+ register struct misc_bunch *next;
+
+ while (misc_bunch)
+ {
+ next = misc_bunch->next;
+ free (misc_bunch);
+ misc_bunch = next;
+ }
+}
+
+/* INCLINK nonzero means bunches are from an incrementally-linked file.
+ Add them to the existing bunches.
+ Otherwise INCLINK is zero, and we start from scratch. */
+static void
+condense_misc_bunches (inclink)
+ int inclink;
+{
+ register int i, j;
+ register struct misc_bunch *bunch;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ if (inclink)
+ {
+ misc_function_vector
+ = (struct misc_function *)
+ xrealloc (misc_function_vector, (misc_count + misc_function_count)
+ * sizeof (struct misc_function));
+ j = misc_function_count;
+ }
+ else
+ {
+ misc_function_vector
+ = (struct misc_function *)
+ xxmalloc (misc_count * sizeof (struct misc_function));
+ j = 0;
+ }
+
+ bunch = misc_bunch;
+ while (bunch)
+ {
+ for (i = 0; i < misc_bunch_index; i++)
+ {
+ misc_function_vector[j] = bunch->contents[i];
+ misc_function_vector[j].name
+ = obconcat (misc_function_vector[j].name
+ + (misc_function_vector[j].name[0] == '_' ? offset : 0),
+ "", "");
+ j++;
+ }
+ bunch = bunch->next;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+ }
+
+ if (inclink)
+ misc_function_count += misc_count;
+ else
+ misc_function_count = j;
+
+ /* Sort the misc functions by address. */
+
+ qsort (misc_function_vector, misc_function_count,
+ sizeof (struct misc_function),
+ compare_misc_functions);
+}
+
+/* Call sort_syms to sort alphabetically
+ the symbols of each block of each symtab. */
+
+static int
+compare_symbols (s1, s2)
+ struct symbol **s1, **s2;
+{
+ register int namediff;
+
+ /* Compare the initial characters. */
+ namediff = SYMBOL_NAME (*s1)[0] - SYMBOL_NAME (*s2)[0];
+ if (namediff != 0) return namediff;
+
+ /* If they match, compare the rest of the names. */
+ namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
+ if (namediff != 0) return namediff;
+
+ /* For symbols of the same name, registers should come first. */
+ return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
+ - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
+}
+
+static void sort_symtab_syms ();
+
+static void
+sort_syms ()
+{
+ register struct symtab *s;
+
+ for (s = symtab_list; s; s = s->next)
+ sort_symtab_syms (s);
+}
+
+static void
+sort_symtab_syms (s)
+ register struct symtab *s;
+{
+ register struct blockvector *bv = BLOCKVECTOR (s);
+ int nbl = BLOCKVECTOR_NBLOCKS (bv);
+ int i;
+ register struct block *b;
+
+ /* Note that in the following sort, we always make sure that
+ register debug symbol declarations always come before regular
+ debug symbol declarations (as might happen when parameters are
+ then put into registers by the compiler). We do this by a
+ correct compare in compare_symbols, and by the reversal of the
+ symbols if we don't sort. This works as long as a register debug
+ symbol always comes after a parameter debug symbol. */
+
+ /* This is no longer necessary; lookup_block_symbol now always
+ prefers some other declaration over a parameter declaration. We
+ still sort the thing (that is necessary), but we don't reverse it
+ if we shouldn't sort it. */
+
+ for (i = 0; i < nbl; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ if (BLOCK_SHOULD_SORT (b))
+ qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ sizeof (struct symbol *), compare_symbols);
+ }
+}
+
+
+extern struct symtab *psymtab_to_symtab ();
+
+/* This is the symbol-file command. Read the file, analyze its symbols,
+ and add a struct symtab to symtab_list. */
+
+void
+symbol_file_command (name)
+ char *name;
+{
+ register int desc;
+ DECLARE_FILE_HEADERS;
+ struct nlist *nlist;
+ char *stringtab;
+ long buffer;
+ register int val;
+ extern void close ();
+ struct cleanup *old_chain;
+ struct symtab *symseg;
+ struct stat statbuf;
+
+ dont_repeat ();
+
+ if (name == 0)
+ {
+ if ((symtab_list || partial_symtab_list)
+ && !query ("Discard symbol table? ", 0))
+ error ("Not confirmed.");
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+ return;
+ }
+
+ if ((symtab_list || partial_symtab_list)
+ && !query ("Load new symbol table from \"%s\"? ", name))
+ error ("Not confirmed.");
+
+ {
+ char *absolute_name;
+ desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name);
+ if (desc < 0)
+ perror_with_name (name);
+ else
+ name = absolute_name;
+ }
+
+ old_chain = make_cleanup (close, desc);
+ make_cleanup (free_current_contents, &name);
+
+ READ_FILE_HEADERS (desc, name);
+
+ if (NUMBER_OF_SYMBOLS == 0)
+ {
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+ printf ("%s has no symbol-table; symbols discarded.\n", name);
+ fflush (stdout);
+ do_cleanups (old_chain);
+ return;
+ }
+
+ printf ("Reading symbol data from %s...", name);
+ fflush (stdout);
+
+ /* Now read the string table, all at once. */
+ val = lseek (desc, STRING_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+ stat (name, &statbuf);
+ READ_STRING_TABLE_SIZE (buffer);
+ if (buffer >= 0 && buffer < statbuf.st_size)
+ stringtab = (char *) alloca (buffer);
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", name, buffer);
+
+ bcopy (&buffer, stringtab, sizeof buffer);
+ val = myread (desc, stringtab + sizeof buffer, buffer - sizeof buffer);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Throw away the old symbol table. */
+
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+
+ /* Empty the hash table of global syms looking for values. */
+ bzero (global_sym_chain, sizeof global_sym_chain);
+
+#ifdef READ_GDB_SYMSEGS
+ /* That puts us at the symsegs. Read them. */
+ symseg_chain = read_symsegs (desc, name);
+ hash_symsegs ();
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ for (symseg = symseg_chain; symseg; symseg = symseg->next)
+ {
+ int i;
+ struct sourcevector *sv = (struct sourcevector *) symseg->linetable;
+
+ for (i = 0; i < sv->length; i++)
+ {
+ int j;
+ struct source *source = sv->source[i];
+ struct symtab *sp1
+ = (struct symtab *) xxmalloc (sizeof (struct symtab));
+
+ bcopy (symseg, sp1, sizeof (struct symtab));
+ sp1->filename = savestring (source->name, strlen (source->name));
+ sp1->linetable = &source->contents;
+ sp1->free_code = free_nothing;
+ sp1->free_ptr = (i == 0) ? (char *) symseg : 0;
+
+ sp1->next = symtab_list;
+ symtab_list = sp1;
+ }
+ }
+#else
+ /* Where people are using the 4.2 ld program, must not check for
+ symsegs, because that ld puts randonm garbage at the end of
+ the output file and that would trigger an error message. */
+ symseg_chain = 0;
+#endif
+
+ /* Position to read the symbol table. Do not read it all at once. */
+ val = lseek (desc, SYMBOL_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Don't put these on the cleanup chain; they need to stick around
+ until the next call to symbol_file_command. *Then* we'll free
+ them. */
+ free_header_files ();
+ init_header_files ();
+
+ init_misc_functions ();
+ make_cleanup (discard_misc_bunches, 0);
+
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ make_cleanup (really_free_pendings, 0);
+
+ /* Now that the symbol table data of the executable file are all in core,
+ process them and define symbols accordingly. Closes desc. */
+
+ read_dbx_symtab (desc, stringtab, NUMBER_OF_SYMBOLS, 0, 0, 0);
+
+ /* Go over the misc functions and install them in vector. */
+
+ condense_misc_bunches (0);
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+ /* Make a default for file to list. */
+
+ symfile = savestring (name, strlen (name));
+
+ /* Call to select_source_symtab used to be here; it was using too
+ much time. I'll make sure that list_sources can handle the lack
+ of current_source_symtab */
+
+ do_cleanups (old_chain); /* Descriptor closed here */
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ while (symseg_chain)
+ {
+ register struct symtab *s = symseg_chain->next;
+ free (symseg_chain);
+ symseg_chain = s;
+ }
+
+ if (!partial_symtab_list)
+ printf ("\n(no debugging symbols found)...");
+
+ printf ("done.\n");
+ fflush (stdout);
+}
+
+/* Return name of file symbols were loaded from, or 0 if none.. */
+
+char *
+get_sym_file ()
+{
+ return symfile;
+}
+
+/* Buffer for reading the symbol table entries. */
+static struct nlist symbuf[4096];
+static int symbuf_idx;
+static int symbuf_end;
+
+/* I/O descriptor for reading the symbol table. */
+static int symtab_input_desc;
+
+/* The address of the string table
+ of the object file we are reading (as copied into core). */
+static char *stringtab_global;
+
+/* Refill the symbol table input buffer
+ and set the variables that control fetching entries from it.
+ Reports an error if no data available.
+ This function can read past the end of the symbol table
+ (into the string table) but this does no harm. */
+
+static int
+fill_symbuf ()
+{
+ int nbytes = myread (symtab_input_desc, symbuf, sizeof (symbuf));
+ if (nbytes <= 0)
+ error ("error or end of file reading symbol table");
+ symbuf_end = nbytes / sizeof (struct nlist);
+ symbuf_idx = 0;
+ return 1;
+}
+
+/* dbx allows the text of a symbol name to be continued into the
+ next symbol name! When such a continuation is encountered
+ (a \ at the end of the text of a name)
+ call this function to get the continuation. */
+
+static char *
+next_symbol_text ()
+{
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+ symnum++;
+ return symbuf[symbuf_idx++].n_un.n_strx + stringtab_global;
+}
+
+/*
+ * Initializes storage for all of the partial symbols that will be
+ * created by read_dbx_symtab and subsidiaries.
+ */
+void
+init_psymbol_list (total_symbols)
+ int total_symbols;
+{
+ /* Current best guess is that there are approximately a twentieth
+ of the total symbols (in a debugging file) are global or static
+ oriented symbols */
+ global_psymbols_allocated = total_symbols / 10;
+ static_psymbols_allocated = total_symbols / 10;
+ next_ps_global = global_psymbols = (struct partial_symbol *)
+ xmalloc (global_psymbols_allocated * sizeof (struct partial_symbol));
+ next_ps_static = static_psymbols = (struct partial_symbol *)
+ xmalloc (static_psymbols_allocated * sizeof (struct partial_symbol));
+}
+
+/*
+ * Initialize the list of bincls to contain none and have some
+ * allocated.
+ */
+static void
+init_bincl_list (number)
+ int number;
+{
+ bincls_allocated = number;
+ next_bincl = bincl_list = (struct header_file_location *)
+ xmalloc (bincls_allocated * sizeof(struct header_file_location));
+}
+
+/*
+ * Add a bincl to the list.
+ */
+static void
+add_bincl_to_list (pst, name, instance)
+ struct partial_symtab *pst;
+ char *name;
+ int instance;
+{
+ if (next_bincl >= bincl_list + bincls_allocated)
+ {
+ int offset = next_bincl - bincl_list;
+ bincls_allocated *= 2;
+ bincl_list = (struct header_file_location *)
+ xrealloc (bincl_list,
+ bincls_allocated * sizeof (struct header_file_location));
+ next_bincl = bincl_list + offset;
+ }
+ next_bincl->pst = pst;
+ next_bincl->instance = instance;
+ next_bincl++->name = name;
+}
+
+/*
+ * Given a name, value pair, find the corresponding
+ * bincl in the list. Return the partial symtab associated
+ * with that header_file_location.
+ */
+struct partial_symtab *
+find_corresponding_bincl_psymtab (name, instance)
+ char *name;
+ int instance;
+{
+ struct header_file_location *bincl;
+
+ for (bincl = bincl_list; bincl < next_bincl; bincl++)
+ if (bincl->instance == instance
+ && !strcmp (name, bincl->name))
+ return bincl->pst;
+
+ return (struct partial_symtab *) 0;
+}
+
+/*
+ * Free the storage allocated for the bincl list.
+ */
+static void
+free_bincl_list ()
+{
+ free (bincl_list);
+ bincls_allocated = 0;
+}
+
+static struct partial_symtab *start_psymtab ();
+static void add_psymtab_dependency ();
+static void end_psymtab();
+
+/* Given pointers to an a.out symbol table in core containing dbx
+ style data, setup partial_symtab's describing each source file for
+ which debugging information is available. NLISTLEN is the number
+ of symbols in the symbol table. All symbol names are given as
+ offsets relative to STRINGTAB.
+
+ I have no idea whether or not this routine should be setup to deal
+ with inclinks. It seems reasonable to me that they be dealt with
+ standardly, so I am not going to make a strong effort to deal with
+ them here.
+ */
+
+static void process_symbol_for_psymtab ();
+
+static void
+read_dbx_symtab (desc, stringtab, nlistlen, inclink, text_addr, text_size)
+ int desc;
+ register char *stringtab;
+ register int nlistlen;
+ int inclink;
+ unsigned text_addr;
+ int text_size;
+{
+ register char *namestring;
+ register struct symbol *sym, *prev;
+ int hash;
+ int num_object_files = 0;
+ int past_first_source_file = 0;
+ struct cleanup *old_chain;
+ int current_text_start, current_file_symbol_start;
+ struct pending *global_symbols, *static_symbols;
+ int nsl; /* Length of namestring, when needed */
+
+ /* Current partial symtab */
+ struct partial_symtab *pst;
+
+ /* List of current psymtab's include files */
+ char **psymtab_include_list;
+ int includes_allocated;
+ int includes_used;
+
+ /* Index within current psymtab dependency list */
+ struct partial_symtab **dependency_list;
+ int dependencies_used, dependencies_allocated;
+
+ /* Setup a define to deal cleanly with the underscore problem */
+
+#ifdef NAMES_HAVE_UNDERSCORE
+#define HASH_OFFSET 1
+#else
+#define HASH_OFFSET 0
+#endif
+
+ global_symbols = static_symbols =
+ (struct pending *) 0;
+ pst = (struct partial_symtab *) 0;
+
+ includes_allocated = 30;
+ includes_used = 0;
+ psymtab_include_list = (char **) alloca (includes_allocated *
+ sizeof (char *));
+
+ dependencies_allocated = 30;
+ dependencies_used = 0;
+ dependency_list =
+ (struct partial_symtab **) alloca (dependencies_allocated *
+ sizeof (struct partial_symtab *));
+
+ old_chain = make_cleanup (free_all_psymtabs, 0);
+
+ /* Init bincl list */
+ init_bincl_list (20);
+ make_cleanup (free_bincl_list, 0);
+
+ /* Setup global partial symbol list */
+ init_psymbol_list (nlistlen);
+
+ last_source_file = 0;
+
+#ifdef END_OF_TEXT_DEFAULT
+ end_of_text_addr = END_OF_TEXT_DEFAULT;
+#endif
+
+ symtab_input_desc = desc; /* This is needed for fill_symbuf below */
+ symbuf_end = symbuf_idx = 0;
+
+ for (symnum = 0; symnum < nlistlen; symnum++)
+ {
+ struct nlist *bufp;
+ unsigned char type;
+
+ /* Get the symbol for this run and pull out some info */
+ QUIT; /* allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type;
+
+ /*
+ * Special cases to speed up readin.
+ */
+ if (type == N_SLINE) continue;
+
+ namestring = bufp->n_un.n_strx ? bufp->n_un.n_strx + stringtab : "";
+
+ switch (type)
+ {
+ /*
+ * Standard, non-debugger, symbols
+ */
+
+ case N_TEXT | N_EXT:
+ /* Catch etext */
+
+ if (!strcmp (namestring, "_etext"))
+ end_of_text_addr = bufp->n_value;
+ /* Fall through */
+
+#ifdef N_NBTEXT
+ case N_NBTEXT | N_EXT:
+#endif
+#ifdef N_NBDATA
+ case N_NBDATA | N_EXT:
+#endif
+#ifdef N_NBBSS
+ case N_NBBSS | N_EXT:
+#endif
+ case N_ABS | N_EXT:
+ case N_DATA | N_EXT:
+ case N_BSS | N_EXT:
+ /* Figure out beginning and end of global linker symbol
+ section and put non-debugger specified symbols on
+ tmp_symchain */
+
+ last_global_sym = symnum;
+ if (!first_global_sym) first_global_sym = symnum;
+
+ record_misc_function (namestring, bufp->n_value); /* Always */
+
+ continue;
+
+#ifdef N_NBTEXT
+ case N_NBTEXT:
+#endif
+ case N_TEXT:
+ if (!strcmp (namestring + strlen (namestring) - 2, ".o")
+ || !strncmp (namestring, "-l", 2))
+ {
+ if (num_object_files++ == 1)
+ first_object_file_end = bufp->n_value;
+ if (past_first_source_file && pst)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), bufp->n_value,
+ dependency_list, dependencies_used,
+ next_ps_global, next_ps_static);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+ }
+ continue;
+
+ case N_UNDF:
+ case N_UNDF | N_EXT:
+ case N_ABS:
+ case N_DATA:
+ case N_BSS:
+#ifdef N_NBDATA
+ case N_NBDATA:
+#endif
+#ifdef N_NBBSS
+ case N_NBBSS:
+#endif
+ case N_FN:
+ /* Keep going . . .*/
+
+ /*
+ * Special symbol types for GNU
+ */
+#ifdef N_INDR
+ case N_INDR:
+ case N_INDR | N_EXT:
+#endif
+#ifdef N_SETA
+ case N_SETA:
+ case N_SETA | N_EXT:
+ case N_SETT:
+ case N_SETT | N_EXT:
+ case N_SETD:
+ case N_SETD | N_EXT:
+ case N_SETB:
+ case N_SETB | N_EXT:
+ case N_SETV:
+ case N_SETV | N_EXT:
+#endif
+ continue;
+
+ /*
+ * Debugger symbols
+ */
+
+ case N_SO:
+ /* End the current partial symtab and start a new one */
+
+ if (past_first_source_file && pst)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), bufp->n_value,
+ dependency_list, dependencies_used,
+ next_ps_global, next_ps_static);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+
+ pst = start_psymtab (namestring, bufp->n_value,
+ symnum * sizeof (struct nlist),
+ next_ps_global, next_ps_static);
+
+ continue;
+
+#ifdef N_BINCL
+ case N_BINCL:
+ /* Add this bincl to the bincl_list for future EXCLs. No
+ need to save the string; it'll be around until
+ read_dbx_symtab function return */
+ add_bincl_to_list (pst, namestring, bufp->n_value);
+
+ /* Fall through */
+#endif
+
+ case N_SOL:
+ /* Mark down an include file in the current psymtab */
+
+ psymtab_include_list[includes_used++] = namestring;
+ if (includes_used >= includes_allocated)
+ {
+ char **orig = psymtab_include_list;
+
+ psymtab_include_list = (char **)
+ alloca ((includes_allocated *= 2) *
+ sizeof (char *));
+ bcopy (orig, psymtab_include_list,
+ includes_used * sizeof (char *));
+#ifdef DEBUG_INFO
+ fprintf (stderr, "Had to realloc includes. New size: %d\n",
+ includes_allocated);
+#endif
+ }
+ continue;
+
+ case N_FUN:
+ case N_SSYM:
+ case N_GSYM:
+ case N_LSYM:
+ case N_STSYM:
+ case N_LCSYM:
+ case N_ENTRY:
+#ifdef N_MAIN
+ case N_MAIN:
+#endif
+#ifdef N_BSLINE
+ case N_BSLINE:
+#endif
+ case N_PC:
+#ifdef N_M2C
+ case N_M2C:
+ case N_SCOPE:
+#endif
+ /* Process a symbol as appropriate for the type (this
+ information is contained in the name of the symbol) */
+
+ if (namestring[0] != '\0')
+#if 1
+ process_symbol_for_psymtab (namestring);
+#else
+ process_symbol_for_psymtab (namestring, tmp_symchain);
+#endif
+ continue;
+
+#ifdef N_BINCL
+ case N_EXCL:
+ /* Find the corresponding bincl and mark that psymtab on the
+ psymtab dependency list */
+ {
+ struct partial_symtab *needed_pst =
+ find_corresponding_bincl_psymtab (namestring, bufp->n_value);
+
+ /* If this include file was defined earlier in this file,
+ leave it alone. */
+ if (needed_pst == pst) continue;
+
+ if (needed_pst)
+ {
+ int i;
+ int found = 0;
+
+ for (i = 0; i < dependencies_used; i++)
+ if (dependency_list[i] == needed_pst)
+ {
+ found = 1;
+ break;
+ }
+
+ /* If it's already in the list, skip the rest. */
+ if (found) continue;
+
+ dependency_list[dependencies_used++] = needed_pst;
+ if (dependencies_used >= dependencies_allocated)
+ {
+ struct partial_symtab **orig = dependency_list;
+ dependency_list =
+ (struct partial_symtab **)
+ alloca ((dependencies_allocated *= 2)
+ * sizeof (struct partial_symtab *));
+ bcopy (orig, dependency_list,
+ (dependencies_used
+ * sizeof (struct partial_symtab *)));
+#ifdef DEBUG_INFO
+ fprintf (stderr, "Had to reallocate dependency list.\n");
+ fprintf (stderr, "New dependencies allocated: %d\n",
+ dependencies_allocated);
+#endif
+ }
+ }
+ else
+ error ("Invalid symbol data: \"repeated\" header file not previously seen, at symtab pos %d.",
+ symnum);
+ }
+ continue;
+
+ case N_EINCL:
+#endif
+#ifdef N_DSLINE
+ case N_DSLINE:
+#endif
+ case N_LENG:
+ case N_BCOMM:
+ case N_ECOMM:
+ case N_ECOML:
+ case N_FNAME:
+ case N_SLINE:
+ case N_RSYM:
+ case N_PSYM:
+ case N_LBRAC:
+ case N_RBRAC:
+ /* These symbols aren't interesting; don't worry about them */
+
+ continue;
+
+ default:
+ /* If we haven't found it yet, we've got problems */
+
+ if (IGNORE_SYMBOL (type))
+ continue;
+
+ fatal ("Bad symbol type 0x%x encountered in gdb scan", type);
+ }
+ }
+
+ if (last_source_file)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), end_of_text_addr,
+ dependency_list, dependencies_used,
+ next_ps_global, next_ps_static);
+ includes_used = 0;
+ dependencies_used = 0;
+ pst = (struct partial_symtab *) 0;
+ }
+
+ free_bincl_list ();
+ discard_cleanups (old_chain);
+}
+
+/*
+ * Take a single symbol (name: NAME) and process it (add it to the
+ * app psymbol list or not).
+ */
+static void
+process_symbol_for_psymtab (name)
+ char *name;
+{
+ char *p = (char *) index(name, ':') + 1;
+ int deftype;
+ struct partial_symbol *sym;
+ enum { T_IGNORE, T_STATIC, T_GLOBAL } symbol_type;
+ enum namespace ns = UNDEF_NAMESPACE;
+ enum address_class class;
+ int hash;
+
+ if (p == (char *) 0x1)
+ /* No ":" ; I guess it's not a debuggging symbol */
+ return;
+
+ if ((*p >= '0' && *p <= '9') || *p == '(')
+ deftype = 'l';
+ else
+ deftype = *p;
+
+ /* Figure out how to handle this symbol */
+ switch (deftype)
+ {
+ /* T is a struct/union/enum, t is a typedef */
+ case 'T':
+ symbol_type = T_STATIC;
+ ns = STRUCT_NAMESPACE;
+ class = LOC_TYPEDEF;
+ break;
+ case 't':
+ symbol_type = T_STATIC;
+ ns = VAR_NAMESPACE;
+ class = LOC_TYPEDEF;
+ break;
+ case 'c':
+ symbol_type = T_STATIC;
+ ns = VAR_NAMESPACE;
+ class = LOC_CONST;
+ break;
+ case 'S':
+ symbol_type = T_STATIC;
+ ns = VAR_NAMESPACE;
+ class = LOC_STATIC;
+ break;
+ case 'f':
+ symbol_type = T_STATIC;
+ ns = VAR_NAMESPACE;
+ class = LOC_BLOCK;
+ break;
+ case 'F':
+ symbol_type = T_GLOBAL;
+ ns = VAR_NAMESPACE;
+ class = LOC_BLOCK;
+ break;
+ case 'G':
+ symbol_type = T_GLOBAL;
+ ns = VAR_NAMESPACE;
+ class = LOC_STATIC;
+ break;
+ default:
+ return;
+ }
+
+ /* Create the symbol and store it on the list */
+ /* There's a better algorithm possible for the allocation; figure
+ out how far through the symbol table we are and do a reestimate */
+ if (symbol_type == T_STATIC)
+ {
+ if (next_ps_static >= static_psymbols + static_psymbols_allocated)
+ {
+ static_psymbols = (struct partial_symbol *)
+ xrealloc (static_psymbols,
+ (static_psymbols_allocated * 2
+ * sizeof (struct partial_symbol)));
+ /* Next assumes we only went one over. Should be good if
+ program works correctly */
+ next_ps_static = static_psymbols + static_psymbols_allocated;
+ static_psymbols_allocated *= 2;
+#ifdef DEBUGINFO
+ fprintf(stderr, "debuginfo: Had to realloc statics\n");
+#endif
+ }
+ sym = next_ps_static++;
+ }
+ else
+ {
+ if (next_ps_global >= global_psymbols + global_psymbols_allocated)
+ {
+ global_psymbols = (struct partial_symbol *)
+ xrealloc (global_psymbols,
+ (global_psymbols_allocated * 2
+ * sizeof (struct partial_symbol)));
+ next_ps_global = global_psymbols + global_psymbols_allocated;
+ global_psymbols_allocated *= 2;
+#ifdef DEBUGINFO
+ fprintf(stderr, "debuginfo: Had to realloc globals\n");
+#endif
+ }
+ sym = next_ps_global++;
+ }
+
+ SYMBOL_NAME(sym) = (char *) obstack_alloc (psymbol_obstack,
+ p - name);
+ strncpy(SYMBOL_NAME(sym), name, p - name - 1);
+ SYMBOL_NAME(sym)[p - name - 1] = '\0';
+ SYMBOL_NAMESPACE(sym) = ns;
+ SYMBOL_CLASS(sym) = class;
+}
+#undef HASH_OFFSET
+
+/*
+ * Allocate and partially fill a partial symtab. It will be
+ * completely filled at the end of the symbol list.
+ */
+static struct partial_symtab *
+start_psymtab (filename, textlow, ldsymoff, global_syms, static_syms)
+ char *filename;
+ int textlow;
+ int ldsymoff;
+ struct partial_symbol *global_syms;
+ struct partial_symbol *static_syms;
+{
+ struct partial_symtab *result =
+ (struct partial_symtab *) obstack_alloc (psymbol_obstack,
+ sizeof (struct partial_symtab));
+
+ result->filename =
+ (char *) obstack_alloc (psymbol_obstack,
+ strlen (filename) + 1);
+ strcpy (result->filename, filename);
+
+ result->textlow = textlow;
+ result->ldsymoff = ldsymoff;
+
+ result->readin = 0;
+
+ result->globals_offset = global_syms - global_psymbols;
+ result->statics_offset = static_syms - static_psymbols;
+
+ result->n_global_syms = 0;
+ result->n_static_syms = 0;
+
+ return result;
+}
+
+static int
+compare_psymbols (s1, s2)
+ register struct partial_symbol *s1, *s2;
+{
+ register char
+ *st1 = SYMBOL_NAME (s1),
+ *st2 = SYMBOL_NAME (s2);
+
+ return (st1[0] - st2[0] ? st1[0] - st2[0] :
+ strcmp (st1 + 1, st2 + 1));
+}
+
+
+/* Close off the current usage of a partial_symbol table entry. This
+ involves setting the correct number of includes (with a realloc),
+ setting the high text mark, setting the symbol length in the
+ executable, and setting the length of the global and static lists
+ of psymbols.
+
+ The global symbols and static symbols are then seperately sorted.
+
+ Then the partial symtab is put on the global list.
+ *** List variables and peculiarities of same. ***
+ */
+static void
+end_psymtab (pst, include_list, num_includes, capping_symbol_offset,
+ capping_text, dependency_list, number_dependencies,
+ capping_global, capping_static)
+ struct partial_symtab *pst;
+ char **include_list;
+ int num_includes;
+ int capping_symbol_offset;
+ int capping_text;
+ struct partial_symtab **dependency_list;
+ int number_dependencies;
+ struct partial_symbol *capping_global, *capping_static;
+{
+ int i;
+
+ pst->ldsymlen = capping_symbol_offset - pst->ldsymoff;
+ pst->texthigh = capping_text;
+
+ pst->n_global_syms =
+ capping_global - (global_psymbols + pst->globals_offset);
+ pst->n_static_syms =
+ capping_static - (static_psymbols + pst->statics_offset);
+
+ pst->dependencies = (struct partial_symtab **)
+ obstack_alloc (psymbol_obstack,
+ number_dependencies * sizeof (struct partial_symtab *));
+ bcopy (dependency_list, pst->dependencies,
+ number_dependencies * sizeof (struct partial_symtab *));
+ pst->number_of_dependencies = number_dependencies;
+
+ for (i = 0; i < num_includes; i++)
+ {
+ /* Eventually, put this on obstack */
+ struct partial_symtab *subpst =
+ (struct partial_symtab *)
+ obstack_alloc (psymbol_obstack,
+ sizeof (struct partial_symtab));
+
+ subpst->filename =
+ (char *) obstack_alloc (psymbol_obstack,
+ strlen (include_list[i]) + 1);
+ strcpy (subpst->filename, include_list[i]);
+
+ subpst->ldsymoff =
+ subpst->ldsymlen =
+ subpst->textlow =
+ subpst->texthigh = 0;
+ subpst->readin = 0;
+
+ subpst->dependencies = (struct partial_symtab **)
+ obstack_alloc (psymbol_obstack,
+ sizeof (struct partial_symtab *));
+ subpst->dependencies[0] = pst;
+ subpst->number_of_dependencies = 1;
+
+ subpst->globals_offset =
+ subpst->n_global_syms =
+ subpst->statics_offset =
+ subpst->n_static_syms = 0;
+
+ subpst->next = partial_symtab_list;
+ partial_symtab_list = subpst;
+ }
+
+ /* Sort the global list; don't sort the static list */
+ qsort (global_psymbols + pst->globals_offset, pst->n_global_syms,
+ sizeof (struct partial_symbol), compare_psymbols);
+
+ /* Put the psymtab on the psymtab list */
+ pst->next = partial_symtab_list;
+ partial_symtab_list = pst;
+}
+
+/*
+ * Read in all of the symbols for a given psymtab for real. Return
+ * the value of the symtab you create. Do not free the storage
+ * allocated to the psymtab; it may have pointers to it.
+ */
+static void scan_file_globals ();
+static void read_ofile_symtab ();
+
+struct symtab *
+psymtab_to_symtab(pst)
+ struct partial_symtab *pst;
+{
+ int desc;
+ DECLARE_FILE_HEADERS;
+ char *stringtab;
+ struct partial_symtab **list_patch;
+ int stsize, val;
+ struct stat statbuf;
+ struct cleanup *old_chain;
+ extern void close ();
+ int i;
+ struct symtab *result;
+ char *name = symfile; /* Some of the macros require the */
+ /* variable "name" to be defined in */
+ /* the context in which they execute */
+ /* (Yech!) */
+
+ if (!pst)
+ return 0;
+
+ if (pst->readin)
+ {
+ fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return 0;
+ }
+
+ if (!name)
+ error("No symbol file currently specified; use command symbol-file");
+
+ /* Read in all partial symbtabs on which this one is dependent */
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin)
+ psymtab_to_symtab (pst->dependencies[i]);
+
+ if (pst->ldsymlen) /* Otherwise it's a dummy */
+ {
+ /* Open symbol file and read in string table */
+ stat (name, &statbuf);
+ desc = open(name, O_RDONLY, 0); /* symbol_file_command
+ guarrantees that the symbol file name
+ will be absolute, so there is no
+ need for openp */
+
+ old_chain = make_cleanup (close, desc);
+
+ if (desc < 0)
+ error("Symbol file not readable");
+
+ READ_FILE_HEADERS (desc, name);
+
+ /* Read in the string table */
+ lseek (desc, STRING_TABLE_OFFSET, L_SET);
+ READ_STRING_TABLE_SIZE (stsize);
+ if (stsize >= 0 && stsize < statbuf.st_size)
+ stringtab = (char *) alloca (stsize);
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", name, stsize);
+
+ bcopy (&stsize, stringtab, sizeof stsize);
+ val = myread (desc, stringtab + sizeof stsize, stsize - sizeof stsize);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Init stuff necessary for reading in symbols */
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ make_cleanup (really_free_pendings, 0);
+
+ /* Read in this files symbols */
+ lseek (desc, SYMBOL_TABLE_OFFSET, L_SET);
+ read_ofile_symtab (desc, stringtab, pst->ldsymoff,
+ pst->ldsymlen, pst->textlow,
+ pst->texthigh - pst->textlow, 0);
+ sort_symtab_syms (symtab_list); /* At beginning since just added */
+
+ /* Match with global symbols */
+ lseek (desc, SYMBOL_TABLE_OFFSET, L_SET);
+ scan_file_globals (desc, stringtab,
+ first_global_sym * sizeof(struct nlist),
+ last_global_sym - first_global_sym + 1);
+
+ do_cleanups (old_chain);
+ }
+
+ /* Find pst in list, prune it, and free it's storage */
+ for (list_patch = &partial_symtab_list;
+ *list_patch && *list_patch != pst;
+ list_patch = &((*list_patch)->next))
+ ;
+
+ if (!(*list_patch)) /* pst not in list. Don't worry about it? */
+ fatal ("internal: psymtab_to_symtab called with non-listed pst");
+
+ *list_patch = (*list_patch)->next; /* Prune */
+
+ pst->readin = 1; /* Mark as read in */
+
+ /* It's the last one if we actually read something in */
+ if (pst->ldsymlen)
+ return symtab_list;
+ else
+ /* Search through list for correct name. */
+ for (result = symtab_list; result; result = result->next)
+ if (!strcmp (result->filename, pst->filename))
+ return result;
+
+ return 0;
+}
+
+/*
+ * Scan through all of the global symbols defined in the object file,
+ * assigning values to the debugging symbols that need to be assigned
+ * to.
+ *
+ * DESC is the file descriptor of the symbol file, with the seek
+ * pointer pointing at the beginning of the symbol table.
+ * STRINGTAB is the file's string table, already read in.
+ * OFFSET is the offset (in bytes) of the beginning of the global
+ * symbols from the beginning of the symbol table.
+ * NUMSYMS is the number of symbols that have to be checked.
+ */
+static void
+scan_file_globals (desc, stringtab, offset, numsyms)
+ int desc;
+ char *stringtab;
+ int offset;
+ int numsyms;
+{
+ int hash;
+
+ lseek(desc, offset, L_INCR);
+ symtab_input_desc = desc;
+ symbuf_end = symbuf_idx = 0;
+
+ for (symnum = 0; symnum < numsyms; symnum++)
+ {
+ struct nlist *bufp;
+ unsigned char type;
+ char *namestring;
+
+ QUIT;
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type;
+
+ if (type & N_EXT && type != N_EXT)
+ {
+ struct symbol *sym, *prev;
+
+ namestring = bufp->n_un.n_strx ?
+ bufp->n_un.n_strx + stringtab : "";
+ prev = (struct symbol *) 0;
+
+ /* Get the hash index and check all the symbols
+ under that hash index. */
+
+#ifdef NAMES_HAVE_UNDERSCORE
+ hash = hashname (namestring + 1);
+#else /* ! NAMES_HAVE_UNDERSCORE */
+ hash = hashname (namestring);
+#endif /* ! NAMES_HAVE_UNDERSCORE */
+ for (sym = global_sym_chain[hash]; sym;)
+ {
+ if (
+#ifdef NAMES_HAVE_UNDERSCORE
+ *namestring == '_'
+ && namestring[1] == SYMBOL_NAME (sym)[0]
+ && !strcmp(namestring + 2, SYMBOL_NAME (sym) + 1)
+#else /* ! NAMES_HAVE_UNDERSCORE */
+ namestring[0] == SYMBOL_NAME (sym) [0]
+ && !strcmp(namestring + 1, SYMBOL_NAME(sym) + 1)
+#endif /* ! NAMES_HAVE_UNDERSCORE */
+ )
+ {
+ /* Splice this symbol out of the hash chain and
+ assign the value we have to it. */
+ if (prev)
+ SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym);
+ else
+ global_sym_chain[hash]
+ = (struct symbol *) SYMBOL_VALUE (sym);
+ SYMBOL_VALUE (sym) = bufp->n_value;
+ if (prev)
+ sym = (struct symbol *) SYMBOL_VALUE (prev);
+ else
+ sym = global_sym_chain[hash];
+ break; /* Only one reference per file */
+ }
+ else
+ {
+ prev = sym;
+ sym = (struct symbol *) SYMBOL_VALUE (sym);
+ }
+ }
+ }
+ }
+ /* There shouldn't be anything left on the hash list at this point.
+ If there is, we have done something wrong. For right now it's
+ worth checking, until I get the bugs out. */
+ /* Sigh. Unfortunately, the above is not true. If an extern
+ variable is mentioned in an include file (or a program) and the
+ variable is never either referenced or defined, there will be a
+ debugger symbol with no "real" symbol. Oh well. */
+}
+
+/*
+ * Read in a defined section of a specific object file's symbols.
+ *
+ * DESC is the file descriptor for the file, positioned at the
+ * beginning of the symtab
+ * STRINGTAB is a pointer to the files string
+ * table, already read in
+ * SYM_OFFSET is the offset within the file of
+ * the beginning of the symbols we want to read, NUM_SUMBOLS is the
+ * number of symbols to read
+ * TEXT_OFFSET is the offset to be added to
+ * all values of symbols coming in and
+ * TEXT_SIZE is the size of the text segment read in.
+ * OFFSET is a flag which indicates that the value of all of the
+ * symbols should be offset by TEXT_OFFSET (for the purposes of
+ * incremental linking).
+ */
+
+static void
+read_ofile_symtab (desc, stringtab, sym_offset,
+ sym_size, text_offset, text_size, offset)
+ int desc;
+ register char *stringtab;
+ int sym_offset;
+ int sym_size;
+ int text_offset;
+ int text_size;
+ int offset;
+{
+ register char *namestring;
+ register struct symbol *sym, *prev;
+ int hash;
+ struct cleanup *old_chain;
+ struct nlist *bufp;
+ unsigned char type;
+#ifdef N_BINCL
+ subfile_stack = 0;
+#endif
+
+ stringtab_global = stringtab;
+ last_source_file = 0;
+
+ symtab_input_desc = desc;
+ symbuf_end = symbuf_idx = 0;
+ lseek(desc, sym_offset, L_INCR);
+
+ fill_symbuf();
+ bufp = &symbuf[symbuf_idx];
+ if ((unsigned char) bufp->n_type != N_SO)
+ fatal("First symbol in segment of executable not a source symbol");
+
+ for (symnum = 0;
+ symnum < sym_size / sizeof(struct nlist);
+ symnum++)
+ {
+ QUIT; /* Allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf();
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type;
+
+ if (offset &&
+ (type == N_TEXT || type == N_DATA || type == N_BSS))
+ bufp->n_value += text_offset;
+
+ namestring = bufp->n_un.n_strx ? bufp->n_un.n_strx + stringtab : "";
+
+ if (type & N_STAB)
+ process_one_symbol(type, bufp->n_desc,
+ bufp->n_value, namestring);
+ /* We skip checking for a new .o or -l file; that should never
+ happen in this routine. */
+ else if (type == N_TEXT
+ && !strcmp (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (type & N_EXT || type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ /* Global symbol: see if we came across a dbx defintion for
+ a corresponding symbol. If so, store the value. Remove
+ syms from the chain when their values are stored, but
+ search the whole chain, as there may be several syms from
+ different files with the same name. */
+ /* This is probably not true. Since the files will be read
+ in one at a time, each reference to a global symbol will
+ be satisfied in each file as it appears. So we skip this
+ section. */
+ &stringtab_global; /* For debugger; am I right? */
+ }
+ end_symtab (text_offset + text_size);
+}
+
+static int
+hashname (name)
+ char *name;
+{
+ register char *p = name;
+ register int total = p[0];
+ register int c;
+
+ c = p[1];
+ total += c << 2;
+ if (c)
+ {
+ c = p[2];
+ total += c << 4;
+ if (c)
+ total += p[3] << 6;
+ }
+
+ /* Ensure result is positive. */
+ if (total < 0) total += (1000 << 6);
+ return total % HASHSIZE;
+}
+
+/* Put all appropriate global symbols in the symseg data
+ onto the hash chains so that their addresses will be stored
+ when seen later in loader global symbols. */
+
+static void
+hash_symsegs ()
+{
+ /* Look at each symbol in each block in each symseg symtab. */
+ struct symtab *s;
+ for (s = symseg_chain; s; s = s->next)
+ {
+ register int n;
+ for (n = BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)) - 1; n >= 0; n--)
+ {
+ register struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), n);
+ register int i;
+ for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--)
+ {
+ register struct symbol *sym = BLOCK_SYM (b, i);
+
+ /* Put the symbol on a chain if its value is an address
+ that is figured out by the loader. */
+
+ if (SYMBOL_CLASS (sym) == LOC_EXTERNAL)
+ {
+ register int hash = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE (sym) = (int) global_sym_chain[hash];
+ global_sym_chain[hash] = sym;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ }
+ }
+ }
+ }
+}
+
+static void
+process_one_symbol (type, desc, value, name)
+ int type, desc;
+ CORE_ADDR value;
+ char *name;
+{
+ register struct context_stack *new;
+
+ /* Something is wrong if we see real data before
+ seeing a source file name. */
+
+ if (last_source_file == 0 && type != N_SO)
+ {
+ /* Currently this ignores N_ENTRY on Gould machines, N_NSYM on machines
+ where that code is defined, and all symbols on the Convex. */
+ if (IGNORE_SYMBOL (type))
+ return;
+
+ error ("Invalid symbol data: does not start by identifying a source file.");
+ }
+
+ switch (type)
+ {
+ case N_FUN:
+ case N_FNAME:
+ /* Either of these types of symbols indicates the start of
+ a new function. We must process its "name" normally for dbx,
+ but also record the start of a new lexical context, and possibly
+ also the end of the lexical context for the previous function. */
+
+ within_function = 1;
+ if (context_stack_depth > 0)
+ {
+ new = &context_stack[--context_stack_depth];
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, value);
+ }
+ /* Stack must be empty now. */
+ if (context_stack_depth != 0)
+ error ("Invalid symbol data: unmatched N_LBRAC before symtab pos %d.",
+ symnum);
+
+ new = &context_stack[context_stack_depth++];
+ new->old_blocks = pending_blocks;
+ new->start_addr = value;
+ new->name = define_symbol (value, name, desc);
+ local_symbols = 0;
+ break;
+
+ case N_LBRAC:
+ /* This "symbol" just indicates the start of an inner lexical
+ context within a function. */
+
+ if (context_stack_depth == context_stack_size)
+ {
+ context_stack_size *= 2;
+ context_stack = (struct context_stack *)
+ xrealloc (context_stack,
+ (context_stack_size
+ * sizeof (struct context_stack)));
+ }
+
+ new = &context_stack[context_stack_depth++];
+ new->depth = desc;
+ new->locals = local_symbols;
+ new->old_blocks = pending_blocks;
+ new->start_addr = value;
+ new->name = 0;
+ local_symbols = 0;
+ break;
+
+ case N_RBRAC:
+ /* This "symbol" just indicates the end of an inner lexical
+ context that was started with N_RBRAC. */
+ new = &context_stack[--context_stack_depth];
+ if (desc != new->depth)
+ error ("Invalid symbol data: N_LBRAC/N_RBRAC symbol mismatch, symtab pos %d.", symnum);
+ local_symbols = new->locals;
+
+ /* If this is not the outermost LBRAC...RBRAC pair in the
+ function, its local symbols preceded it, and are the ones
+ just recovered from the context stack. Defined the block for them.
+
+ If this is the outermost LBRAC...RBRAC pair, there is no
+ need to do anything; leave the symbols that preceded it
+ to be attached to the function's own block. */
+ if (local_symbols && context_stack_depth > 1)
+ {
+ /* Muzzle a compiler bug that makes end > start. */
+ if (new->start_addr > value)
+ new->start_addr = value;
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr + last_source_start_addr,
+ value + last_source_start_addr);
+ }
+ break;
+
+ case N_FN:
+ /* This kind of symbol supposedly indicates the start
+ of an object file. In fact this type does not appear. */
+ break;
+
+ case N_SO:
+ /* This type of symbol indicates the start of data
+ for one source file.
+ Finish the symbol table of the previous source file
+ (if any) and start accumulating a new symbol table. */
+ if (last_source_file)
+ end_symtab (value);
+ start_symtab (name, value);
+ break;
+
+ case N_SOL:
+ /* This type of symbol indicates the start of data for
+ a sub-source-file, one whose contents were copied or
+ included in the compilation of the main source file
+ (whose name was given in the N_SO symbol.) */
+ start_subfile (name);
+ break;
+
+#ifdef N_BINCL
+ case N_BINCL:
+ push_subfile ();
+ add_new_header_file (name, value);
+ start_subfile (name);
+ break;
+
+ case N_EINCL:
+ start_subfile (pop_subfile ());
+ break;
+
+ case N_EXCL:
+ add_old_header_file (name, value);
+ break;
+#endif /* have N_BINCL */
+
+ case N_SLINE:
+ /* This type of "symbol" really just records
+ one line-number -- core-address correspondence.
+ Enter it in the line list for this symbol table. */
+ record_line (desc, value);
+ break;
+
+ case N_BCOMM:
+ case N_ECOMM:
+ case N_ECOML:
+ case N_LENG:
+ break;
+
+ default:
+ if (name)
+ define_symbol (value, name, desc);
+ }
+}
+
+/* This function was added for C++ functionality. I presume that it
+ condenses the bunches formed by reading in an additional .o file
+ (incremental linking). */
+
+static void
+condense_addl_misc_bunches ()
+{
+ register int i, j;
+ register struct misc_bunch *bunch;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ misc_function_vector
+ = (struct misc_function *) xrealloc (misc_function_vector,
+ (misc_count + misc_function_count) * sizeof (struct misc_function));
+
+ j = misc_function_count;
+ bunch = misc_bunch;
+ while (bunch)
+ {
+ for (i = 0; i < misc_bunch_index; i++)
+ {
+ misc_function_vector[j] = bunch->contents[i];
+ misc_function_vector[j].name
+ = concat (misc_function_vector[j].name
+ + (misc_function_vector[j].name[0] == '_' ? offset : 0),
+ "", "");
+ j++;
+ }
+ bunch = bunch->next;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+ }
+
+ misc_function_count += misc_count;
+
+ /* Sort the misc functions by address. */
+
+ qsort (misc_function_vector, misc_function_count,
+ sizeof (struct misc_function), compare_misc_functions);
+}
+
+
+/* Read in another .o file and create a symtab entry for it.*/
+
+static void
+read_addl_syms (desc, stringtab, nlistlen, text_addr, text_size)
+ int desc;
+ register char *stringtab;
+ register int nlistlen;
+ unsigned text_addr;
+ int text_size;
+{
+ FILE *stream = fdopen (desc, "r");
+ register char *namestring;
+ register struct symbol *sym, *prev;
+ int hash;
+ int num_object_files = 0;
+
+#ifdef N_BINCL
+ subfile_stack = 0;
+#endif
+
+ last_source_file = 0;
+ bzero (global_sym_chain, sizeof global_sym_chain);
+ symtab_input_desc = desc;
+ stringtab_global = stringtab;
+ fill_symbuf ();
+
+ for (symnum = 0; symnum < nlistlen; symnum++)
+ {
+ struct nlist *bufp;
+ unsigned char type;
+
+ QUIT; /* allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type & N_TYPE;
+ namestring = bufp->n_un.n_strx ? bufp->n_un.n_strx + stringtab : "";
+
+ if( (type == N_TEXT) || (type == N_DATA) || (type == N_BSS) )
+ {
+ /* Relocate this file's symbol table information
+ to the address it has been loaded into. */
+ bufp->n_value += text_addr;
+ }
+
+ type = bufp->n_type;
+
+ if (type & N_STAB)
+ process_one_symbol (type, bufp->n_desc,
+ bufp->n_value, namestring);
+ /* A static text symbol whose name ends in ".o"
+ can only mean the start of another object file.
+ So end the symtab of the source file we have been processing.
+ This is how we avoid counting the libraries as part
+ or the last source file.
+ Also this way we find end of first object file (crt0). */
+ else if ((type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ && (!strcmp (namestring + strlen (namestring) - 2, ".o"))
+ || ! strcmp (namestring, "-l", 2))
+ {
+ if (num_object_files++ == 1)
+ first_object_file_end = bufp->n_value;
+ if (last_source_file)
+ end_symtab (bufp->n_value);
+ }
+ else if (type & N_EXT || type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ {
+ int used_up = 0;
+
+ /* Record the location of _etext. */
+ if (type == (N_TEXT | N_EXT)
+ && !strcmp (namestring, "_etext"))
+ end_of_text_addr = bufp->n_value;
+
+ /* Global symbol: see if we came across a dbx definition
+ for a corresponding symbol. If so, store the value.
+ Remove syms from the chain when their values are stored,
+ but search the whole chain, as there may be several syms
+ from different files with the same name. */
+ if (type & N_EXT)
+ {
+ prev = 0;
+#ifdef NAMES_HAVE_UNDERSCORE
+ hash = hashname (namestring + 1);
+#else /* not NAMES_HAVE_UNDERSCORE */
+ hash = hashname (namestring);
+#endif /* not NAMES_HAVE_UNDERSCORE */
+ for (sym = global_sym_chain[hash];
+ sym;)
+ {
+ if (
+#ifdef NAMES_HAVE_UNDERSCORE
+ *namestring == '_'
+ && namestring[1] == SYMBOL_NAME (sym)[0]
+ &&
+ !strcmp (namestring + 2, SYMBOL_NAME (sym) + 1)
+#else /* NAMES_HAVE_UNDERSCORE */
+ namestring[0] == SYMBOL_NAME (sym)[0]
+ &&
+ !strcmp (namestring + 1, SYMBOL_NAME (sym) + 1)
+#endif /* NAMES_HAVE_UNDERSCORE */
+ )
+ {
+ if (prev)
+ SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym);
+ else
+ global_sym_chain[hash]
+ = (struct symbol *) SYMBOL_VALUE (sym);
+ SYMBOL_VALUE (sym) = bufp->n_value;
+ if (prev)
+ sym = (struct symbol *) SYMBOL_VALUE (prev);
+ else
+ sym = global_sym_chain[hash];
+
+ used_up = 1;
+ }
+ else
+ {
+ prev = sym;
+ sym = (struct symbol *) SYMBOL_VALUE (sym);
+ }
+ }
+ }
+
+ /* Defined global or text symbol: record as a misc function
+ if it didn't give its address to a debugger symbol above. */
+ if (type <= (N_TYPE | N_EXT)
+ && type != N_EXT
+ && ! used_up)
+ record_misc_function (namestring, bufp->n_value);
+ }
+ }
+
+ if (last_source_file)
+ end_symtab (text_addr + text_size);
+
+ fclose (stream);
+}
+
+/* C++:
+ This function allows the addition of incrementally linked object files.
+ Since this has a fair amount of code in common with symbol_file_command,
+ it might be worthwhile to consolidate things, as was done with
+ read_dbx_symtab and condense_misc_bunches. */
+
+void
+add_file_command (arg_string)
+ char* arg_string;
+{
+ register int desc;
+ DECLARE_FILE_HEADERS;
+ struct nlist *nlist;
+ char *stringtab;
+ long buffer;
+ register int val;
+ extern void close ();
+ struct cleanup *old_chain;
+ struct symtab *symseg;
+ struct stat statbuf;
+ char *name;
+ unsigned text_addr;
+
+ if (arg_string == 0)
+ error ("add-file takes a file name and an address");
+
+ for( ; *arg_string == ' '; arg_string++ );
+ name = arg_string;
+ for( ; *arg_string && *arg_string != ' ' ; arg_string++ );
+ *arg_string++ = (char) 0;
+
+ if (name[0] == 0)
+ error ("add-file takes a file name and an address");
+
+ text_addr = parse_and_eval_address (arg_string);
+
+ dont_repeat ();
+
+ if (!query ("add symbol table from filename \"%s\" at text_addr = 0x%x\n",
+ name, text_addr))
+ error ("Not confirmed.");
+
+ desc = open (name, O_RDONLY);
+ if (desc < 0)
+ perror_with_name (name);
+
+ old_chain = make_cleanup (close, desc);
+ make_cleanup (free_current_contents, &name);
+
+ READ_FILE_HEADERS (desc, name);
+
+ if (NUMBER_OF_SYMBOLS == 0)
+ {
+ printf ("%s does not have a symbol-table.\n", name);
+ fflush (stdout);
+ return;
+ }
+
+ printf ("Reading symbol data from %s...", name);
+ fflush (stdout);
+
+ /* Now read the string table, all at once. */
+ val = lseek (desc, STRING_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+ stat (name, &statbuf);
+ READ_STRING_TABLE_SIZE (buffer);
+ if (buffer >= 0 && buffer < statbuf.st_size)
+ stringtab = (char *) alloca (buffer);
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", name, buffer);
+
+ bcopy (&buffer, stringtab, sizeof buffer);
+ val = myread (desc, stringtab + sizeof buffer, buffer - sizeof buffer);
+ if (val < 0)
+ perror_with_name (name);
+
+#ifdef READ_GDB_SYMSEGS
+ /* That puts us at the symsegs. Read them. */
+ symseg_chain = read_symsegs (desc, name);
+ hash_symsegs ();
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ for (symseg = symseg_chain; symseg; symseg = symseg->next)
+ {
+ int i;
+ struct sourcevector *sv = (struct sourcevector *) symseg->linetable;
+
+ for (i = 0; i < sv->length; i++)
+ {
+ int j;
+ struct source *source = sv->source[i];
+ struct symtab *sp1
+ = (struct symtab *) xxmalloc (sizeof (struct symtab));
+
+ bcopy (symseg, sp1, sizeof (struct symtab));
+ sp1->filename = savestring (source->name, strlen (source->name));
+ sp1->linetable = &source->contents;
+ sp1->free_code = free_nothing;
+ sp1->free_ptr = (i == 0) ? (char *) symseg : 0;
+
+ sp1->next = symtab_list;
+ symtab_list = sp1;
+ }
+ }
+#else
+ /* Where people are using the 4.2 ld program, must not check for
+ symsegs, because that ld puts randonm garbage at the end of
+ the output file and that would trigger an error message. */
+ symseg_chain = 0;
+#endif
+
+ /* Position to read the symbol table. Do not read it all at once. */
+ val = lseek (desc, SYMBOL_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+
+ init_misc_functions ();
+ make_cleanup (discard_misc_bunches, 0);
+ init_header_files ();
+ make_cleanup (free_header_files, 0);
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ make_cleanup (really_free_pendings, 0);
+
+ read_addl_syms (desc, stringtab, NUMBER_OF_SYMBOLS, text_addr,
+ SIZE_OF_TEXT_SEGMENT);
+
+
+ /* Sort symbols alphabetically within each block. */
+
+ sort_syms ();
+
+ /* Go over the misc functions and install them in vector. */
+
+ condense_addl_misc_bunches (1);
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+ /* Make a default for file to list. */
+ /* Hmmm. I'd say we don't want this in add_file_command, but . . . */
+
+ select_source_symtab (symtab_list);
+
+ do_cleanups (old_chain);
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ while (symseg_chain)
+ {
+ register struct symtab *s = symseg_chain->next;
+ free (symseg_chain);
+ symseg_chain = s;
+ }
+
+ printf ("done.\n");
+ fflush (stdout);
+}
+
+static struct symbol *
+define_symbol (value, string, desc)
+ int value;
+ char *string;
+ int desc;
+{
+ register struct symbol *sym
+ = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+ char *p = (char *) index (string, ':');
+ int deftype;
+ register int i;
+
+ /* Ignore syms with empty names. */
+ if (string[0] == 0)
+ return 0;
+
+ SYMBOL_NAME (sym)
+ = (char *) obstack_alloc (symbol_obstack, ((p - string) + 1));
+ /* Open-coded bcopy--saves function call time. */
+ {
+ register char *p1 = string;
+ register char *p2 = SYMBOL_NAME (sym);
+ while (p1 != p)
+ *p2++ = *p1++;
+ *p2++ = '\0';
+ }
+ p++;
+ /* Determine the type of name being defined. */
+ if ((*p >= '0' && *p <= '9') || *p == '(')
+ deftype = 'l';
+ else
+ deftype = *p++;
+
+ /* c is a special case, not followed by a type-number.
+ SYMBOL:c=iVALUE for an integer constant symbol.
+ SYMBOL:c=rVALUE for a floating constant symbol. */
+ if (deftype == 'c')
+ {
+ if (*p++ != '=')
+ error ("Invalid symbol data at symtab pos %d.", symnum);
+ switch (*p++)
+ {
+ case 'r':
+ {
+ double d = atof (p);
+ char *value;
+
+ SYMBOL_TYPE (sym) = builtin_type_double;
+ value = (char *) obstack_alloc (symbol_obstack, sizeof (double));
+ bcopy (&d, value, sizeof (double));
+ SYMBOL_VALUE_BYTES (sym) = value;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ }
+ break;
+ case 'i':
+ {
+ SYMBOL_TYPE (sym) = builtin_type_int;
+ SYMBOL_VALUE (sym) = atoi (p);
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ }
+ break;
+ default:
+ error ("Invalid symbol data at symtab pos %d.", symnum);
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+ }
+
+ /* Now usually comes a number that says which data type,
+ and possibly more stuff to define the type
+ (all of which is handled by read_type) */
+
+ if (deftype == 'p' && *p == 'F')
+ /* pF is a two-letter code that means a function parameter in Fortran.
+ The type-number specifies the type of the return value.
+ Translate it into a pointer-to-function type. */
+ {
+ p++;
+ SYMBOL_TYPE (sym)
+ = lookup_pointer_type (lookup_function_type (read_type (&p)));
+ }
+ else
+ {
+ struct type *type = read_type (&p);
+
+ if ((deftype == 'F' || deftype == 'f')
+ && TYPE_CODE (type) != TYPE_CODE_FUNC)
+ SYMBOL_TYPE (sym) = lookup_function_type (type);
+ else
+ SYMBOL_TYPE (sym) = type;
+ }
+
+ switch (deftype)
+ {
+ case 'f':
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'F':
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ case 'G':
+ /* For a class G (global) symbol, it appears that the
+ value is not correct. It is necessary to search for the
+ corresponding linker definition to find the value.
+ These definitions appear at the end of the namelist. */
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE (sym) = (int) global_sym_chain[i];
+ global_sym_chain[i] = sym;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ /* This case is faked by a conditional above,
+ when there is no code letter in the dbx data.
+ Dbx data never actually contains 'l'. */
+ case 'l':
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'p':
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ /* DESC == 0 implies compiled with GCC.
+ In this case, if it says `short', believe it. */
+ if (desc == 0)
+ break;
+ /* If PCC says a parameter is a short or a char,
+ it is really an int. */
+ if (SYMBOL_TYPE (sym) == builtin_type_char
+ || SYMBOL_TYPE (sym) == builtin_type_short)
+ SYMBOL_TYPE (sym) = builtin_type_int;
+ else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char
+ || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+ SYMBOL_TYPE (sym) = builtin_type_unsigned_int;
+ break;
+
+ case 'P':
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'r':
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'S':
+ /* Static symbol at top level of file */
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 't':
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+ && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym)) =
+ obsavestring (SYMBOL_NAME (sym),
+ strlen (SYMBOL_NAME (sym)));
+ /* C++ vagaries: we may have a type which is derived from
+ a base type which did not have its name defined when the
+ derived class was output. We fill in the derived class's
+ base part member's name here in that case. */
+ else if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)
+ && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)))
+ {
+ int i;
+ for (i = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)); i > 0; i--)
+ if (TYPE_FIELD_NAME (SYMBOL_TYPE (sym), i - 1) == 0)
+ TYPE_FIELD_NAME (SYMBOL_TYPE (sym), i - 1) =
+ TYPE_NAME (TYPE_BASECLASS (SYMBOL_TYPE (sym), i));
+ }
+
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'T':
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+ && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = obconcat ("",
+ (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM
+ ? "enum "
+ : (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ ? "struct " : "union ")),
+ SYMBOL_NAME (sym));
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'V':
+ case 'v':
+ /* Static symbol of local scope */
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ default:
+ error ("Invalid symbol data: unknown symbol-type code `%c' at symtab pos %d.", deftype, symnum);
+ }
+ return sym;
+}
+
+/* Read a number by which a type is referred to in dbx data,
+ or perhaps read a pair (FILENUM, TYPENUM) in parentheses.
+ Just a single number N is equivalent to (0,N).
+ Return the two numbers by storing them in the vector TYPENUMS.
+ TYPENUMS will then be used as an argument to dbx_lookup_type. */
+
+static void
+read_type_number (pp, typenums)
+ register char **pp;
+ register int *typenums;
+{
+ if (**pp == '(')
+ {
+ (*pp)++;
+ typenums[0] = read_number (pp, ',');
+ typenums[1] = read_number (pp, ')');
+ }
+ else
+ {
+ typenums[0] = 0;
+ typenums[1] = read_number (pp, 0);
+ }
+}
+
+/* Read a dbx type reference or definition;
+ return the type that is meant.
+ This can be just a number, in which case it references
+ a type already defined and placed in type_vector.
+ Or the number can be followed by an =, in which case
+ it means to define a new type according to the text that
+ follows the =. */
+
+static
+struct type *
+read_type (pp)
+ register char **pp;
+{
+ register struct type *type = 0;
+ register int n;
+ struct type *type1;
+ int typenums[2];
+ int xtypenums[2];
+
+ read_type_number (pp, typenums);
+
+ /* Detect random reference to type not yet defined.
+ Allocate a type object but leave it zeroed. */
+ if (**pp != '=')
+ return dbx_alloc_type (typenums);
+
+ *pp += 2;
+ switch ((*pp)[-1])
+ {
+ case 'x':
+ type = dbx_alloc_type (typenums);
+ /* Set the type code according to the following letter. */
+ switch ((*pp)[0])
+ {
+ case 's':
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+ case 'e':
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ break;
+ }
+ /* Skip the name the cross-ref points to. */
+ /* Note: for C++, the cross reference may be to a base type which
+ has not yet been seen. In this case, we skip to the comma,
+ which will mark the end of the base class name. (The ':'
+ at the end of the base class name will be skipped as well.) */
+ *pp = (char *) index (*pp, ',');
+ /* Just allocate the type and leave it zero if nothing known */
+ return dbx_alloc_type (typenums);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '(':
+ (*pp)--;
+ read_type_number (pp, xtypenums);
+ type = *dbx_lookup_type (xtypenums);
+ if (type == 0)
+ type = builtin_type_void;
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case '*':
+ type1 = read_type (pp);
+ if (TYPE_POINTER_TYPE (type1))
+ {
+ type = TYPE_POINTER_TYPE (type1);
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_pointer_type (type, type1);
+ }
+ break;
+
+ case '@@':
+ {
+ struct type *domain = read_type (pp);
+ char c;
+ struct type *memtype;
+
+ if (*(*pp)++ != ',')
+ error ("invalid member type data format, at symtab pos %d.",
+ symnum);
+
+ memtype = read_type (pp);
+ type = dbx_alloc_type (typenums);
+ smash_to_member_type (type, domain, memtype);
+ }
+ break;
+
+ case '&':
+ type1 = read_type (pp);
+ if (TYPE_REFERENCE_TYPE (type1))
+ {
+ type = TYPE_REFERENCE_TYPE (type1);
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_reference_type (type, type1);
+ }
+ break;
+
+ case 'f':
+ type1 = read_type (pp);
+ if (TYPE_FUNCTION_TYPE (type1))
+ {
+ type = TYPE_FUNCTION_TYPE (type1);
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_function_type (type, type1);
+ }
+ break;
+
+ case 'r':
+ type = read_range_type (pp, typenums);
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'e':
+ type = dbx_alloc_type (typenums);
+ type = read_enum_type (pp, type);
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 's':
+ type = dbx_alloc_type (typenums);
+ type = read_struct_type (pp, type);
+ break;
+
+ case 'u':
+ type = dbx_alloc_type (typenums);
+ type = read_struct_type (pp, type);
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+
+ case 'a':
+ if (*(*pp)++ != 'r')
+ error ("Invalid symbol data: unrecognized type-code `a%c' %s %d.",
+ (*pp)[-1], "at symtab position", symnum);
+
+ type = dbx_alloc_type (typenums);
+ type = read_array_type (pp, type);
+ break;
+
+#if 0
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>". Put code
+ in to handle this. */
+
+ /* dbx expresses array types in terms of a range type for the index,
+ and that range type is specified right inside the array type spec
+ making ar1;MIN;MAX;VALTYPE */
+ if (!strncmp (*pp, "r1;0;", 5))
+ (*pp) += 5;
+ else if (!strncmp (*pp, "r(0,1);0;", 9))
+ (*pp) += 9;
+ else break;
+
+ TYPE_CODE (type) = TYPE_CODE_ARRAY;
+ /* In Fortran, an upper bound may be T... meaning a parameter specifies
+ the length of the data. In this case, just pretend the bound is 1.
+ This happens only for array parameters, which are really passed
+ as pointers anyway, and we will translate them into such. */
+ if (**pp == 'T')
+ {
+ n = 1;
+ while (**pp != ';')
+ (*pp)++;
+ }
+ else
+ n = read_number (pp, ';') + 1;
+ TYPE_TARGET_TYPE (type) = read_type (pp);
+ TYPE_LENGTH (type) = TYPE_LENGTH (TYPE_TARGET_TYPE (type)) * n;
+ break;
+#endif
+
+ default:
+ error ("Invalid symbol data: unrecognized type-code `%c' at symtab pos %d.",
+ (*pp)[-1], symnum);
+ }
+
+ if (type == 0)
+ abort ();
+
+#if 0
+ /* If this is an overriding temporary alteration for a header file's
+ contents, and this type number is unknown in the global definition,
+ put this type into the global definition at this type number. */
+ if (header_file_prev_index >= 0)
+ {
+ register struct type **tp
+ = explicit_lookup_type (header_file_prev_index, typenums[1]);
+ if (*tp == 0)
+ *tp = type;
+ }
+#endif
+ return type;
+}
+
+/* This page contains subroutines of read_type. */
+
+/* Read the description of a structure (or union type)
+ and return an object describing the type. */
+
+static struct type *
+read_struct_type (pp, type)
+ char **pp;
+ register struct type *type;
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+ int visibility;
+ struct field field;
+ };
+
+ struct next_fnfield
+ {
+ struct next_fnfield *next;
+ int visibility;
+ struct fn_field fn_field;
+ };
+
+ struct next_fnfieldlist
+ {
+ struct next_fnfieldlist *next;
+ struct fn_fieldlist fn_fieldlist;
+ };
+
+ register struct nextfield *list = 0;
+ struct nextfield *new;
+ int totalsize;
+ char *name;
+ register char *p;
+ int nfields = 0;
+ register int n;
+
+ register struct next_fnfieldlist *mainlist = 0;
+ int nfn_fields = 0;
+ struct type *baseclass = NULL;
+ int read_possible_virtual_info = 0;
+
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+ /* First comes the total size in bytes. */
+
+ TYPE_LENGTH (type) = read_number (pp, 0);
+
+ /* C++: Now, if the class is a derived class, then the next character
+ will be a '!', followed by the number of base classes derived from.
+ Each element in the list contains visibility information,
+ the offset of this base class in the derived structure,
+ and then the base type. */
+ if (**pp == '!')
+ {
+ int i, n_baseclasses, offset;
+ struct type **baseclass_vec;
+ struct type *baseclass;
+ int via_public, via_virtual;
+
+ *pp += 1;
+
+ n_baseclasses = read_number (pp, ',');
+ baseclass_vec = (struct type **)
+ obstack_alloc (symbol_obstack,
+ (n_baseclasses) * sizeof (struct type **)) - 1;
+
+ for (i = 1; i <= n_baseclasses; i++)
+ {
+ if (**pp == '\\')
+ *pp = next_symbol_text ();
+
+ switch (*(*pp)++)
+ {
+ case '0':
+ via_virtual = 0;
+ break;
+ case '1':
+ via_virtual = 1;
+ break;
+ default:
+ error ("Invalid symbol data: bad visibility format at symtab pos %d",
+ symnum);
+ }
+
+ switch (*(*pp)++)
+ {
+ case '0':
+ via_public = 0;
+ break;
+ case '2':
+ via_public = 1;
+ break;
+ default:
+ error ("Invalid symbol data: bad visibility format at symtab pos %d.",
+ symnum);
+ }
+ offset = read_number (pp, ',');
+ baseclass = read_type (pp);
+ *pp += 1; /* skip trailing ';' */
+ baseclass_vec[i] = lookup_basetype_type (baseclass, offset, via_virtual, via_public);
+
+ /* Make this baseclass visible for structure-printing purposes. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+ list->field.type = baseclass_vec[i];
+ list->field.name = TYPE_NAME (baseclass_vec[i]);
+ list->field.bitpos = offset;
+ list->field.bitsize = 0; /* this should be an unpacked field! */
+ nfields++;
+ }
+ TYPE_N_BASECLASSES (type) = n_baseclasses;
+ TYPE_BASECLASSES (type) = baseclass_vec;
+ }
+
+ /* Now come the fields, as NAME:?TYPENUM,BITPOS,BITSIZE; for each one.
+ At the end, we see a semicolon instead of a field.
+
+ In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+ a static field.
+
+ The `?' is a placeholder for one of '+' (public visibility),
+ '0' (protected visibility), and '-' (private visibility). */
+
+ while (**pp != ';')
+ {
+ int visibility;
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Read the data. */
+ p = *pp;
+ while (*p != ':') p++;
+ list->field.name = obsavestring (*pp, p - *pp);
+
+ /* C++: Check to see if we have hit the methods yet. */
+ if (p[1] == ':')
+ break;
+
+ *pp = p + 1;
+
+ /* This means we have a visibility for a field coming. */
+ if (**pp == '/')
+ {
+ switch (*++*pp)
+ {
+ case '0':
+ visibility = 0;
+ *pp += 1;
+ break;
+
+ case '1':
+ visibility = 1;
+ *pp += 1;
+ break;
+
+ case '2':
+ visibility = 2;
+ *pp += 1;
+ break;
+ }
+ }
+ /* else normal dbx-style format. */
+
+ list->field.type = read_type (pp);
+ if (**pp == ':')
+ {
+ list->field.bitpos = (long)-1;
+ p = ++(*pp);
+ while (*p != ';') p++;
+ list->field.bitsize = (long) savestring (*pp, p - *pp);
+ *pp = p + 1;
+ nfields++;
+ continue;
+ }
+ else if (**pp != ',')
+ error ("Invalid symbol data: bad structure-type format at symtab pos %d.",
+ symnum);
+ (*pp)++; /* Skip the comma. */
+ list->field.bitpos = read_number (pp, ',');
+ list->field.bitsize = read_number (pp, ';');
+ /* Detect an unpacked field and mark it as such.
+ dbx gives a bit size for all fields.
+ Note that forward refs cannot be packed,
+ and treat enums as if they had the width of ints. */
+ if (TYPE_CODE (list->field.type) != TYPE_CODE_INT
+ && TYPE_CODE (list->field.type) != TYPE_CODE_ENUM)
+ list->field.bitsize = 0;
+ if ((list->field.bitsize == 8 * TYPE_LENGTH (list->field.type)
+ || (TYPE_CODE (list->field.type) == TYPE_CODE_ENUM
+ && list->field.bitsize == 8 * TYPE_LENGTH (builtin_type_int)))
+ &&
+ list->field.bitpos % 8 == 0)
+ list->field.bitsize = 0;
+ nfields++;
+ }
+
+ /* Now come the method fields, as NAME::methods
+ where each method is of the form TYPENUM,ARGS,...:PHYSNAME;
+ At the end, we see a semicolon instead of a field.
+
+ For the case of overloaded operators, the format is
+ OPERATOR::*.methods, where OPERATOR is the string "operator",
+ `*' holds the place for an operator name (such as `+=')
+ and `.' marks the end of the operator name. */
+ if (p[1] == ':')
+ {
+ /* Now, read in the methods. To simplify matters, we
+ "unread" the name that has been read, so that we can
+ start from the top. */
+
+ p = *pp;
+
+ /* chill the list of fields: the last entry (at the head)
+ is a partially constructed entry which we now scrub. */
+ list = list->next;
+
+ /* For each list of method lists... */
+ do
+ {
+ int i;
+ struct next_fnfield *sublist = 0;
+ struct fn_field *fn_fields = 0;
+ int length = 0;
+ struct next_fnfieldlist *new_mainlist =
+ (struct next_fnfieldlist *)alloca (sizeof (struct next_fnfieldlist));
+
+ /* read in the name. */
+ while (*p != ':') p++;
+ if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == '$')
+ {
+ static char opname[32] = "operator ";
+ char *o = opname + 9;
+
+ /* Skip past '::'. */
+ p += 2;
+ while (*p != '.')
+ *o++ = *p++;
+ new_mainlist->fn_fieldlist.name = savestring (opname, o - opname);
+ /* Skip past '.' */
+ *pp = p + 1;
+ }
+ else
+ {
+ i = 0;
+ new_mainlist->fn_fieldlist.name = savestring (*pp, p - *pp);
+ /* Skip past '::'. */
+ *pp = p + 2;
+ }
+
+ do
+ {
+ struct next_fnfield *new_sublist =
+ (struct next_fnfield *)alloca (sizeof (struct next_fnfield));
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ new_sublist->fn_field.type = read_type (pp);
+ new_sublist->fn_field.args = read_args (pp, ':');
+ p = *pp;
+ while (*p != ';') p++;
+ new_sublist->fn_field.physname = savestring (*pp, p - *pp);
+ *pp = p + 1;
+ new_sublist->visibility = *(*pp)++ - '0';
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ if (*(*pp)++ == '*')
+ new_sublist->fn_field.voffset = read_number (pp, ';') + 1;
+ else
+ new_sublist->fn_field.voffset = 0;
+
+ new_sublist->next = sublist;
+ sublist = new_sublist;
+ length++;
+ }
+ while (**pp != ';');
+
+ *pp += 1;
+
+ new_mainlist->fn_fieldlist.fn_fields =
+ (struct fn_field *) obstack_alloc (symbol_obstack,
+ sizeof (struct fn_field) * length);
+ TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (length >> 5)));
+
+ TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (length >> 5)));
+
+ for (i = length; sublist; sublist = sublist->next)
+ {
+ new_mainlist->fn_fieldlist.fn_fields[--i] = sublist->fn_field;
+ if (sublist->visibility == 0)
+ B_SET (new_mainlist->fn_fieldlist.private_fn_field_bits, i);
+ else if (sublist->visibility == 1)
+ B_SET (new_mainlist->fn_fieldlist.protected_fn_field_bits, i);
+ }
+
+ new_mainlist->fn_fieldlist.length = length;
+ new_mainlist->next = mainlist;
+ mainlist = new_mainlist;
+ nfn_fields++;
+ }
+ while (**pp != ';');
+ }
+
+ *pp += 1;
+
+ /* Now create the vector of fields, and record how big it is. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack,
+ sizeof (struct field) * nfields);
+ TYPE_FIELD_PRIVATE_BITS (type) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (nfields >> 5)));
+ TYPE_FIELD_PROTECTED_BITS (type) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (nfields >> 5)));
+
+ TYPE_NFN_FIELDS (type) = nfn_fields;
+ TYPE_NFN_FIELDS_TOTAL (type) = nfn_fields;
+ if (baseclass)
+ TYPE_NFN_FIELDS_TOTAL (type) += TYPE_NFN_FIELDS_TOTAL (baseclass);
+
+ TYPE_FN_FIELDLISTS (type) =
+ (struct fn_fieldlist *) obstack_alloc (symbol_obstack,
+ sizeof (struct fn_fieldlist) * nfn_fields);
+
+ /* Copy the saved-up fields into the field vector. */
+
+ for (n = nfields; list; list = list->next)
+ {
+ TYPE_FIELD (type, --n) = list->field;
+ if (list->visibility == 0)
+ SET_TYPE_FIELD_PRIVATE (type, n);
+ else if (list->visibility == 1)
+ SET_TYPE_FIELD_PROTECTED (type, n);
+ }
+
+ for (n = nfn_fields; mainlist; mainlist = mainlist->next)
+ TYPE_FN_FIELDLISTS (type)[--n] = mainlist->fn_fieldlist;
+
+ if (**pp == '~')
+ {
+ *pp += 1;
+
+ if (**pp == '=')
+ {
+ TYPE_FLAGS (type)
+ |= TYPE_FLAG_HAS_CONSTRUCTOR | TYPE_FLAG_HAS_DESTRUCTOR;
+ *pp += 1;
+ }
+ else if (**pp == '+')
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_HAS_CONSTRUCTOR;
+ *pp += 1;
+ }
+ else if (**pp == '-')
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_HAS_DESTRUCTOR;
+ *pp += 1;
+ }
+
+ /* Read either a '%' or the final ';'. */
+ if (*(*pp)++ == '%')
+ {
+ /* Now we must record the virtual function table pointer's
+ field information. */
+
+ struct type *t;
+ int i;
+
+ t = read_type (pp);
+ p = (*pp)++;
+ while (*p != ';') p++;
+ TYPE_VPTR_BASETYPE (type) = t;
+ if (type == t)
+ {
+ if (TYPE_FIELD_NAME (t, 0) == 0)
+ TYPE_VPTR_FIELDNO (type) = i = 0;
+ else for (i = TYPE_NFIELDS (t) - 1; i >= 0; --i)
+ if (! strncmp (TYPE_FIELD_NAME (t, i), *pp,
+ strlen (TYPE_FIELD_NAME (t, i))))
+ {
+ TYPE_VPTR_FIELDNO (type) = i;
+ break;
+ }
+ if (i < 0)
+ error ("virtual function table field not found");
+ }
+ else
+ TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, 1));
+ *pp = p + 1;
+ }
+ else
+ {
+ TYPE_VPTR_BASETYPE (type) = 0;
+ TYPE_VPTR_FIELDNO (type) = -1;
+ }
+ }
+ else
+ {
+ TYPE_VPTR_BASETYPE (type) = 0;
+ TYPE_VPTR_FIELDNO (type) = -1;
+ }
+
+ return type;
+}
+
+/* Read a definition of an enumberation type,
+ and create and return a suitable type object.
+ Also creates a range type which represents the bounds of that
+ array. */
+static struct type *
+read_array_type (pp, type)
+ register char **pp;
+ register struct type *type;
+{
+ struct type *index_type, *element_type, *range_type;
+ int lower, upper;
+
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>". Put code in
+ to handle this. */
+
+ index_type = read_type (pp);
+ if (*(*pp)++ != ';')
+ error ("Invalid symbol data; improper format of array type decl.");
+ lower = read_number (pp, ';');
+ upper = read_number (pp, ';');
+ element_type = read_type (pp);
+
+ {
+ /* Create range type. */
+ range_type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ TYPE_CODE (range_type) = TYPE_CODE_RANGE;
+ TYPE_TARGET_TYPE (range_type) = index_type;
+
+ /* This should never be needed. */
+ TYPE_LENGTH (range_type) = sizeof (int);
+
+ TYPE_NFIELDS (range_type) = 2;
+ TYPE_FIELDS (range_type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ 2 * sizeof (struct field));
+ TYPE_FIELD_BITPOS (range_type, 0) = lower;
+ TYPE_FIELD_BITPOS (range_type, 1) = upper;
+ }
+
+ TYPE_CODE (type) = TYPE_CODE_ARRAY;
+ TYPE_TARGET_TYPE (type) = element_type;
+ TYPE_LENGTH (type) = (upper - lower + 1) * TYPE_LENGTH (element_type);
+ TYPE_NFIELDS (type) = 1;
+ TYPE_FIELDS (type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ sizeof (struct field));
+ TYPE_FIELD_TYPE (type, 0) = range_type;
+
+ return type;
+}
+
+
+/* Read a definition of an enumeration type,
+ and create and return a suitable type object.
+ Also defines the symbols that represent the values of the type. */
+
+static struct type *
+read_enum_type (pp, type)
+ register char **pp;
+ register struct type *type;
+{
+ register char *p;
+ char *name;
+ register long n;
+ register struct symbol *sym;
+ int nsyms = 0;
+ struct pending **symlist;
+ struct pending *osyms, *syms;
+ int o_nsyms;
+
+ if (within_function)
+ symlist = &local_symbols;
+ else
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ /* Read the value-names and their values.
+ The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+ A semicolon instead of a NAME means the end. */
+ while (**pp && **pp != ';')
+ {
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ p = *pp;
+ while (*p != ':') p++;
+ name = obsavestring (*pp, p - *pp);
+ *pp = p + 1;
+ n = read_number (pp, ',');
+
+ sym = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+ bzero (sym, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = name;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (sym) = n;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ }
+
+ (*pp)++; /* Skip the semicolon. */
+
+ /* Now fill in the fields of the type-structure. */
+
+ TYPE_LENGTH (type) = sizeof (int);
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the values and put them into the type.
+ The symbols can be found in the symlist that we put them on
+ to cause them to be defined. osyms contains the old value
+ of that symlist; everything up to there was defined by us. */
+
+ for (syms = *symlist, n = nsyms; syms; syms = syms->next)
+ {
+ int j = 0;
+ if (syms == osyms)
+ j = o_nsyms;
+ for (; j < syms->nsyms; j++)
+ {
+ struct symbol *sym = syms->symbol[j];
+ SYMBOL_TYPE (sym) = type;
+ TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (sym);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (sym);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+ return type;
+}
+
+#define MAX_OF_TYPE(t) ((1 << (sizeof (t) - 1)) - 1)
+#define MIN_OF_TYPE(t) (-(1 << (sizeof (t) - 1)))
+
+static struct type *
+read_range_type (pp, typenums)
+ char **pp;
+ int typenums[2];
+{
+ char *errp = *pp;
+ int rangenums[2];
+ int n2, n3;
+ int self_subrange;
+ struct type *result_type;
+
+ /* First comes a type we are a subrange of.
+ In C it is usually 0, 1 or the type being defined. */
+ read_type_number (pp, rangenums);
+ self_subrange = (rangenums[0] == typenums[0] &&
+ rangenums[1] == typenums[1]);
+
+ /* A semicolon should now follow; skip it. */
+ if (**pp == ';')
+ (*pp)++;
+
+ /* The remaining two operands are usually lower and upper bounds
+ of the range. But in some special cases they mean something else. */
+ n2 = read_number (pp, ';');
+ n3 = read_number (pp, ';');
+
+ /* A type defined as a subrange of itself, with bounds both 0, is void. */
+ if (self_subrange && n2 == 0 && n3 == 0)
+ return builtin_type_void;
+
+ /* If n3 is zero and n2 is not, we want a floating type,
+ and n2 is the width in bytes.
+
+ Fortran programs appear to use this for complex types also,
+ and they give no way to distinguish between double and single-complex!
+ We don't have complex types, so we would lose on all fortran files!
+ So return type `double' for all of those. It won't work right
+ for the complex values, but at least it makes the file loadable. */
+
+ if (n3 == 0 && n2 > 0)
+ {
+ if (n2 == sizeof (float))
+ return builtin_type_float;
+ return builtin_type_double;
+ }
+
+ /* If the upper bound is -1, it must really be an unsigned int. */
+
+ else if (n2 == 0 && n3 == -1)
+ {
+ if (sizeof (int) == sizeof (long))
+ return builtin_type_unsigned_int;
+ else
+ return builtin_type_unsigned_long;
+ }
+
+ /* Special case: char is defined (Who knows why) as a subrange of
+ itself with range 0-127. */
+ else if (self_subrange && n2 == 0 && n3 == 127)
+ return builtin_type_char;
+
+ /* Assumptions made here: Subrange of self is equivalent to subrange
+ of int. */
+ else if (n2 == 0
+ && (self_subrange ||
+ *dbx_lookup_type (rangenums) == builtin_type_int))
+ {
+ /* an unsigned type */
+ if (n3 == (1 << (8 * sizeof (int))) - 1)
+ return builtin_type_unsigned_int;
+ if (n3 == (1 << (8 * sizeof (short))) - 1)
+ return builtin_type_unsigned_short;
+ if (n3 == (1 << (8 * sizeof (char))) - 1)
+ return builtin_type_unsigned_char;
+ }
+ else if (n2 == -n3 -1)
+ {
+ /* a signed type */
+ if (n3 == (1 << (8 * sizeof (int) - 1)) - 1)
+ return builtin_type_int;
+ if (n3 == (1 << (8 * sizeof (long) - 1)) - 1)
+ return builtin_type_long;
+ if (n3 == (1 << (8 * sizeof (short) - 1)) - 1)
+ return builtin_type_short;
+ if (n3 == (1 << (8 * sizeof (char) - 1)) - 1)
+ return builtin_type_char;
+ }
+
+ /* We have a real range type on our hands. Allocate space and
+ return a real pointer. */
+
+ /* At this point I don't have the faintest idea how to deal with
+ a self_subrange type; I'm going to assume that this is used
+ as an idiom, and that all of them are special cases. So . . . */
+ if (self_subrange)
+ error ("Type defined as subrange of itself.");
+
+ result_type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ bzero (result_type, sizeof (struct type));
+
+ TYPE_TARGET_TYPE (result_type) = (self_subrange ?
+ builtin_type_int :
+ *dbx_lookup_type(rangenums));
+
+ /* We have to figure out how many bytes it takes to hold this
+ range type. I'm going to assume that anything that is pushing
+ the bounds of a long was taken care of above. */
+ if (n2 >= MIN_OF_TYPE(char) && n3 <= MAX_OF_TYPE(char))
+ TYPE_LENGTH (result_type) = 1;
+ else if (n2 >= MIN_OF_TYPE(short) && n3 <= MAX_OF_TYPE(short))
+ TYPE_LENGTH (result_type) = sizeof (short);
+ else if (n2 >= MIN_OF_TYPE(int) && n3 <= MAX_OF_TYPE(int))
+ TYPE_LENGTH (result_type) = sizeof (int);
+ else if (n2 >= MIN_OF_TYPE(long) && n3 <= MAX_OF_TYPE(long))
+ TYPE_LENGTH (result_type) = sizeof (long);
+ else
+ error ("Ranged type doesn't fit within known sizes.");
+
+ TYPE_LENGTH (result_type) = TYPE_LENGTH (TYPE_TARGET_TYPE (result_type));
+ TYPE_CODE (result_type) = TYPE_CODE_RANGE;
+ TYPE_NFIELDS (result_type) = 2;
+ TYPE_FIELDS (result_type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ 2 * sizeof (struct field));
+ bzero (TYPE_FIELDS (result_type), 2 * sizeof (struct field));
+ TYPE_FIELD_BITPOS (result_type, 0) = n2;
+ TYPE_FIELD_BITPOS (result_type, 1) = n3;
+
+ return result_type;
+}
+
+/* Read a number from the string pointed to by *PP.
+ The value of *PP is advanced over the number.
+ If END is nonzero, the character that ends the
+ number must match END, or an error happens;
+ and that character is skipped if it does match.
+ If END is zero, *PP is left pointing to that character. */
+
+static long
+read_number (pp, end)
+ char **pp;
+ int end;
+{
+ register char *p = *pp;
+ register long n = 0;
+ register int c;
+ int sign = 1;
+
+ /* Handle an optional leading minus sign. */
+
+ if (*p == '-')
+ {
+ sign = -1;
+ p++;
+ }
+
+ /* Read the digits, as far as they go. */
+
+ while ((c = *p++) >= '0' && c <= '9')
+ {
+ n *= 10;
+ n += c - '0';
+ }
+ if (end)
+ {
+ if (c && c != end)
+ error ("Invalid symbol data: invalid character \\%03o at symbol pos %d.", c, symnum);
+ }
+ else
+ --p;
+
+ *pp = p;
+ return n * sign;
+}
+
+/* Read in an argument list. This is a list of types. It is terminated with
+ a ':', FYI. Return the list of types read in. */
+static struct type **
+read_args (pp, end)
+ char **pp;
+ int end;
+{
+ struct type *types[1024], **rval; /* allow for fns of 1023 parameters */
+ int n = 0;
+
+ while (**pp != end)
+ {
+ if (**pp != ',')
+ error ("Invalid argument list: no ',', at symtab pos %d", symnum);
+ *pp += 1;
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\')
+ *pp = next_symbol_text ();
+
+ types[n++] = read_type (pp);
+ }
+ *pp += 1; /* get past `end' (the ':' character) */
+
+ if (n == 1)
+ {
+ rval = (struct type **) xmalloc (2 * sizeof (struct type *));
+ }
+ else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID)
+ {
+ rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *));
+ bzero (rval + n, sizeof (struct type *));
+ }
+ else
+ {
+ rval = (struct type **) xmalloc (n * sizeof (struct type *));
+ }
+ bcopy (types, rval, n * sizeof (struct type *));
+ return rval;
+}
+
+/* This function is really horrible, but to avoid it, there would need
+ to be more filling in of forward references. THIS SHOULD BE MOVED OUT
+ OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED */
+int
+fill_in_vptr_fieldno (type)
+ struct type *type;
+{
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ TYPE_VPTR_FIELDNO (type) =
+ fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1));
+ return TYPE_VPTR_FIELDNO (type);
+}
+
+void
+_initialize_dbxread ()
+{
+ symfile = 0;
+ header_files = (struct header_file *) 0;
+ this_object_header_files = (int *) 0;
+
+ add_com ("symbol-file", class_files, symbol_file_command,
+ "Load symbol table (in dbx format) from executable file FILE.");
+
+ add_com ("add-file", class_files, add_file_command,
+ "Load the symbols from FILE, assuming its code is at TEXT_START.") ;
+}
+
+#endif /* READ_DBX_FORMAT */
+@
+
+
+1.2
+log
+@If discarding the symbol table, discard its name too, so "info files"
+will give the right answer.
+@
+text
+@d27 1
+a27 1
+#include <sys/fcntl.h>
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d2 1
+a2 1
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+d1457 3
+@
diff --git a/gdb/RCS/default-dep.c,v b/gdb/RCS/default-dep.c,v
new file mode 100644
index 0000000..81c18f3
--- /dev/null
+++ b/gdb/RCS/default-dep.c,v
@@ -0,0 +1,731 @@
+head 1.4;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.4
+date 89.03.27.20.08.50; author gnu; state Exp;
+branches ;
+next 1.3;
+
+1.3
+date 89.03.27.20.07.47; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.03.27.18.49.06; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.20.19.47.11; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.4
+log
+@Restore A/UX-specific changes.
+@
+text
+@/* Low level interface to ptrace, for GDB when running under Unix.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#ifdef UNISOFT_ASSHOLES
+#define PMMU
+#define NEW_PMMU
+#define mc68881 /* Needed to get float in user.h!!! */
+#include <sys/seg.h> /* For user.h */
+#include <sys/mmu.h>
+#include <sys/time.h>
+/* Things Unisoft defined differently from every other Unix system */
+#define NBPG PAGESIZE
+#define UPAGES USIZE
+#define KERNEL_U_ADDR UDOT
+#endif
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+#include <a.out.h>
+#endif
+#ifndef N_SET_MAGIC
+#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
+#endif
+
+#include <sys/user.h> /* After a.out.h */
+#include <sys/file.h>
+#include <sys/stat.h>
+
+extern int errno;
+
+/* This function simply calls ptrace with the given arguments.
+ It exists so that all calls to ptrace are isolated in this
+ machine-dependent file.
+
+ If you are having trouble debugging ptrace calls, turn on DEBUG
+ and every call to ptrace, in this module or elsewhere, will be
+ logged to stderr. */
+int
+call_ptrace (request, pid, arg3, arg4)
+ int request, pid, arg3, arg4;
+{
+#ifdef DEBUG
+ int result;
+
+ fprintf(stderr, "ptrace(%x,,%x, %x) = ", request, arg3, arg4);
+ result=ptrace (request, pid, arg3, arg4);
+ fprintf(stderr, "%x\n", result);
+ return result;
+
+#define ptrace call_ptrace
+
+#else
+ return ptrace (request, pid, arg3, arg4);
+#endif
+}
+
+kill_inferior ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+ inferior_died ();
+}
+
+/* This is used when GDB is exiting. It gives less chance of error.*/
+
+kill_inferior_fast ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+}
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+resume (step, signal)
+ int step;
+ int signal;
+{
+ errno = 0;
+ if (remote_debugging)
+ remote_resume (step, signal);
+ else
+ {
+ ptrace (step ? 9 : 7, inferior_pid, 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+ }
+}
+
+void
+fetch_inferior_registers ()
+{
+ register int regno;
+ register unsigned int regaddr;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ register int i;
+
+ struct user u;
+ unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
+ offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
+ regaddr += sizeof (int);
+ }
+ supply_register (regno, buf);
+ }
+}
+
+/* Store our register values back into the inferior.
+ If REGNO is -1, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+
+store_inferior_registers (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[80];
+
+ struct user u;
+ unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
+ offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
+
+ if (regno >= 0)
+ {
+ regaddr = register_addr (regno, offset);
+ errno = 0;
+#ifdef UNISOFT_ASSHOLES
+ /* You can't write the PC with ptrace 6, only with ptrace 11! */
+ if (regno == PC_REGNUM)
+ ptrace(11, inferior_pid, 16, read_register(regno));
+ else
+#endif
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+ if (errno != 0)
+ {
+ sprintf (buf, "writing register number %d", regno);
+ perror_with_name (buf);
+ }
+ }
+ else for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ regaddr = register_addr (regno, offset);
+ errno = 0;
+#ifdef UNISOFT_ASSHOLES
+ if (regno == PC_REGNUM)
+ ptrace(11, inferior_pid, 16, read_register(regno));
+ else
+#endif
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+ if (errno != 0)
+ {
+ sprintf (buf, "writing all regs, number %d", regno);
+ perror_with_name (buf);
+ }
+ }
+}
+
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+ to debugger memory starting at MYADDR.
+ On failure (cannot read from inferior, usually because address is out
+ of bounds) returns the value of errno. */
+
+int
+read_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca (count * sizeof (int));
+ extern int errno;
+
+ /* Read all the longwords */
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ if (remote_debugging)
+ buffer[i] = remote_fetch_word (addr);
+ else
+ buffer[i] = ptrace (1, inferior_pid, addr, 0);
+ if (errno)
+ return errno;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+ return 0;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+ to inferior's memory at MEMADDR.
+ On failure (cannot write the inferior)
+ returns the value of errno. */
+
+int
+write_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca (count * sizeof (int));
+ extern int errno;
+
+ /* Fill start and end extra bytes of buffer with existing memory data. */
+
+ if (remote_debugging)
+ buffer[0] = remote_fetch_word (addr);
+ else
+ buffer[0] = ptrace (1, inferior_pid, addr, 0);
+
+ if (count > 1)
+ {
+ if (remote_debugging)
+ buffer[count - 1]
+ = remote_fetch_word (addr + (count - 1) * sizeof (int));
+ else
+ buffer[count - 1]
+ = ptrace (1, inferior_pid,
+ addr + (count - 1) * sizeof (int), 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ if (remote_debugging)
+ remote_store_word (addr, buffer[i]);
+ else
+ ptrace (4, inferior_pid, addr, buffer[i]);
+ if (errno)
+ return errno;
+ }
+
+ return 0;
+}
+
+/* Work with core dump and executable files, for GDB.
+ This code would be in core.c if it weren't machine-dependent. */
+
+/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
+#ifdef AOUTHDR
+#define COFF_FORMAT
+#endif
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(hdr) 0
+#endif /* no N_TXTADDR */
+
+#ifndef N_DATADDR
+#define N_DATADDR(hdr) hdr.a_text
+#endif /* no N_DATADDR */
+
+/* Make COFF and non-COFF names for things a little more compatible
+ to reduce conditionals later. */
+
+#ifdef COFF_FORMAT
+#define a_magic magic
+#endif
+
+#ifndef COFF_FORMAT
+#define AOUTHDR struct exec
+#endif
+
+extern char *sys_siglist[];
+
+
+/* Hook for `exec_file_command' command to call. */
+
+extern void (*exec_file_display_hook) ();
+
+/* File names of core file and executable file. */
+
+extern char *corefile;
+extern char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+extern int corechan;
+extern int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+extern int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+extern CORE_ADDR data_start;
+extern CORE_ADDR data_end;
+extern CORE_ADDR stack_start;
+extern CORE_ADDR stack_end;
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+extern CORE_ADDR text_start;
+extern CORE_ADDR text_end;
+
+extern CORE_ADDR exec_data_start;
+extern CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+extern int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+extern int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+extern int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+extern int stack_offset;
+
+#ifdef COFF_FORMAT
+/* various coff data structures */
+
+extern FILHDR file_hdr;
+extern SCNHDR text_hdr;
+extern SCNHDR data_hdr;
+
+#endif /* not COFF_FORMAT */
+
+/* a.out header saved in core file. */
+
+extern AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+extern AOUTHDR exec_aouthdr;
+
+extern void validate_files ();
+
+core_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+ extern char registers[];
+
+ /* Discard all vestiges of any previous core file
+ and mark data and stack spaces as empty. */
+
+ if (corefile)
+ free (corefile);
+ corefile = 0;
+
+ if (corechan >= 0)
+ close (corechan);
+ corechan = -1;
+
+ data_start = 0;
+ data_end = 0;
+ stack_start = STACK_END_ADDR;
+ stack_end = STACK_END_ADDR;
+
+ /* Now, if a new core file was specified, open it and digest it. */
+
+ if (filename)
+ {
+ if (have_inferior_p ())
+ error ("To look at a core file, you must kill the inferior with \"kill\".");
+ corechan = open (filename, O_RDONLY, 0);
+ if (corechan < 0)
+ perror_with_name (filename);
+ /* 4.2-style (and perhaps also sysV-style) core dump file. */
+ {
+ struct user u;
+
+ int reg_offset;
+
+ val = myread (corechan, &u, sizeof u);
+ if (val < 0)
+ perror_with_name ("Not a core file: reading upage");
+ if (val != sizeof u)
+ error ("Not a core file: could only read %d bytes", val);
+ data_start = exec_data_start;
+
+ data_end = data_start + NBPG * u.u_dsize;
+ stack_start = stack_end - NBPG * u.u_ssize;
+ data_offset = NBPG * UPAGES;
+ stack_offset = NBPG * (UPAGES + u.u_dsize);
+
+ /* Some machines put an absolute address in here; Unisoft
+ seems to put the offset in the upage of the regs. Sigh. */
+ reg_offset = (int) u.u_ar0;
+ if (reg_offset > NBPG * UPAGES)
+ reg_offset -= KERNEL_U_ADDR;
+
+ /* I don't know where to find this info.
+ So, for now, mark it as not available. */
+ N_SET_MAGIC (core_aouthdr, 0);
+
+ /* Read the register values out of the core file and store
+ them where `read_register' will find them. */
+
+ {
+ register int regno;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ char buf[MAX_REGISTER_RAW_SIZE];
+
+ val = lseek (corechan, register_addr (regno, reg_offset), 0);
+ if (val < 0)
+ perror_with_name (reg_names[regno]);
+
+ val = myread (corechan, buf, sizeof buf);
+ if (val < 0)
+ perror_with_name (reg_names[regno]);
+ supply_register (regno, buf);
+ }
+ }
+ }
+ if (filename[0] == '/')
+ corefile = savestring (filename, strlen (filename));
+ else
+ {
+ corefile = concat (current_directory, "/", filename);
+ }
+
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+ select_frame (get_current_frame (), 0);
+ validate_files ();
+ }
+ else if (from_tty)
+ printf ("No core file now.\n");
+}
+
+exec_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+
+ /* Eliminate all traces of old exec file.
+ Mark text segment as empty. */
+
+ if (execfile)
+ free (execfile);
+ execfile = 0;
+ data_start = 0;
+ data_end -= exec_data_start;
+ text_start = 0;
+ text_end = 0;
+ exec_data_start = 0;
+ exec_data_end = 0;
+ if (execchan >= 0)
+ close (execchan);
+ execchan = -1;
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (filename)
+ {
+ execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
+ &execfile);
+ if (execchan < 0)
+ perror_with_name (filename);
+
+#ifdef COFF_FORMAT
+ {
+ int aout_hdrsize;
+ int num_sections;
+
+ if (read_file_hdr (execchan, &file_hdr) < 0)
+ error ("\"%s\": not in executable format.", execfile);
+
+ aout_hdrsize = file_hdr.f_opthdr;
+ num_sections = file_hdr.f_nscns;
+
+ if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
+ error ("\"%s\": can't read optional aouthdr", execfile);
+
+ if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
+ error ("\"%s\": can't read text section header", execfile);
+
+ if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
+ error ("\"%s\": can't read data section header", execfile);
+
+ text_start = exec_aouthdr.text_start;
+ text_end = text_start + exec_aouthdr.tsize;
+ text_offset = text_hdr.s_scnptr;
+ exec_data_start = exec_aouthdr.data_start;
+ exec_data_end = exec_data_start + exec_aouthdr.dsize;
+ exec_data_offset = data_hdr.s_scnptr;
+ data_start = exec_data_start;
+ data_end += exec_data_start;
+ exec_mtime = file_hdr.f_timdat;
+ }
+#else /* not COFF_FORMAT */
+ {
+ struct stat st_exec;
+
+#ifdef HEADER_SEEK_FD
+ HEADER_SEEK_FD (execchan);
+#endif
+
+ val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
+
+ if (val < 0)
+ perror_with_name (filename);
+
+ text_start = N_TXTADDR (exec_aouthdr);
+ exec_data_start = N_DATADDR (exec_aouthdr);
+
+ text_offset = N_TXTOFF (exec_aouthdr);
+ exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
+
+ text_end = text_start + exec_aouthdr.a_text;
+ exec_data_end = exec_data_start + exec_aouthdr.a_data;
+ data_start = exec_data_start;
+ data_end += exec_data_start;
+
+ fstat (execchan, &st_exec);
+ exec_mtime = st_exec.st_mtime;
+ }
+#endif /* not COFF_FORMAT */
+
+ validate_files ();
+ }
+ else if (from_tty)
+ printf ("No exec file now.\n");
+
+ /* Tell display code (if any) about the changed file name. */
+ if (exec_file_display_hook)
+ (*exec_file_display_hook) (filename);
+}
+@
+
+
+1.3
+log
+@Remove A/UX-specific changes for shipping to FSF.
+@
+text
+@d30 13
+d176 7
+a182 1
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+d193 6
+a198 1
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+@
+
+
+1.2
+log
+@A/UX and USG changes, and a little better error reporting.
+@
+text
+@a29 13
+#ifdef UNISOFT_ASSHOLES
+#define PMMU
+#define NEW_PMMU
+#define mc68881 /* Needed to get float in user.h!!! */
+#include <sys/seg.h> /* For user.h */
+#include <sys/mmu.h>
+#include <sys/time.h>
+/* Things Unisoft defined differently from every other Unix system */
+#define NBPG PAGESIZE
+#define UPAGES USIZE
+#define KERNEL_U_ADDR UDOT
+#endif
+
+d163 1
+a163 7
+#ifdef UNISOFT_ASSHOLES
+ /* You can't write the PC with ptrace 6, only with ptrace 11! */
+ if (regno == PC_REGNUM)
+ ptrace(11, inferior_pid, 16, read_register(regno));
+ else
+#endif
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+d174 1
+a174 6
+#ifdef UNISOFT_ASSHOLES
+ if (regno == PC_REGNUM)
+ ptrace(11, inferior_pid, 16, read_register(regno));
+ else
+#endif
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d30 13
+a46 1
+#include <sys/user.h>
+d58 2
+d67 5
+a71 1
+ machine-dependent file. */
+d76 11
+d88 1
+d176 7
+a182 1
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+d193 6
+a198 1
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+d201 1
+a201 1
+ sprintf (buf, "writing register number %d", regno);
+d446 3
+a448 1
+ perror_with_name (filename);
+d455 6
+a460 1
+ reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
+d478 1
+a478 1
+ perror_with_name (filename);
+d482 1
+a482 1
+ perror_with_name (filename);
+@
diff --git a/gdb/RCS/findvar.c,v b/gdb/RCS/findvar.c,v
new file mode 100644
index 0000000..9095f2b
--- /dev/null
+++ b/gdb/RCS/findvar.c,v
@@ -0,0 +1,584 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.04.26.01.06.46; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.04.25.15.38.48; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@use XXX_BIG_ENDIAN macros rather than runtime tests.
+@
+text
+@/* Find a variable's value in memory, for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "value.h"
+
+CORE_ADDR read_register ();
+
+/* Return the address in which frame FRAME's value of register REGNUM
+ has been saved in memory. Or return zero if it has not been saved.
+ If REGNUM specifies the SP, the value we return is actually
+ the SP value, not an address where it was saved. */
+
+CORE_ADDR
+find_saved_register (frame, regnum)
+ FRAME frame;
+ int regnum;
+{
+ struct frame_info *fi;
+ struct frame_saved_regs saved_regs;
+
+ register FRAME frame1 = 0;
+ register CORE_ADDR addr = 0;
+
+#ifdef HAVE_REGISTER_WINDOWS
+ /* We assume that a register in a register window will only be saved
+ in one place (since the name changes and dissapears as you go
+ towards inner frames), so we only call get_frame_saved_regs on
+ the current frame. This is directly in contradiction to the
+ usage below, which assumes that registers used in a frame must be
+ saved in a lower (more interior) frame. This change is a result
+ of working on a register window machine; get_frame_saved_regs
+ always returns the registers saved within a frame, within the
+ context (register namespace) of that frame. */
+
+ if (REGISTER_IN_WINDOW_P(regnum))
+ {
+ fi = get_frame_info (frame);
+ get_frame_saved_regs (fi, &saved_regs);
+ return (saved_regs.regs[regnum] ?
+ saved_regs.regs[regnum] : 0);
+ }
+#endif /* HAVE_REGISTER_WINDOWS */
+
+ /* Note that this next routine assumes that registers used in
+ frame x will be saved only in the frame that x calls and
+ frames interior to it. This is not true on the sparc, but the
+ above macro takes care of it, so we should be all right. */
+ while (1)
+ {
+ QUIT;
+ frame1 = get_prev_frame (frame1);
+ if (frame1 == 0 || frame1 == frame)
+ break;
+ fi = get_frame_info (frame1);
+ get_frame_saved_regs (fi, &saved_regs);
+ if (saved_regs.regs[regnum])
+ addr = saved_regs.regs[regnum];
+ }
+
+ return addr;
+}
+
+/* Copy the bytes of register REGNUM, relative to the current stack frame,
+ into our memory at MYADDR.
+ The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). */
+
+void
+read_relative_register_raw_bytes (regnum, myaddr)
+ int regnum;
+ char *myaddr;
+{
+ register CORE_ADDR addr;
+
+ if (regnum == FP_REGNUM)
+ {
+ bcopy (&FRAME_FP(selected_frame), myaddr, sizeof (CORE_ADDR));
+ return;
+ }
+
+ addr = find_saved_register (selected_frame, regnum);
+
+ if (addr)
+ {
+ if (regnum == SP_REGNUM)
+ {
+ CORE_ADDR buffer = addr;
+ bcopy (&buffer, myaddr, sizeof (CORE_ADDR));
+ }
+ else
+ read_memory (addr, myaddr, REGISTER_RAW_SIZE (regnum));
+ return;
+ }
+ read_register_bytes (REGISTER_BYTE (regnum),
+ myaddr, REGISTER_RAW_SIZE (regnum));
+}
+
+/* Return a `value' with the contents of register REGNUM
+ in its virtual format, with the type specified by
+ REGISTER_VIRTUAL_TYPE. */
+
+value
+value_of_register (regnum)
+ int regnum;
+{
+ register CORE_ADDR addr;
+ register value val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+
+ if (! (have_inferior_p () || have_core_file_p ()))
+ error ("Can't get value of register without inferior or core file");
+
+ addr = find_saved_register (selected_frame, regnum);
+ if (addr)
+ {
+ if (regnum == SP_REGNUM)
+ return value_from_long (builtin_type_int, (LONGEST) addr);
+ read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+ }
+ else
+ read_register_bytes (REGISTER_BYTE (regnum), raw_buffer,
+ REGISTER_RAW_SIZE (regnum));
+
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
+ val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+ bcopy (virtual_buffer, VALUE_CONTENTS (val), REGISTER_VIRTUAL_SIZE (regnum));
+ VALUE_LVAL (val) = addr ? lval_memory : lval_register;
+ VALUE_ADDRESS (val) = addr ? addr : REGISTER_BYTE (regnum);
+ VALUE_REGNO (val) = regnum;
+ return val;
+}
+
+/* Low level examining and depositing of registers.
+
+ Note that you must call `fetch_registers' once
+ before examining or depositing any registers. */
+
+char registers[REGISTER_BYTES];
+
+/* Copy LEN bytes of consecutive data from registers
+ starting with the REGBYTE'th byte of register data
+ into memory at MYADDR. */
+
+void
+read_register_bytes (regbyte, myaddr, len)
+ int regbyte;
+ char *myaddr;
+ int len;
+{
+ bcopy (&registers[regbyte], myaddr, len);
+}
+
+/* Copy LEN bytes of consecutive data from memory at MYADDR
+ into registers starting with the REGBYTE'th byte of register data. */
+
+void
+write_register_bytes (regbyte, myaddr, len)
+ int regbyte;
+ char *myaddr;
+ int len;
+{
+ bcopy (myaddr, &registers[regbyte], len);
+ if (have_inferior_p ())
+ store_inferior_registers (-1);
+}
+
+/* Return the contents of register REGNO,
+ regarding it as an integer. */
+
+CORE_ADDR
+read_register (regno)
+ int regno;
+{
+ /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
+ return *(int *) &registers[REGISTER_BYTE (regno)];
+}
+
+/* Store VALUE in the register number REGNO, regarded as an integer. */
+
+void
+write_register (regno, val)
+ int regno, val;
+{
+ /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
+#if defined(sun4)
+ /* This is a no-op on a Sun 4. */
+ if (regno == 0)
+ return;
+#endif
+
+ *(int *) &registers[REGISTER_BYTE (regno)] = val;
+
+ if (have_inferior_p ())
+ store_inferior_registers (regno);
+}
+
+/* Record that register REGNO contains VAL.
+ This is used when the value is obtained from the inferior or core dump,
+ so there is no need to store the value there. */
+
+void
+supply_register (regno, val)
+ int regno;
+ char *val;
+{
+ bcopy (val, &registers[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno));
+}
+
+/* Given a struct symbol for a variable,
+ and a stack frame address, read the value of the variable
+ and return a (pointer to a) struct value containing the value. */
+
+value
+read_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ register value v;
+
+ struct frame_info *fi;
+
+ struct type *type = SYMBOL_TYPE (var);
+ register CORE_ADDR addr = 0;
+ int val = SYMBOL_VALUE (var);
+ register int len;
+
+ v = allocate_value (type);
+ VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */
+ len = TYPE_LENGTH (type);
+
+ if (frame == 0) frame = selected_frame;
+
+ switch (SYMBOL_CLASS (var))
+ {
+ case LOC_CONST:
+ case LOC_LABEL:
+ bcopy (&val, VALUE_CONTENTS (v), len);
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ case LOC_CONST_BYTES:
+ bcopy (val, VALUE_CONTENTS (v), len);
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ case LOC_STATIC:
+ addr = val;
+ break;
+
+ case LOC_ARG:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_ARGS_ADDRESS (fi);
+ break;
+
+ case LOC_LOCAL:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_LOCALS_ADDRESS (fi);
+ break;
+
+ case LOC_TYPEDEF:
+ error ("Cannot look up value of a typedef");
+
+ case LOC_BLOCK:
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+ return v;
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ v = value_from_register (type, val, frame);
+ return v;
+ }
+
+ read_memory (addr, VALUE_CONTENTS (v), len);
+ VALUE_ADDRESS (v) = addr;
+ return v;
+}
+
+/* Return a value of type TYPE, stored in register REGNUM, in frame
+ FRAME. */
+
+value
+value_from_register (type, regnum, frame)
+ struct type *type;
+ int regnum;
+ FRAME frame;
+{
+ char raw_buffer [MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ CORE_ADDR addr;
+ value v = allocate_value (type);
+ int len = TYPE_LENGTH (type);
+ char *value_bytes = 0;
+ int value_bytes_copied = 0;
+ int num_storage_locs;
+
+ VALUE_REGNO (v) = regnum;
+
+ num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ?
+ ((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 :
+ 1);
+
+ if (num_storage_locs > 1)
+ {
+ /* Value spread across multiple storage locations. */
+
+ int local_regnum;
+ int mem_stor = 0, reg_stor = 0;
+ int mem_tracking = 1;
+ CORE_ADDR last_addr = 0;
+
+ value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE);
+
+ /* Copy all of the data out, whereever it may be. */
+
+ for (local_regnum = regnum;
+ value_bytes_copied < len;
+ (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
+ ++local_regnum))
+ {
+ int register_index = local_regnum - regnum;
+ addr = find_saved_register (frame, local_regnum);
+ if (addr == 0)
+ {
+ read_register_bytes (REGISTER_BYTE (local_regnum),
+ value_bytes + value_bytes_copied,
+ REGISTER_RAW_SIZE (local_regnum));
+ reg_stor++;
+ }
+ else
+ {
+ read_memory (addr, value_bytes + value_bytes_copied,
+ REGISTER_RAW_SIZE (local_regnum));
+ mem_stor++;
+ mem_tracking =
+ (mem_tracking
+ && (regnum == local_regnum
+ || addr == last_addr));
+ }
+ last_addr = addr;
+ }
+
+ if ((reg_stor && mem_stor)
+ || (mem_stor && !mem_tracking))
+ /* Mixed storage; all of the hassle we just went through was
+ for some good purpose. */
+ {
+ VALUE_LVAL (v) = lval_reg_frame_relative;
+ VALUE_FRAME (v) = FRAME_FP (frame);
+ VALUE_FRAME_REGNUM (v) = regnum;
+ }
+ else if (mem_stor)
+ {
+ VALUE_LVAL (v) = lval_memory;
+ VALUE_ADDRESS (v) = find_saved_register (frame, regnum);
+ }
+ else if (reg_stor)
+ {
+ VALUE_LVAL (v) = lval_register;
+ VALUE_ADDRESS (v) = REGISTER_BYTE (regnum);
+ }
+ else
+ fatal ("value_from_register: Value not stored anywhere!");
+
+ /* Any structure stored in more than one register will always be
+ an inegral number of registers. Otherwise, you'd need to do
+ some fiddling with the last register copied here for little
+ endian machines. */
+
+ /* Copy into the contents section of the value. */
+ bcopy (value_bytes, VALUE_CONTENTS (v), len);
+
+ return v;
+ }
+
+ /* Data is completely contained within a single register. Locate the
+ register's contents in a real register or in core;
+ read the data in raw format. */
+
+ addr = find_saved_register (frame, regnum);
+ if (addr == 0)
+ {
+ /* Value is really in a register. */
+
+ VALUE_LVAL (v) = lval_register;
+ VALUE_ADDRESS (v) = REGISTER_BYTE (regnum);
+
+ read_register_bytes (REGISTER_BYTE (regnum),
+ raw_buffer, REGISTER_RAW_SIZE (regnum));
+ }
+ else
+ {
+ /* Value was in a register that has been saved in memory. */
+
+ read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+ VALUE_LVAL (v) = lval_memory;
+ VALUE_ADDRESS (v) = addr;
+ }
+
+ /* Convert the raw contents to virtual contents.
+ (Just copy them if the formats are the same.) */
+
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
+
+ if (REGISTER_CONVERTIBLE (regnum))
+ {
+ /* When the raw and virtual formats differ, the virtual format
+ corresponds to a specific data type. If we want that type,
+ copy the data into the value.
+ Otherwise, do a type-conversion. */
+
+ if (type != REGISTER_VIRTUAL_TYPE (regnum))
+ {
+ /* eg a variable of type `float' in a 68881 register
+ with raw type `extended' and virtual type `double'.
+ Fetch it as a `double' and then convert to `float'. */
+ v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+ bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
+ v = value_cast (type, v);
+ }
+ else
+ bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
+ }
+ else
+ {
+ /* Raw and virtual formats are the same for this register. */
+
+#ifdef BYTES_BIG_ENDIAN
+ if (len < REGISTER_RAW_SIZE (regnum))
+ {
+ /* Big-endian, and we want less than full size. */
+ VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len;
+ }
+#endif
+
+ bcopy (virtual_buffer + VALUE_OFFSET (v),
+ VALUE_CONTENTS (v), len);
+ }
+
+ return v;
+}
+
+/* Given a struct symbol for a variable,
+ and a stack frame address,
+ return a (pointer to a) struct value containing the variable's address. */
+
+value
+locate_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ register CORE_ADDR addr = 0;
+ int val = SYMBOL_VALUE (var);
+ struct frame_info *fi;
+ struct type *type = SYMBOL_TYPE (var);
+
+ if (frame == 0) frame = selected_frame;
+
+ switch (SYMBOL_CLASS (var))
+ {
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ error ("Address requested for identifier \"%s\" which is a constant.",
+ SYMBOL_NAME (var));
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ addr = find_saved_register (frame, val);
+ if (addr != 0)
+ {
+ int len = TYPE_LENGTH (type);
+#ifdef BYTES_BIG_ENDIAN
+ if (len < REGISTER_RAW_SIZE (val))
+ /* Big-endian, and we want less than full size. */
+ addr += REGISTER_RAW_SIZE (val) - len;
+#endif
+ break;
+ }
+ error ("Address requested for identifier \"%s\" which is in a register.",
+ SYMBOL_NAME (var));
+
+ case LOC_STATIC:
+ case LOC_LABEL:
+ addr = val;
+ break;
+
+ case LOC_ARG:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_ARGS_ADDRESS (fi);
+ break;
+
+ case LOC_LOCAL:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_LOCALS_ADDRESS (fi);
+ break;
+
+ case LOC_TYPEDEF:
+ error ("Address requested for identifier \"%s\" which is a typedef.",
+ SYMBOL_NAME (var));
+
+ case LOC_BLOCK:
+ addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+ break;
+ }
+
+ return value_cast (lookup_pointer_type (type),
+ value_from_long (builtin_type_long, (LONGEST) addr));
+}
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d448 2
+a449 5
+ union { int i; char c; } test;
+ /* If we want less than the full size, we need to
+ test for a big-endian or little-endian machine. */
+ test.i = 1;
+ if (test.c != 1 && len < REGISTER_RAW_SIZE (regnum))
+d454 2
+a455 1
+
+a490 1
+ union { int i; char c; } test;
+d492 2
+a493 4
+ /* If var is less than the full size of register, we need to
+ test for a big-endian or little-endian machine. */
+ test.i = 1;
+ if (test.c != 1 && len < REGISTER_RAW_SIZE (val))
+d496 1
+@
diff --git a/gdb/RCS/gdb.texinfo,v b/gdb/RCS/gdb.texinfo,v
new file mode 100644
index 0000000..ff38f18
--- /dev/null
+++ b/gdb/RCS/gdb.texinfo,v
@@ -0,0 +1,3009 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @@;
+
+
+1.2
+date 89.02.10.01.41.38; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.10.00.33.03; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Improve doc in various ways, mostly xref{Expressions} so you can
+find out what an expression is (I had trouble finding it, since
+it's in a nested menu somewhere.)
+@
+text
+@\input texinfo
+@@setfilename ../info/gdb
+@@settitle GDB, The GNU Debugger
+@@ifinfo
+This file documents the GNU debugger GDB.
+
+Copyright (C) 1988 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Distribution'' and ``GDB General Public License'' are
+included exactly as in the original, and provided that the entire resulting
+derived work is distributed under the terms of a permission notice
+identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the sections entitled ``Distribution'' and ``GDB General Public
+License'' may be included in a translation approved by the author instead
+of in the original English.
+@@end ifinfo
+
+@@setchapternewpage odd
+@@settitle GDB Manual
+@@titlepage
+@@sp 6
+@@center @@titlefont{GDB Manual}
+@@sp 1
+@@center The GNU Source-Level Debugger
+@@sp 4
+@@center Third Edition, GDB version 3.1
+@@sp 1
+@@center January 1989
+@@sp 5
+@@center Richard M. Stallman
+@@page
+@@vskip 0pt plus 1filll
+Copyright @@copyright{} 1988, 1989 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Distribution'' and ``GDB General Public License'' are
+included exactly as in the original, and provided that the entire resulting
+derived work is distributed under the terms of a permission notice
+identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the sections entitled ``Distribution'' and ``GDB General Public
+License'' may be included in a translation approved by the author instead
+of in the original English.
+@@end titlepage
+@@page
+
+@@node Top, Commands,, (DIR)
+@@unnumbered Summary of GDB
+
+The purpose of a debugger such as GDB is to allow you to execute another
+program while examining what is going on inside it. We call the other
+program ``your program'' or ``the program being debugged''.
+
+GDB can do four kinds of things (plus other things in support of these):
+
+@@enumerate
+@@item
+Start the program, specifying anything that might affect its behavior.
+
+@@item
+Make the program stop on specified conditions.
+
+@@item
+Examine what has happened, when the program has stopped, so that you
+can see bugs happen.
+
+@@item
+Change things in the program, so you can correct the effects of one bug
+and go on to learn about another without having to recompile first.
+@@end enumerate
+
+GDB can be used to debug programs written in C and C++. Pascal support
+is being implemented, and Fortran support will be added when a GNU
+Fortran compiler is written.
+
+@@menu
+* License:: The GDB General Public License gives you permission
+ to redistribute GDB on certain terms; and also
+ explains that there is no warranty.
+* Input:: GDB command syntax and input conventions.
+* Files:: Specifying files for GDB to operate on.
+* Options:: GDB arguments and options.
+* Compilation::Compiling your program so you can debug it.
+* Running:: Running your program under GDB.
+* Stopping:: Making your program stop. Why it may stop. What to do then.
+* Stack:: Examining your program's stack.
+* Source:: Examining your program's source files.
+* Data:: Examining data in your program.
+* Symbols:: Examining the debugger's symbol table.
+* Altering:: Altering things in your program.
+* Sequences:: Canned command sequences for repeated use.
+* Emacs:: Using GDB through GNU Emacs.
+* Remote:: Remote kernel debugging across a serial line.
+* Commands:: Index of GDB commands.
+* Concepts:: Index of GDB concepts.
+@@end menu
+
+@@node License, Input, Top, Top
+@@unnumbered GDB General Public License
+@@center (Clarified 11 Feb 1988)
+
+ The license agreements of most software companies keep you at the mercy
+of those companies. By contrast, our general public license is intended to
+give everyone the right to share GDB. To make sure that you get the rights
+we want you to have, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. Hence this
+license agreement.
+
+ Specifically, we want to make sure that you have the right to give away
+copies of GDB, that you receive source code or else can get it if you want
+it, that you can change GDB or use pieces of it in new free programs, and
+that you know you can do these things.
+
+ To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights. For example, if you distribute copies
+of GDB, you must give the recipients all the rights that you have. You
+must make sure that they, too, receive or can get the source code. And you
+must tell them their rights.
+
+ Also, for our own protection, we must make certain that everyone finds
+out that there is no warranty for GDB. If GDB is modified by someone else
+and passed on, we want its recipients to know that what they have is not
+what we distributed, so that any problems introduced by others will not
+reflect on our reputation.
+
+ Therefore we (Richard Stallman and the Free Software Foundation,
+Inc.) make the following terms which say what you must do to be
+allowed to distribute or change GDB.
+
+@@unnumberedsec Copying Policies
+
+@@enumerate
+@@item
+You may copy and distribute verbatim copies of GDB source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each file a valid copyright notice ``Copyright
+@@copyright{} 1988 Free Software Foundation, Inc.'' (or with whatever year
+is appropriate); keep intact the notices on all files that
+refer to this License Agreement and to the absence of any warranty; and
+give any other recipients of the GDB program a copy of this License
+Agreement along with the program. You may charge a distribution fee
+for the physical act of transferring a copy.
+
+@@item
+You may modify your copy or copies of GDB source code or any portion
+of it, and copy and distribute such modifications under the terms of
+Paragraph 1 above, provided that you also do the following:
+
+@@itemize @@bullet
+@@item
+cause the modified files to carry prominent notices stating
+that you changed the files and the date of any change; and
+
+@@item
+cause the whole of any work that you distribute or publish, that
+in whole or in part contains or is a derivative of GDB or any
+part thereof, to be licensed at no charge to all third parties on
+terms identical to those contained in this License Agreement
+(except that you may choose to grant more extensive warranty
+protection to some or all third parties, at your option).
+
+@@item
+if the modified program serves as a debugger, cause it, when
+started running in the simplest and usual way, to print an
+announcement including a valid copyright notice ``Copyright
+@@copyright{} 1988 Free Software Foundation, Inc.'' (or with the
+year that is appropriate), saying that there is no warranty (or
+else, saying that you provide a warranty) and that users may
+redistribute the program under these conditions, and telling the
+user how to view a copy of this License Agreement.
+
+@@item
+You may charge a distribution fee for the physical act of
+transferring a copy, and you may at your option offer warranty
+protection in exchange for a fee.
+@@end itemize
+
+Mere aggregation of another unrelated program with this program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other program under the scope of these terms.
+
+@@item
+You may copy and distribute GDB (or a portion or derivative of it,
+under Paragraph 2) in object code or executable form under the terms
+of Paragraphs 1 and 2 above provided that you also do one of the
+following:
+
+@@itemize @@bullet
+@@item
+accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of
+Paragraphs 1 and 2 above; or,
+
+@@item
+accompany it with a written offer, valid for at least three
+years, to give any third party free (except for a nominal
+shipping charge) a complete machine-readable copy of the
+corresponding source code, to be distributed under the terms of
+Paragraphs 1 and 2 above; or,
+
+@@item
+accompany it with the information you received as to where the
+corresponding source code may be obtained. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form alone.)
+@@end itemize
+
+For an executable file, complete source code means all the source code
+for all modules it contains; but, as a special exception, it need not
+include source code for modules which are standard libraries that
+accompany the operating system on which the executable file runs.
+
+@@item
+You may not copy, sublicense, distribute or transfer GDB except as
+expressly provided under this License Agreement. Any attempt
+otherwise to copy, sublicense, distribute or transfer GDB is void and
+your rights to use GDB under this License agreement shall be
+automatically terminated. However, parties who have received computer
+software programs from you with this License Agreement will not have
+their licenses terminated so long as such parties remain in full
+compliance.
+
+@@item
+If you wish to incorporate parts of GDB into other free programs whose
+distribution conditions are different, write to the Free Software
+Foundation. We have not yet worked out a simple rule that can be
+stated here, but we will often permit this. We will be guided by the
+two goals of preserving the free status of all derivatives our free
+software and of promoting the sharing and reuse of software.
+@@end enumerate
+
+@@iftex
+@@vfil
+@@eject
+@@end iftex
+@@unnumberedsec NO WARRANTY
+
+ BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
+WHEN OTHERWISE STATED IN WRITING, THE FREE SOFTWARE FOUNDATION, INC,
+RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB ``AS IS''
+WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
+AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE GDB
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
+SERVICING, REPAIR OR CORRECTION.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL FREE SOFTWARE
+FOUNDATION, INC., RICHARD M. STALLMAN, AND/OR ANY OTHER PARTY WHO MAY
+MODIFY AND REDISTRIBUTE GDB AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
+BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
+FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
+FREE SOFTWARE FOUNDATION, INC.) THE PROGRAM, EVEN IF YOU HAVE BEEN
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY
+OTHER PARTY.
+
+@@node Input, Files, License, Top
+@@chapter GDB Input Conventions
+
+GDB is invoked with the shell command @@samp{gdb}. Once started, it reads
+commands from the terminal until you tell it to exit.
+
+A GDB command is a single line of input. There is no limit on how long
+it can be. It starts with a command name, which is followed by arguments
+whose meaning depends on the command name. Some command names do not
+allow arguments.
+
+GDB command names may always be abbreviated if the abbreviation is
+unambiguous. Sometimes even ambiguous abbreviations are allowed; for
+example, @@samp{s} is specially defined as equivalent to @@samp{step}
+even though there are other commands whose names start with @@samp{s}.
+Possible command abbreviations are often stated in the documentation
+of the individual commands.
+
+A blank line as input to GDB means to repeat the previous command verbatim.
+Certain commands do not allow themselves to be repeated this way; these are
+commands for which unintentional repetition might cause trouble and which
+you are unlikely to want to repeat. Certain others (@@samp{list} and
+@@samp{x}) act differently when repeated because that is more useful.
+
+A line of input starting with @@samp{#} is a comment; it does nothing.
+This is useful mainly in command files (@@xref{Command Files}).
+
+Occasionally it is useful to execute a shell command from within gdb.
+This can be done with the @@samp{shell} command, or the shell escape
+character @@samp{!}.
+
+@@table @@code
+@@item shell @@var{shell command string}
+@@kindex shell
+@@item !@@var{shell command string}
+@@kindex !
+@@cindex shell escape
+Directs GDB to invoke an inferior shell to execute @@samp{shell command string}.
+The environmental variable @@samp{SHELL} is used if it exists, otherwise gdb
+uses @@samp{/bin/sh}.
+@@end table
+
+GDB @@dfn{prompts} for commands with a string that is normally @@samp{(gdb)}.
+When debugging GDB with GDB, it is useful to change the prompt in one of
+the GDBs so that you can distinguish them. This can be done with the
+@@samp{set prompt} command.
+
+@@table @@code
+@@item set prompt @@var{newprompt}
+@@kindex set prompt
+Directs GDB to use @@var{newprompt} as its prompt string henceforth.
+@@end table
+
+@@cindex exiting GDB
+@@kindex quit
+To exit GDB, use the @@samp{quit} command (abbreviated @@samp{q}).
+@@kbd{Ctrl-c} will not exit from GDB, but rather will terminate the action
+of any GDB command that is in progress and return to GDB command level.
+It is safe to type @@kbd{Ctrl-c} at any time because GDB does not allow
+it to take effect until a time when it is safe.
+
+@@node Files, Options, Input, Top
+@@chapter Specifying GDB's Files
+
+@@cindex core dump file
+@@cindex executable file
+@@cindex symbol table
+GDB needs to know the filename of the program to be debugged. To debug a
+core dump of a previous run, GDB must be told the filename of the core
+dump.
+
+@@menu
+* Arguments: File Arguments. Specifying files with arguments
+ (when you start GDB).
+* Commands: File Commands. Specifying files with GDB commands.
+@@end menu
+
+@@node File Arguments, File Commands, Files, Files
+@@section Specifying Files with Arguments
+
+The usual way to specify the executable and core dump file names is with
+two command arguments given when you start GDB. The first argument is used
+as the file for execution and symbols, and the second argument (if any) is
+used as the core dump file name. Thus,
+
+@@example
+gdb progm core
+@@end example
+
+@@noindent
+specifies @@file{progm} as the executable program and @@file{core} as a core
+dump file to examine. (You do not need to have a core dump file if what
+you plan to do is debug the program interactively.)
+
+@@xref{Options}, for full information on command options and arguments for
+GDB.
+
+@@node File Commands,, File Arguments, Files
+@@section Specifying Files with Commands
+
+Usually you specify the files for GDB to work with by giving arguments when
+you invoke GDB. But occasionally it is necessary to change to a different
+file during a GDB session. Or you may run GDB and forget to specify the
+files you want to use. In these situations the GDB commands to specify new
+files are useful.
+
+@@table @@code
+@@item exec-file @@var{filename}
+@@kindex exec-file
+Specify that the program to be run is found in @@var{filename}. If you
+do not specify a directory and the file is not found in GDB's working
+directory, GDB will use the environment variable @@samp{PATH} as a list
+of directories to search, just as the shell does when looking for a
+program to run.
+
+@@item symbol-file @@var{filename}
+@@kindex symbol-file
+Read symbol table information from file @@var{filename}. @@samp{PATH}
+is searched when necessary. Most of the time you will use both the
+@@samp{exec-file} and @@samp{symbol-file} commands on the same file.
+
+@@samp{symbol-file} with no argument clears out GDB's symbol table.
+
+@@item core-file @@var{filename}
+@@kindex core-file
+Specify the whereabouts of a core dump file to be used as the
+``contents of memory''. Note that the core dump contains only the
+writable parts of memory; the read-only parts must come from the
+executable file.
+
+@@samp{core-file} with no argument specifies that no core file is
+to be used.
+
+@@item add-file @@var{filename} @@var{address}
+@@kindex add-file
+The @@samp{add-file} command takes two arguments, a file name, and the
+address at which that file has been (or should be) dynamically loaded.
+GDB will then treat that file as though it had always been dynamically
+linked, and provide the user with all the normal GDB features, including
+symbolic debugging.
+
+With the @@samp{add-file} command, it is possible to debug code which was
+not present in the initial load image of the program under test.
+Suppose you have a program which can, while running, dynamically link a
+program fragment into its address space. One program which does this is
+KCL, a free common lisp implementation. The fragment will be loaded
+into the main program's address space at some address, and the main
+program can then call functions within the fragment by calculating (or
+otherwise obtaining) their addresses.
+
+@@item kill
+@@kindex kill
+Cancel running the program under GDB. This could be used if you wish
+to debug a core dump instead. GDB ignores any core dump file if it is
+actually running the program, so the @@samp{kill} command is the only
+sure way to go back to using the core dump file.
+
+@@item info files
+@@kindex info files
+Print the names of the executable and core dump files currently in
+use by GDB, and the file from which symbols were loaded.
+@@end table
+
+While all three file-specifying commands allow both absolute and relative
+file names as arguments, GDB always converts the file name to an absolute
+one and remembers it that way.
+
+The @@samp{symbol-file} command causes GDB to forget the contents of its
+convenience variables, the value history, and all breakpoints and
+auto-display expressions. This is because they may contain pointers to the
+internal data recording symbols and data types, which are part of the old
+symbol table data being discarded inside GDB.
+
+@@node Options, Compilation, Files, Top
+@@chapter Options and Arguments for GDB
+
+When you invoke GDB, you can pass commands telling it what files to
+operate on and what other things to do.
+
+@@menu
+* Mode Options:: Options controlling modes of operation.
+* File Options:: Options to specify files (executable, coredump, commands)
+* Other Arguments:: Any other arguments without options
+ also specify files.
+@@end menu
+
+@@node Mode Options, File Options, Options, Options
+@@section Mode Options
+
+@@table @@samp
+@@item -nx
+Do not execute commands from the init files @@file{.gdbinit}.
+Normally, the commands in these files are executed after all the
+command options and arguments have been processed. @@xref{Command
+Files}.
+
+@@item -q
+``Quiet''. Do not print the usual introductory messages.
+
+@@item -batch
+Run in batch mode. Exit with code 1 after processing all the command
+files specified with @@samp{-x} (and @@file{.gdbinit}, if not
+inhibited). Exit also if, due to an error, GDB would otherwise
+attempt to read a command from the terminal.
+
+@@item -fullname
+This option is used when Emacs runs GDB as a subprocess. It tells GDB
+to output the full file name and line number in a standard,
+recognizable fashion each time a stack frame is displayed (which
+includes each time the program stops). This recognizable format looks
+like two @@samp{\032} characters, followed by the filename, line number
+and character position separated by colons, and a newline. The
+Emacs-to-GDB interface program uses the two @@samp{\032} characters as
+a signal to display the source code for the frame.
+@@end table
+
+@@node File Options, Other Arguments, Mode Options, Options
+@@section File-specifying Options
+
+All the options and command line arguments given are processed
+in sequential order. The order makes a difference when the
+@@samp{-x} command is used.
+
+@@table @@samp
+@@item -s @@var{file}
+Read symbol table from file @@var{file}.
+
+@@item -e @@var{file}
+Use file @@var{file} as the executable file to execute when
+appropriate, and for examining pure data in conjunction with a core
+dump.
+
+@@item -se @@var{file}
+Read symbol table from file @@var{file} and use it as the executable
+file.
+
+@@item -c @@var{file}
+Use file @@var{file} as a core dump to examine.
+
+@@item -x @@var{file}
+Execute GDB commands from file @@var{file}.
+
+@@item -d @@var{directory}
+Add @@var{directory} to the path to search for source files.
+@@end table
+
+@@node Other Arguments,, File Options, Options
+@@section Other Arguments
+
+If there are arguments to GDB that are not options or associated with
+options, the first one specifies the symbol table and executable file name
+(as if it were preceded by @@samp{-se}) and the second one specifies a core
+dump file name (as if it were preceded by @@samp{-c}).
+
+@@node Compilation, Running, Options, Top
+@@chapter Compiling Your Program for Debugging
+
+In order to debug a program effectively, you need to ask for debugging
+information when you compile it. This information in the object file
+describes the data type of each variable or function and the correspondence
+between source line numbers and addresses in the executable code.
+
+To request debugging information, specify the @@samp{-g} option when you run
+the compiler.
+
+The Unix C compiler is unable to handle the @@samp{-g} and @@samp{-O} options
+together. This means that you cannot ask for optimization if you ask for
+debugger information.
+
+The GNU C compiler supports @@samp{-g} with or without @@samp{-O}, making it
+possible to debug optimized code. We recommend that you @@emph{always} use
+@@samp{-g} whenever you compile a program. You may think the program is
+correct, but there's no sense in pushing your luck.
+
+If you are using the GNU C compiler, the GNU assembler and the GNU linker,
+you can choose between two formats of debugging information: the standard
+Unix format, which is what you get with @@samp{-g}, and GDB's own format,
+which you request by using @@samp{-gg} instead of @@samp{-g}. This stores
+debugging information in the executable file in a format much like that
+which is used inside GDB. This has these advantages and disadvantages:
+
+@@itemize @@bullet
+@@item
+GDB can read @@samp{-gg} format more than twice as fast as Unix
+@@samp{-g} format.
+
+@@item
+The @@samp{-gg} format uses much more disk space than Unix format.
+
+@@item
+The Unix debuggers can understand only Unix format, so you cannot use
+Unix source-level debuggers if you compile with @@samp{-gg}. (The
+@@code{adb} debugger works with either format; it does not use this
+information in any case.)
+@@end itemize
+
+@@node Running, Stopping, Compilation, Top
+@@chapter Running Your Program Under GDB
+
+@@cindex running
+@@kindex run
+To start your program under GDB, use the @@samp{run} command. The program
+must already have been specified using the @@samp{exec-file} command or with
+an argument to GDB (@@pxref{Files}); what @@samp{run} does is create an
+inferior process, load the program into it, and set it in motion.
+
+The execution of a program is affected by certain information it receives
+from its superior. GDB provides ways to specify them, which you must do
+@@i{before} starting the program. (You can change them after starting the
+program, but such changes do not affect the program unless you start it
+over again.)
+
+@@table @@asis
+@@item The @@i{arguments.}
+You specify the arguments to give the program as the arguments of the
+@@samp{run} command.
+
+@@item The @@i{environment.}
+The program normally inherits its environment from GDB, but you can
+use the GDB commands @@samp{set environment} and
+@@samp{unset environment} to change parts of the environment that will
+be given to the program.@@refill
+
+@@item The @@i{working directory.}
+The program inherits its working directory from GDB. You can set GDB's
+working directory with the @@samp{cd} command in GDB.
+@@end table
+
+After the @@samp{run} command, the debugger does nothing but wait for your
+program to stop. @@xref{Stopping}.
+
+Note that once your program has been started by the @@samp{run} command,
+you may evaluate expressions that involve calls to functions in the
+inferior. @@xref{Expressions}. If you wish to evaluate a function
+simply for it's side affects, you may use the @@samp{set} command.
+@@xref{Assignment}.
+
+@@menu
+* Arguments:: Specifying the arguments for your program.
+* Environment:: Specifying the environment for your program.
+* Working Directory:: Specifying the working directory for giving
+ to your program when it is run.
+* Input/Output:: Specifying the program's standard input and output.
+* Attach:: Debugging a process started outside GDB.
+@@end menu
+
+@@node Arguments, Environment, Running, Running
+@@section Your Program's Arguments
+
+@@cindex arguments (to your program)
+You specify the arguments to give the program as the arguments of the
+@@samp{run} command. They are passed to a shell, which expands wildcard
+characters and performs redirection of I/O, and thence to the program.
+
+@@samp{run} with no arguments uses the same arguments used by the previous
+@@samp{run}.
+
+@@kindex set args
+The command @@samp{set args} can be used to specify the arguments to be used
+the next time the program is run. If @@samp{set args} has no arguments, it
+means to use no arguments the next time the program is run. If you have
+run your program with arguments and want to run it again with no arguments,
+this is the only way to do so.
+
+@@node Environment, Working Directory, Arguments, Running
+@@section Your Program's Environment
+
+@@cindex environment (of your program)
+The @@dfn{environment} consists of a set of @@dfn{environment variables} and
+their values. Environment variables conventionally record such things as
+your user name, your home directory, your terminal type, and your search
+path for programs to run. Usually you set up environment variables with
+the shell and they are inherited by all the other programs you run. When
+debugging, it can be useful to try running the program with different
+environments without having to start the debugger over again.
+
+@@table @@code
+@@item info environment @@var{varname}
+@@kindex info environment
+Print the value of environment variable @@var{varname} to be given to
+your program when it is started. This command can be abbreviated
+@@samp{i env @@var{varname}}.
+
+@@item info environment
+Print the names and values of all environment variables to be given to
+your program when it is started. This command can be abbreviated
+@@samp{i env}.
+
+@@item set environment @@var{varname} @@var{value}
+@@item set environment @@var{varname} = @@var{value}
+@@kindex set environment
+Sets environment variable @@var{varname} to @@var{value}, for your program
+only, not for GDB itself. @@var{value} may be any string; the values of
+environment variables are just strings, and any interpretation is
+supplied by your program itself. The @@var{value} parameter is optional;
+if it is eliminated, the variable is set to a null value. This command
+can be abbreviated as short as @@samp{set e}.
+
+@@item delete environment @@var{varname}
+@@kindex delete environment
+@@item unset environment @@var{varname}
+@@kindex unset environment
+Remove variable @@var{varname} from the environment to be passed to
+your program. This is different from @@samp{set env @@var{varname} =}
+because @@samp{delete environment} makes a variable not be defined at
+all, which is distinguishable from an empty value. This command can
+be abbreviated @@samp{d e}.
+@@end table
+
+@@node Working Directory, Input/Output, Environment, Running
+@@section Your Program's Working Directory
+
+@@cindex working directory (of your program)
+Each time you start your program with @@samp{run}, it inherits its working
+directory from the current working directory of GDB. GDB's working
+directory is initially whatever it inherited from its superior, but you can
+specify the working directory for GDB with the @@samp{cd} command.
+
+The GDB working directory also serves as a default for the commands
+that specify files for GDB to operate on. @@xref{Files}.
+
+@@table @@code
+@@item cd @@var{directory}
+@@kindex cd
+Set GDB's working directory to @@var{directory}.
+
+@@item pwd
+@@kindex pwd
+Print GDB's working directory.
+@@end table
+
+@@node Input/Output, Attach, Working Directory, Running
+@@section Your Program's Input and Output
+
+@@cindex redirection
+@@cindex controlling terminal
+By default, the program you run under GDB does input and output to the same
+terminal that GDB uses.
+
+You can redirect the program's input and/or output using @@samp{sh}-style
+redirection commands in the @@samp{run} command. For example,
+
+@@example
+run > outfile
+@@end example
+
+@@noindent
+starts the program, diverting its output to the file @@file{outfile}.
+
+@@kindex tty
+Another way to specify where the program should do input and output is with
+the @@samp{tty} command. This command accepts a file name as argument, and
+causes this file to be the default for future @@samp{run} commands. It also
+resets the controlling terminal for future @@samp{run} commands. For
+example,
+
+@@example
+tty /dev/ttyb
+@@end example
+
+@@noindent
+directs that processes started with subsequent @@samp{run} commands default
+to do input and output on the terminal @@file{/dev/ttyb} and sets the
+controlling terminal to @@file{/dev/ttyb}. An explicit redirection in
+@@samp{run} overrides the @@samp{tty} command's effect on input/output
+redirection.
+
+When you use the @@samp{tty} command or redirect input in the @@samp{run}
+command, the @@emph{input for your program} comes from the specified file,
+but the input for GDB still comes from your terminal.
+
+@@node Attach,, Input/Output, Running
+@@section Debugging an Already-Running Process
+@@kindex detach
+@@kindex attach
+@@cindex attach
+
+Some operating systems (in particular, Sun) allow GDB to begin debugging an
+already-running process that was started outside of GDB. To do this you
+must use the @@samp{attach} command instead of the @@samp{run} command.
+
+The @@samp{attach} command requires one argument, which is the process-id of
+the process you want to debug. (The usual way to find out the process-id
+of the process is with the @@samp{ps} utility.)
+
+The first thing GDB does after arranging to debug the process is to stop
+it. You can examine and modify an attached process with all the GDB
+commands that ordinarily available when you start processes with
+@@samp{run}. You can insert breakpoints; you can step and continue; you
+can modify storage. If you would rather the process continue running,
+use the @@samp{continue} command after attaching.
+
+When you are finished debugging the attached process, you can use the
+@@samp{detach} command to release it from GDB's control. Detaching
+the process continues its execution. After the @@samp{detach} command,
+that process and GDB become completely independent once more, and you
+are ready to @@samp{attach} another process or start one with @@samp{run}.
+
+If you exit GDB or use the @@samp{run} command while you have an attached
+process, you kill that process. You will be asked for confirmation if you
+try to do either of these things.
+
+@@node Stopping, Stack, Running, Top
+@@chapter Stopping and Continuing
+
+When you run a program normally, it runs until exiting. The purpose
+of using a debugger is so that you can stop it before that point;
+or so that if the program runs into trouble you can find out why.
+
+@@menu
+* Signals:: Fatal signals in your program just stop it;
+ then you can use GDB to see what is going on.
+* Breakpoints:: Breakpoints let you stop your program when it
+ reaches a specified point in the code.
+* Continuing:: Resuming execution until the next signal or breakpoint.
+* Stepping:: Stepping runs the program a short distance and
+ then stops it wherever it has come to.
+@@end menu
+
+@@node Signals, Breakpoints, Stopping, Stopping
+@@section Signals
+
+A signal is an asynchronous event that can happen in a program. The
+operating system defines the possible kinds of signals, and gives each kind
+a name and a number. For example, @@code{SIGINT} is the signal a program
+gets when you type @@kbd{Ctrl-c}; @@code{SIGSEGV} is the signal a program
+gets from referencing a place in memory far away from all the areas in use;
+@@code{SIGALRM} occurs when the alarm clock timer goes off (which happens
+only if the program has requested an alarm).
+
+Some signals, including @@code{SIGALRM}, are a normal part of the
+functioning of the program. Others, such as @@code{SIGSEGV}, indicate
+errors; these signals are @@dfn{fatal} (kill the program immediately) if the
+program has not specified in advance some other way to handle the signal.
+@@code{SIGINT} does not indicate an error in the program, but it is normally
+fatal so it can carry out the purpose of @@kbd{Ctrl-c}: to kill the program.
+
+GDB has the ability to detect any occurrence of a signal in the program
+running under GDB's control. You can tell GDB in advance what to do for
+each kind of signal.
+
+Normally, GDB is set up to ignore non-erroneous signals like @@code{SIGALRM}
+(so as not to interfere with their role in the functioning of the program)
+but to stop the program immediately whenever an error signal happens.
+You can change these settings with the @@samp{handle} command. You must
+specify which signal you are talking about with its number.
+
+@@table @@code
+@@item info signal
+@@kindex info signal
+Print a table of all the kinds of signals and how GDB has been told to
+handle each one. You can use this to see the signal numbers of all
+the defined types of signals.
+
+@@item handle @@var{signalnum} @@var{keywords}@@dots{}
+@@kindex handle
+Change the way GDB handles signal @@var{signalnum}. The @@var{keywords}
+say what change to make.
+@@end table
+
+To use the @@samp{handle} command you must know the code number of the
+signal you are concerned with. To find the code number, type @@samp{info
+signal} which prints a table of signal names and numbers.
+
+The keywords allowed by the handle command can be abbreviated. Their full
+names are
+
+@@table @@code
+@@item stop
+GDB should stop the program when this signal happens. This implies
+the @@samp{print} keyword as well.
+
+@@item print
+GDB should print a message when this signal happens.
+
+@@item nostop
+GDB should not stop the program when this signal happens. It may
+still print a message telling you that the signal has come in.
+
+@@item noprint
+GDB should not mention the occurrence of the signal at all. This
+implies the @@samp{nostop} keyword as well.
+
+@@item pass
+GDB should allow the program to see this signal; the program will be
+able to handle the signal, or may be terminated if the signal is fatal
+and not handled.
+
+@@item nopass
+GDB should not allow the program to see this signal.
+@@end table
+
+When a signal has been set to stop the program, the program cannot see the
+signal until you continue. It will see the signal then, if @@samp{pass} is
+in effect for the signal in question @@i{at that time}. In other words,
+after GDB reports a signal, you can use the @@samp{handle} command with
+@@samp{pass} or @@samp{nopass} to control whether that signal will be seen by
+the program when you later continue it.
+
+You can also use the @@samp{signal} command to prevent the program from
+seeing a signal, or cause it to see a signal it normally would not see,
+or to give it any signal at any time. @@xref{Signaling}.
+
+@@node Breakpoints, Continuing, Signals, Stopping
+@@section Breakpoints
+
+@@cindex breakpoints
+A @@dfn{breakpoint} makes your program stop whenever a certain point in the
+program is reached. You set breakpoints explicitly with GDB commands,
+specifying the place where the program should stop by line number, function
+name or exact address in the program. You can add various other conditions
+to control whether the program will stop.
+
+Each breakpoint is assigned a number when it is created; these numbers are
+successive integers starting with 1. In many of the commands for controlling
+various features of breakpoints you use the breakpoint number to say which
+breakpoint you want to change. Each breakpoint may be @@dfn{enabled} or
+@@dfn{disabled}; if disabled, it has no effect on the program until you
+enable it again.
+
+@@kindex info break
+@@kindex $_
+The command @@samp{info break} prints a list of all breakpoints set and not
+cleared, showing their numbers, where in the program they are, and any
+special features in use for them. Disabled breakpoints are included in the
+list, but marked as disabled. @@samp{info break} with a breakpoint number
+as argument lists only that breakpoint. The convenience variable @@samp{$_}
+and the default examining-address for the @@samp{x} command are set to the
+address of the last breakpoint listed (@@pxref{Memory}).
+
+@@menu
+* Set Breaks:: How to establish breakpoints.
+* Clear Breaks:: How to remove breakpoints no longer needed.
+* Disabling:: How to disable breakpoints (turn them off temporarily).
+* Conditions:: Making extra conditions on whether to stop.
+* Break Commands:: Commands to be executed at a breakpoint.
+* Error in Breakpoints:: "Cannot insert breakpoints" error--why, what to do.
+@@end menu
+
+@@node Set Breaks, Clear Breaks, Breakpoints, Breakpoints
+@@subsection Setting Breakpoints
+
+@@kindex break
+Breakpoints are set with the @@samp{break} command (abbreviated @@samp{b}).
+You have several ways to say where the breakpoint should go.
+
+@@table @@code
+@@item break @@var{function}
+Set a breakpoint at entry to function @@var{function}.
+
+@@item break @@var{linenum}
+Set a breakpoint at line @@var{linenum} in the current source file.
+That file is the last file whose source text was printed. This
+breakpoint will stop the program just before it executes any of the
+code on that line.
+
+@@item break @@var{filename}:@@var{linenum}
+Set a breakpoint at line @@var{linenum} in source file @@var{filename}.
+
+@@item break @@var{filename}:@@var{function}
+Set a breakpoint at entry to function @@var{function} found in file
+@@var{filename}. Specifying a filename as well as a function name is
+superfluous except when multiple files contain similarly named
+functions.
+
+@@item break *@@var{address}
+Set a breakpoint at address @@var{address}. You can use this to set
+breakpoints in parts of the program which do not have debugging
+information or source files.
+
+@@item break
+Set a breakpoint at the next instruction to be executed in the selected
+stack frame (@@pxref{Stack}). In any selected frame but the innermost,
+this will cause the program to stop as soon as control returns to that
+frame. This is equivalent to a @@samp{finish} command in the frame
+inside the selected frame. If this is done in the innermost frame gdb
+will stop the next time it reaches the current location; this may be
+useful inside of loops. It does not stop at this breakpoint immediately
+upon continuation of the program since no code would be executed if it
+did.
+
+@@item break @@dots{} if @@var{cond}
+Set a breakpoint with condition @@var{cond}; evaluate the expression
+@@var{cond} each time the breakpoint is reached, and stop only if the
+value is nonzero. @@samp{@@dots{}} stands for one of the possible
+arguments described above (or no argument) specifying where to break.
+@@xref{Conditions}, for more information on breakpoint conditions.
+
+@@item tbreak @@var{args}
+@@kindex tbreak
+Set a breakpoint enabled only for one stop. @@var{args} are the
+same as in the @@samp{break} command, and the breakpoint is set in the same
+way, but the breakpoint is automatically @@dfn{disabled} the first time it
+is hit.
+@@end table
+
+GDB allows you to set any number of breakpoints at the same place in the
+program. There is nothing silly or meaningless about this. When the
+breakpoints are conditional, this is even useful (@@pxref{Conditions}).
+
+@@node Clear Breaks, Disabling, Set Breaks, Breakpoints
+@@subsection Clearing Breakpoints
+
+@@cindex clear breakpoint
+@@cindex delete breakpoints
+It is often necessary to eliminate a breakpoint once it has done its job
+and you no longer want the program to stop there. This is called
+@@dfn{clearing} or @@samp{deleting} the breakpoint. A breakpoint that
+has been cleared no longer exists in any sense.
+
+With the @@samp{clear} command you can clear breakpoints according to where
+they are in the program. With the @@samp{delete} command you can clear
+individual breakpoints by specifying their breakpoint numbers.
+
+@@b{It is not necessary to clear a breakpoint to proceed past it.} GDB
+automatically ignores breakpoints in the first instruction to be executed
+when you continue execution at the same address where the program stopped.
+
+@@table @@code
+@@item clear
+@@kindex clear
+Clear any breakpoints at the next instruction to be executed in the
+selected stack frame (@@pxref{Selection}). When the innermost frame
+is selected, this is a good way to clear a breakpoint that the program
+just stopped at.
+
+@@item clear @@var{function}
+@@itemx clear @@var{filename}:@@var{function}
+Clear any breakpoints set at entry to the function @@var{function}.
+
+@@item clear @@var{linenum}
+@@item clear @@var{filename}:@@var{linenum}
+Clear any breakpoints set at or within the code of the specified line.
+
+@@item delete @@var{bnums}@@dots{}
+@@kindex delete
+Delete the breakpoints of the numbers specified as arguments.
+A breakpoint deleted is forgotten completely.
+@@end table
+
+@@node Disabling, Conditions, Clear Breaks, Breakpoints
+@@subsection Disabling Breakpoints
+
+@@cindex disabled breakpoints
+@@cindex enabled breakpoints
+Rather than clearing a breakpoint, you might prefer to @@dfn{disable} it.
+This makes the breakpoint inoperative as if it had been cleared, but
+remembers the information on the breakpoint so that you can @@dfn{enable}
+it again later.
+
+You disable and enable breakpoints with the @@samp{enable} and
+@@samp{disable} commands, specifying one or more breakpoint numbers as
+arguments. Use @@samp{info break} to print a list of breakpoints if you
+don't know which breakpoint numbers to use.
+
+A breakpoint can have any of four different states of enablement:
+
+@@itemize @@bullet
+@@item
+Enabled. The breakpoint will stop the program. A breakpoint made
+with the @@samp{break} command starts out in this state.
+@@item
+Disabled. The breakpoint has no effect on the program.
+@@item
+Enabled once. The breakpoint will stop the program, but
+when it does so it will become disabled. A breakpoint made
+with the @@samp{tbreak} command starts out in this state.
+@@item
+Enabled for deletion. The breakpoint will stop the program, but
+immediately after it does so it will be deleted permanently.
+@@end itemize
+
+You change the state of enablement of a breakpoint with the following
+commands:
+
+@@table @@code
+@@item disable breakpoints @@var{bnums}@@dots{}
+@@kindex disable breakpoints
+@@item disable @@var{bnums}@@dots{}
+@@kindex disable
+Disable the specified breakpoints. A disabled breakpoint has no
+effect but is not forgotten. All options such as ignore-counts,
+conditions and commands are remembered in case the breakpoint is
+enabled again later.
+
+@@item enable breakpoints @@var{bnums}@@dots{}
+@@kindex enable breakpoints
+@@item enable @@var{bnums}@@dots{}
+@@kindex enable
+Enable the specified breakpoints. They become effective once again in
+stopping the program, until you specify otherwise.
+
+@@item enable breakpoints once @@var{bnums}@@dots{}
+@@item enable once @@var{bnums}@@dots{}
+Enable the specified breakpoints temporarily. Each will be disabled
+again the next time it stops the program (unless you have used one of
+these commands to specify a different state before that time comes).
+
+@@item enable breakpoints delete @@var{bnums}@@dots{}
+@@item enable delete @@var{bnums}@@dots{}
+Enable the specified breakpoints to work once and then die. Each of
+the breakpoints will be deleted the next time it stops the program
+(unless you have used one of these commands to specify a different
+state before that time comes).
+@@end table
+
+Aside from the automatic disablement or deletion of a breakpoint when it
+stops the program, which happens only in certain states, the state of
+enablement of a breakpoint changes only when one of the commands above
+is used.
+
+@@node Conditions, Break Commands, Disabling, Breakpoints
+@@subsection Break Conditions
+
+@@cindex conditions
+The simplest sort of breakpoint breaks every time the program reaches a
+specified place. You can also specify a @@dfn{condition} for a breakpoint.
+A condition is just a boolean expression in your programming language
+(@@xref{Expressions}). A breakpoint with a condition evaluates the
+expression each time the program reaches it, and the program stops
+only if the condition is true.
+
+Break conditions may have side effects, and may even call functions in your
+program. These may sound like strange things to do, but their effects are
+completely predictable unless there is another enabled breakpoint at the
+same address. (In that case, GDB might see the other breakpoint first and
+stop the program without checking the condition of this one.) Note that
+breakpoint commands are usually more convenient and flexible for the
+purpose of performing side effects when a breakpoint is reached
+(@@pxref{Break Commands}).
+
+Break conditions can be specified when a breakpoint is set, by using
+@@samp{if} in the arguments to the @@samp{break} command. @@xref{Set Breaks}.
+They can also be changed at any time with the @@samp{condition} command:
+
+@@table @@code
+@@item condition @@var{bnum} @@var{expression}
+@@kindex condition
+Specify @@var{expression} as the break condition for breakpoint number
+@@var{bnum}. From now on, this breakpoint will stop the program only if
+the value of @@var{expression} is true (nonzero, in C). @@var{expression}
+is not evaluated at the time the @@samp{condition} command is given.
+@@xref{Expressions}.
+
+@@item condition @@var{bnum}
+Remove the condition from breakpoint number @@var{bnum}. It becomes
+an ordinary unconditional breakpoint.
+@@end table
+
+@@cindex ignore count (of breakpoint)
+A special feature is provided for one kind of condition: to prevent the
+breakpoint from doing anything until it has been reached a certain number
+of times. This is done with the @@dfn{ignore count} of the breakpoint.
+When the program reaches a breakpoint whose ignore count is positive, then
+instead of stopping, it just decrements the ignore count by one and
+continues.
+
+@@table @@code
+@@item ignore @@var{bnum} @@var{count}
+@@kindex ignore
+Set the ignore count of breakpoint number @@var{bnum} to @@var{count}.
+The next @@var{count} times the breakpoint is reached, it will not stop.
+
+To make the breakpoint stop the next time it is reached, specify
+a count of zero.
+
+@@item cont @@var{count}
+Continue execution of the program, setting the ignore count of the
+breakpoint that the program stopped at to @@var{count} minus one.
+Continuing through the breakpoint does not itself count as one of
+@@var{count}. Thus, the program will not stop at this breakpoint until the
+@@var{count}'th time it is hit.
+
+This command is allowed only when the program stopped due to a
+breakpoint. At other times, the argument to @@samp{cont} is ignored.
+@@end table
+
+If a breakpoint has a positive ignore count and a condition, the condition
+is not checked. Once the ignore count reaches zero, the condition will
+start to be checked.
+
+Note that you could achieve the effect of the ignore count with a condition
+such as @@samp{$foo-- <= 0} using a debugger convenience variable that is
+decremented each time. That is why the ignore count is considered a
+special case of a condition. @@xref{Convenience Vars}.
+
+@@node Break Commands, Error in Breakpoints, Conditions, Breakpoints
+@@subsection Commands Executed on Breaking
+
+@@cindex breakpoint commands
+You can give any breakpoint a series of commands to execute when the
+program stops due to that breakpoint. For example, you might want to
+print the values of certain expressions, or enable other breakpoints.
+
+@@table @@code
+@@item commands @@var{bnum}
+Specify commands for breakpoint number @@var{bnum}. The commands
+themselves appear on the following lines. Type a line containing just
+@@samp{end} to terminate the commands.
+
+To remove all commands from a breakpoint, use the command
+@@samp{commands} and follow it immediately by @@samp{end}; that is, give
+no commands.
+
+With no arguments, @@samp{commands} refers to the last breakpoint set.
+@@end table
+
+It is possible for breakpoint commands to start the program up again.
+Simply use the @@samp{cont} command, or @@samp{step}, or any other command
+to resume execution. However, any remaining breakpoint commands are
+ignored. When the program stops again, GDB will act according to why
+that stop took place.
+
+@@kindex silent
+If the first command specified is @@samp{silent}, the usual message about
+stopping at a breakpoint is not printed. This may be desirable for
+breakpoints that are to print a specific message and then continue.
+If the remaining commands too print nothing, you will see no sign that
+the breakpoint was reached at all. @@samp{silent} is not really a command;
+it is meaningful only at the beginning of the commands for a breakpoint.
+
+The commands @@samp{echo} and @@samp{output} that allow you to print precisely
+controlled output are often useful in silent breakpoints. @@xref{Output}.
+
+For example, here is how you could use breakpoint commands to print the
+value of @@code{x} at entry to @@code{foo} whenever it is positive. We
+assume that the newly created breakpoint is number 4; @@samp{break} will
+print the number that is assigned.
+
+@@example
+break foo if x>0
+commands 4
+silent
+echo x is\040
+output x
+echo \n
+cont
+end
+@@end example
+
+One application for breakpoint commands is to correct one bug so you can
+test another. Put a breakpoint just after the erroneous line of code, give
+it a condition to detect the case in which something erroneous has been
+done, and give it commands to assign correct values to any variables that
+need them. End with the @@samp{cont} command so that the program does not
+stop, and start with the @@samp{silent} command so that no output is
+produced. Here is an example:
+
+@@example
+break 403
+commands 5
+silent
+set x = y + 4
+cont
+end
+@@end example
+
+One deficiency in the operation of automatically continuing breakpoints
+under Unix appears when your program uses raw mode for the terminal.
+GDB switches back to its own terminal modes (not raw) before executing
+commands, and then must switch back to raw mode when your program is
+continued. This causes any pending terminal input to be lost.
+
+In the GNU system, this will be fixed by changing the behavior of
+terminal modes.
+
+Under Unix, when you have this problem, you might be able to get around
+it by putting your actions into the breakpoint condition instead of
+commands. For example
+
+@@example
+condition 5 (x = y + 4), 0
+@@end example
+
+@@noindent
+is a condition expression (@@xref{Expressions}) that will change @@code{x}
+as needed, then always have the value 0 so the program will not stop.
+Loss of input is avoided here because break conditions are evaluated
+without changing the terminal modes. When you want to have nontrivial
+conditions for performing the side effects, the operators @@samp{&&},
+@@samp{||} and @@samp{?@@: @@dots{} :@@:} may be useful.
+
+@@node Error in Breakpoints,, Break Commands, Breakpoints
+@@subsection ``Cannot Insert Breakpoints'' Error
+
+Under some Unix systems, breakpoints cannot be used in a program if any
+other process is running that program. Attempting to run or continue
+the program with a breakpoint in this case will cause GDB to stop it.
+
+When this happens, you have three ways to proceed:
+
+@@enumerate
+@@item
+Remove or disable the breakpoints, then continue.
+
+@@item
+Suspend GDB, and copy the file containing the program to a new name.
+Resume GDB and use the @@samp{exec-file} command to specify that GDB
+should run the program under that name. Then start the program again.
+
+@@item
+Recompile the program so that the text is non-sharable (a.out format
+OMAGIC).
+@@end enumerate
+
+@@node Continuing, Stepping, Breakpoints, Stopping
+@@section Continuing
+
+After your program stops, most likely you will want it to run some more if
+the bug you are looking for has not happened yet.
+
+@@table @@code
+@@item cont
+@@kindex cont
+Continue running the program at the place where it stopped.
+@@end table
+
+If the program stopped at a breakpoint, the place to continue running
+is the address of the breakpoint. You might expect that continuing would
+just stop at the same breakpoint immediately. In fact, @@samp{cont}
+takes special care to prevent that from happening. You do not need
+to clear the breakpoint to proceed through it after stopping at it.
+
+You can, however, specify an ignore-count for the breakpoint that the
+program stopped at, by means of an argument to the @@samp{cont} command.
+@@xref{Conditions}.
+
+If the program stopped because of a signal other than @@code{SIGINT} or
+@@code{SIGTRAP}, continuing will cause the program to see that signal.
+You may not want this to happen. For example, if the program stopped
+due to some sort of memory reference error, you might store correct
+values into the erroneous variables and continue, hoping to see more
+execution; but the program would probably terminate immediately as
+a result of the fatal signal once it sees the signal. To prevent this,
+you can continue with @@samp{signal 0}. @@xref{Signaling}. You can
+also act in advance to prevent the program from seeing certain kinds
+of signals, using the @@samp{handle} command (@@pxref{Signals}).
+
+@@node Stepping,, Continuing, Stopping
+@@section Stepping
+
+@@cindex stepping
+@@dfn{Stepping} means setting your program in motion for a limited time, so
+that control will return automatically to the debugger after one line of
+code or one machine instruction. Breakpoints are active during stepping
+and the program will stop for them even if it has not gone as far as the
+stepping command specifies.
+
+@@table @@code
+@@item step
+@@kindex step
+Proceed the program until control reaches a different line, then stop
+it and return to the debugger. This command is abbreviated @@samp{s}.
+
+@@item step @@var{count}
+Proceed as in @@samp{step}, but do so @@var{count} times. If a breakpoint
+or a signal not related to stepping is reached before @@var{count} steps,
+stepping stops right away.
+
+This command may be given when control is within a routine for which
+there is no debugging information. In that case, execution will proceed
+until control reaches a different routine, or is about to return from
+this routine. An argument repeats this action.
+
+@@item next
+@@kindex next
+Similar to @@samp{step}, but any function calls appearing within the line of
+code are executed without stopping. Execution stops when control reaches a
+different line of code at the stack level which was executing when the
+@@samp{next} command was given. This command is abbreviated @@samp{n}.
+
+An argument is a repeat count, as in @@samp{step}.
+
+@@samp{next} within a routine without debugging information acts as does
+@@samp{step}, but any function calls appearing within the code of the
+routine are executed without stopping.
+
+@@item finish
+@@kindex finish
+Continue running until just after the selected stack frame returns
+(or until there is some other reason to stop, such as a fatal signal
+or a breakpoint). Print value returned by the selected stack frame (if
+any).
+
+Contrast this with the @@samp{return} command (@@pxref{Returning}).
+
+@@item until
+@@kindex until
+Proceed the program until control reaches a line greater than the current
+line, then stop is and return to the debugger. Control is also returned to
+the debugger if the program exits the current stack frame. Note that this
+form of the command uses single stepping, and hence is slower than
+@@samp{until} with an argument. This command is abbreviated @@samp{u}.
+
+@@item until @@var{location}
+Proceed the program until either the specified location is reached, or the
+current (innermost) stack frame returns. This form of the command uses
+breakpoints, and hence is quicker than @@samp{until} without an argument.
+
+@@item stepi
+@@itemx si
+@@kindex stepi
+@@kindex si
+Proceed one machine instruction, then stop and return to the debugger.
+
+It is often useful to do @@samp{display/i $pc} when stepping by machine
+instructions. This will cause the next instruction to be executed to
+be displayed automatically at each stop. @@xref{Auto Display}.
+
+An argument is a repeat count, as in @@samp{step}.
+
+@@item nexti
+@@itemx ni
+@@kindex nexti
+@@kindex ni
+Proceed one machine instruction, but if it is a subroutine call,
+proceed until the subroutine returns.
+
+An argument is a repeat count, as in @@samp{next}.
+@@end table
+
+A typical technique for using stepping is to put a breakpoint
+(@@pxref{Breakpoints}) at the beginning of the function or the section of
+the program in which a problem is believed to lie, and then step through
+the suspect area, examining the variables that are interesting, until the
+problem happens.
+
+The @@samp{cont} command can be used after stepping to resume execution
+until the next breakpoint or signal.
+
+@@node Stack, Source, Stopping, Top
+@@chapter Examining the Stack
+
+When your program has stopped, the first thing you need to know is where it
+stopped and how it got there.
+
+@@cindex call stack
+Each time your program performs a function call, the information about
+where in the program the call was made from is saved in a block of data
+called a @@dfn{stack frame}. The frame also contains the arguments of the
+call and the local variables of the function that was called. All the
+stack frames are allocated in a region of memory called the @@dfn{call
+stack}.
+
+When your program stops, the GDB commands for examining the stack allow you
+to see all of this information.
+
+One of the stack frames is @@dfn{selected} by GDB and many GDB commands
+refer implicitly to the selected frame. In particular, whenever you ask
+GDB for the value of a variable in the program, the value is found in the
+selected frame. There are special GDB commands to select whichever frame
+you are interested in.
+
+When the program stops, GDB automatically selects the currently executing
+frame and describes it briefly as the @@samp{frame} command does
+(@@pxref{Frame Info, Info}).
+
+@@menu
+* Frames:: Explanation of stack frames and terminology.
+* Backtrace:: Summarizing many frames at once.
+* Selection:: How to select a stack frame.
+* Info: Frame Info, Commands to print information on stack frames.
+@@end menu
+
+@@node Frames, Backtrace, Stack, Stack
+@@section Stack Frames
+
+@@cindex frame
+The call stack is divided up into contiguous pieces called @@dfn{frames};
+each frame is the data associated with one call to one function. The frame
+contains the arguments given to the function, the function's local
+variables, and the address at which the function is executing.
+
+@@cindex initial frame
+@@cindex outermost frame
+@@cindex innermost frame
+When your program is started, the stack has only one frame, that of the
+function @@code{main}. This is called the @@dfn{initial} frame or the
+@@dfn{outermost} frame. Each time a function is called, a new frame is
+made. Each time a function returns, the frame for that function invocation
+is eliminated. If a function is recursive, there can be many frames for
+the same function. The frame for the function in which execution is
+actually occurring is called the @@dfn{innermost} frame. This is the most
+recently created of all the stack frames that still exist.
+
+@@cindex frame pointer
+Inside your program, stack frames are identified by their addresses. A
+stack frame consists of many bytes, each of which has its own address; each
+kind of computer has a convention for choosing one of those bytes whose
+address serves as the address of the frame. Usually this address is kept
+in a register called the @@dfn{frame pointer register} while execution is
+going on in that frame.
+
+@@cindex frame number
+GDB assigns numbers to all existing stack frames, starting with zero for
+the innermost frame, one for the frame that called it, and so on upward.
+These numbers do not really exist in your program; they are to give you a
+way of talking about stack frames in GDB commands.
+
+@@cindex selected frame
+Many GDB commands refer implicitly to one stack frame. GDB records a stack
+frame that is called the @@dfn{selected} stack frame; you can select any
+frame using one set of GDB commands, and then other commands will operate
+on that frame. When your program stops, GDB automatically selects the
+innermost frame.
+
+@@node Backtrace, Selection, Frames, Stack
+@@section Backtraces
+
+A backtrace is a summary of how the program got where it is. It shows one
+line per frame, for many frames, starting with the currently executing
+frame (frame zero), followed by its caller (frame one), and on up the
+stack.
+
+@@table @@code
+@@item backtrace
+@@itemx bt
+Print a backtrace of the entire stack: one line per frame for all
+frames in the stack.
+
+You can stop the backtrace at any time by typing the system interrupt
+character, normally @@kbd{Control-C}.
+
+@@item backtrace @@var{n}
+@@itemx bt @@var{n}
+Similar, but stop after @@var{n} frames.
+
+@@item backtrace @@var{-n}
+@@itemx bt @@var{-n}
+Similar, but print the outermost @@var{n} frames instead of the
+innermost.
+@@end table
+
+Each line in a backtrace shows the frame number, the program counter, the
+function and its arguments, and the source file name and line number (if
+known). The program counter is omitted if is the beginning of the code for
+the source line. This is the same as the first of the two lines printed
+when you select a frame.
+
+@@node Selection, Frame Info, Backtrace, Stack
+@@section Selecting a Frame
+
+Most commands for examining the stack and other data in the program work on
+whichever stack frame is selected at the moment. Here are the commands for
+selecting a stack frame; all of them finish by printing a brief description
+of the stack frame just selected.
+
+@@table @@code
+@@item frame @@var{n}
+@@kindex frame
+Select frame number @@var{n}. Recall that frame zero is the innermost
+(currently executing) frame, frame one is the frame that called the
+innermost one, and so on. The highest-numbered frame is @@code{main}'s
+frame.
+
+@@item frame @@var{addr}
+Select the frame at address @@var{addr}. This is useful mainly if the
+chaining of stack frames has been damaged by a bug, making it
+impossible for GDB to assign numbers properly to all frames. In
+addition, this can be useful when the program has multiple stacks and
+switches between them.
+
+@@item up @@var{n}
+@@kindex up
+Select the frame @@var{n} frames up from the frame previously selected.
+For positive numbers @@var{n}, this advances toward the outermost
+frame, to higher frame numbers, to frames that have existed longer.
+@@var{n} defaults to one.
+
+@@item down @@var{n}
+@@kindex down
+Select the frame @@var{n} frames down from the frame previously
+selected. For positive numbers @@var{n}, this advances toward the
+innermost frame, to lower frame numbers, to frames that were created
+more recently. @@var{n} defaults to one.
+@@end table
+
+All of these commands end by printing some information on the frame that
+has been selected: the frame number, the function name, the arguments, the
+source file and line number of execution in that frame, and the text of
+that source line. For example:
+
+@@example
+#3 main (argc=3, argv=??, env=??) at main.c, line 67
+67 read_input_file (argv[i]);
+@@end example
+
+After such a printout, the @@samp{list} command with no arguments will print
+ten lines centered on the point of execution in the frame. @@xref{List}.
+
+@@node Frame Info,, Selection, Stack
+@@section Information on a Frame
+
+There are several other commands to print information about the selected
+stack frame.
+
+@@table @@code
+@@item frame
+This command prints a brief description of the selected stack frame.
+It can be abbreviated @@samp{f}. With an argument, this command is
+used to select a stack frame; with no argument, it does not change
+which frame is selected, but still prints the same information.
+
+@@item info frame
+@@kindex info frame
+This command prints a verbose description of the selected stack frame,
+including the address of the frame, the addresses of the next frame in
+(called by this frame) and the next frame out (caller of this frame),
+the address of the frame's arguments, the program counter saved in it
+(the address of execution in the caller frame), and which registers
+were saved in the frame. The verbose description is useful when
+something has gone wrong that has made the stack format fail to fit
+the usual conventions.
+
+@@item info frame @@var{addr}
+Print a verbose description of the frame at address @@var{addr},
+without selecting that frame. The selected frame remains unchanged by
+this command.
+
+@@item info args
+@@kindex info args
+Print the arguments of the selected frame, each on a separate line.
+
+@@item info locals
+@@kindex info locals
+Print the local variables of the selected frame, each on a separate
+line. These are all variables declared static or automatic within all
+program blocks that execution in this frame is currently inside of.
+@@end table
+
+@@node Source, Data, Stack, Top
+@@chapter Examining Source Files
+
+GDB knows which source files your program was compiled from, and
+can print parts of their text. When your program stops, GDB
+spontaneously prints the line it stopped in. Likewise, when you
+select a stack frame (@@pxref{Selection}), GDB prints the line
+which execution in that frame has stopped in. You can also
+print parts of source files by explicit command.
+
+@@menu
+* List:: Using the @@samp{list} command to print source files.
+* Search:: Commands for searching source files.
+* Source Path:: Specifying the directories to search for source files.
+@@end menu
+
+@@node List, Search, Source, Source
+@@section Printing Source Lines
+
+@@kindex list
+To print lines from a source file, use the @@samp{list} command
+(abbreviated @@samp{l}). There are several ways to specify what part
+of the file you want to print.
+
+Here are the forms of the @@samp{list} command most commonly used:
+
+@@table @@code
+@@item list @@var{linenum}
+Print ten lines centered around line number @@var{linenum} in the
+current source file.
+
+@@item list @@var{function}
+Print ten lines centered around the beginning of function
+@@var{function}.
+
+@@item list
+Print ten more lines. If the last lines printed were printed with a
+@@samp{list} command, this prints ten lines following the last lines
+printed; however, if the last line printed was a solitary line printed
+as part of displaying a stack frame (@@pxref{Stack}), this prints ten
+lines centered around that line.
+
+@@item list @@minus{}
+Print ten lines just before the lines last printed.
+@@end table
+
+Repeating a @@samp{list} command with @@key{RET} discards the argument,
+so it is equivalent to typing just @@samp{list}. This is more useful
+than listing the same lines again. An exception is made for an
+argument of @@samp{-}; that argument is preserved in repetition so that
+each repetition moves up in the file.
+
+In general, the @@samp{list} command expects you to supply zero, one or two
+@@dfn{linespecs}. Linespecs specify source lines; there are several ways
+of writing them but the effect is always to specify some source line.
+Here is a complete description of the possible arguments for @@samp{list}:
+
+@@table @@code
+@@item list @@var{linespec}
+Print ten lines centered around the line specified by @@var{linespec}.
+
+@@item list @@var{first},@@var{last}
+Print lines from @@var{first} to @@var{last}. Both arguments are
+linespecs.
+
+@@item list ,@@var{last}
+Print ten lines ending with @@var{last}.
+
+@@item list @@var{first},
+Print ten lines starting with @@var{first}.
+
+@@item list +
+Print ten lines just after the lines last printed.
+
+@@item list @@minus{}
+Print ten lines just before the lines last printed.
+
+@@item list
+As described in the preceding table.
+@@end table
+
+Here are the ways of specifying a single source line---all the
+kinds of linespec.
+
+@@table @@asis
+@@item @@var{linenum}
+Specifies line @@var{linenum} of the current source file.
+When a @@samp{list} command has two linespecs, this refers to
+the same source file as the first linespec.
+
+@@item +@@var{offset}
+Specifies the line @@var{offset} lines after the last line printed.
+When used as the second linespec in a @@samp{list} command that has
+two, this specifies the line @@var{offset} lines down from the
+first linespec.
+
+@@item @@minus{}@@var{offset}
+Specifies the line @@var{offset} lines before the last line printed.
+
+@@item @@var{filename}:@@var{linenum}
+Specifies line @@var{linenum} in the source file @@var{filename}.
+
+@@item @@var{function}
+Specifies the line of the open-brace that begins the body of the
+function @@var{function}.
+
+@@item @@var{filename}:@@var{function}
+Specifies the line of the open-brace that begins the body of the
+function @@var{function} in the file @@var{filename}. The file name is
+needed with a function name only for disambiguation of identically
+named functions in different source files.
+
+@@item *@@var{address}
+Specifies the line containing the program address @@var{address}.
+@@var{address} may be any expression.
+@@end table
+
+One other command is used to map source lines to program addresses.
+
+@@table @@code
+@@item info line @@var{linenum}
+@@kindex info line
+Print the starting and ending addresses of the compiled code for
+source line @@var{linenum}.
+
+@@kindex $_
+The default examine address for the @@samp{x} command is changed to the
+starting address of the line, so that @@samp{x/i} is sufficient to
+begin examining the machine code (@@pxref{Memory}). Also, this address
+is saved as the value of the convenience variable @@samp{$_}
+(@@pxref{Convenience Vars}).
+@@end table
+
+@@node Search, Source Path, List, Source
+@@section Searching Source Files
+@@cindex searching
+@@kindex forward-search
+@@kindex reverse-search
+
+There are two commands for searching through the current source file for a
+regular expression.
+
+The command @@samp{forward-search @@var{regexp}} checks each line, starting
+with the one following the last line listed, for a match for @@var{regexp}.
+It lists the line that is found. You can abbreviate the command name
+as @@samp{fo}.
+
+The command @@samp{reverse-search @@var{regexp}} checks each line, starting
+with the one before the last line listed and going backward, for a match
+for @@var{regexp}. It lists the line that is found. You can abbreviate
+this command with as little as @@samp{rev}.
+
+@@node Source Path,, Search, Source
+@@section Specifying Source Directories
+
+@@cindex source path
+@@cindex directories for source files
+Executable programs do not record the directories of the source files they
+were compiled from, just the names. GDB remembers a list of directories to
+search for source files; this is called the @@dfn{source path}. Each time
+GDB wants a source file, it tries all the directories in the list, in the
+order they are present in the list, until it finds a file with the desired
+name.
+
+@@kindex directory
+When you start GDB, its source path contains just the current working
+directory. To add other directories, use the @@samp{directory} command.
+@@b{Note that the search path for executable files and the working directory
+are @@i{not} used for finding source files.}
+
+@@table @@code
+@@item directory @@var{dirname}
+Add directory @@var{dirname} to the end of the source path.
+
+@@item directory
+Reset the source path to just the current working directory of GDB.
+This requires confirmation.
+
+@@samp{directory} with no argument can cause source files previously
+found by GDB to be found in a different directory. To make this work
+correctly, this command also clears out the tables GDB maintains
+about the source files it has already found.
+
+@@item info directories
+@@kindex info directories
+Print the source path: show which directories it contains.
+@@end table
+
+Because the @@samp{directory} command adds to the end of the source path,
+it does not affect any file that GDB has already found. If the source
+path contains directories that you do not want, and these directories
+contain misleading files with names matching your source files, the
+way to correct the situation is as follows:
+
+@@enumerate
+@@item
+Choose the directory you want at the beginning of the source path.
+Use the @@samp{cd} command to make that the current working directory.
+
+@@item
+Use @@samp{directory} with no argument to reset the source path to just
+that directory.
+
+@@item
+Use @@samp{directory} with suitable arguments to add any other
+directories you want in the source path.
+@@end enumerate
+
+@@node Data, Symbols, Source, Top
+@@chapter Examining Data
+
+@@cindex printing data
+@@cindex examining data
+@@kindex print
+The usual way of examining data in your program is with the @@samp{print}
+command (abbreviated @@samp{p}). It evaluates and prints the value of any
+valid expression of the language the program is written in (for now, C).
+You type
+
+@@example
+print @@var{exp}
+@@end example
+
+@@noindent
+where @@var{exp} is any valid expression, and the value of @@var{exp}
+is printed in a format appropriate to its data type.
+
+A more low-level way of examining data is with the @@samp{x} command.
+It examines data in memory at a specified address and prints it in a
+specified format.
+
+GDB supports one command to modify the default format of displayed data:
+
+@@table @@samp
+@@item set array-max
+@@kindex set array-max
+@@samp{set array-max} sets the maximum number of elements of an array which
+will be printed. This limit also applies to the display of strings.
+@@end table
+
+@@menu
+* Expressions:: Expressions that can be computed and printed.
+* Variables:: Using your program's variables in expressions.
+* Assignment:: Setting your program's variables.
+* Arrays:: Examining part of memory as an array.
+* Formats:: Specifying formats for printing values.
+* Memory:: Examining memory explicitly.
+* Auto Display:: Printing certain expressions whenever program stops.
+* Value History:: Referring to values previously printed.
+* Convenience Vars:: Giving names to values for future reference.
+* Registers:: Referring to and storing in machine registers.
+@@end menu
+
+@@node Expressions, Variables, Data, Data
+@@section Expressions
+
+@@cindex expressions
+Many different GDB commands accept an expression and compute its value.
+Any kind of constant, variable or operator defined by the programming
+language you are using is legal in an expression in GDB. This includes
+conditional expressions, function calls, casts and string constants.
+It unfortunately does not include symbols defined by preprocessor
+#define commands.
+
+Casts are supported in all languages, not just in C, because it is so
+useful to cast a number into a pointer so as to examine a structure
+at that address in memory.
+
+GDB supports three kinds of operator in addition to those of programming
+languages:
+
+@@table @@code
+@@item @@@@
+@@samp{@@@@} is a binary operator for treating parts of memory as arrays.
+@@xref{Arrays}, for more information.
+
+@@item ::
+@@samp{::} allows you to specify a variable in terms of the file or
+function it is defined in. @@xref{Variables}.
+
+@@item @@{@@var{type}@@} @@var{addr}
+Refers to an object of type @@var{type} stored at address @@var{addr} in
+memory. @@var{addr} may be any expression whose value is an integer or
+pointer (but parentheses are required around nonunary operators, just as in
+a cast). This construct is allowed regardless of what kind of data is
+officially supposed to reside at @@var{addr}.@@refill
+@@end table
+
+@@node Variables, Arrays, Expressions, Data
+@@section Program Variables
+
+The most common kind of expression to use is the name of a variable
+in your program.
+
+Variables in expressions are understood in the selected stack frame
+(@@pxref{Selection}); they must either be global (or static) or be visible
+according to the scope rules of the programming language from the point of
+execution in that frame. This means that in the function
+
+@@example
+foo (a)
+ int a;
+@@{
+ bar (a);
+ @@{
+ int b = test ();
+ bar (b);
+ @@}
+@@}
+@@end example
+
+@@noindent
+the variable @@code{a} is usable whenever the program is executing
+within the function @@code{foo}, but the variable @@code{b} is visible
+only while the program is executing inside the block in which @@code{b}
+is declared.
+
+As a special exception, you can refer to a variable or function whose
+scope is a single source file even if the current execution point is not
+in this file. But it is possible to have more than one such variable
+or function with the same name (if they are in different source files).
+In such a case, it is not defined which one you will get. If you wish,
+you can specify any one of them using the colon-colon construct:
+
+@@example
+@@var{block}::@@var{variable}
+@@end example
+
+@@noindent
+Here @@var{block} is the name of the source file whose variable you want.
+
+@@node Arrays, Formats, Variables, Data
+@@section Artificial Arrays
+
+@@cindex artificial array
+It is often useful to print out several successive objects of the
+same type in memory; a section of an array, or an array of
+dynamically determined size for which only a pointer exists in the
+program.
+
+This can be done by constructing an @@dfn{artificial array} with the
+binary operator @@samp{@@@@}. The left operand of @@samp{@@@@} should be
+the first element of the desired array, as an individual object.
+The right operand should be the length of the array. The result is
+an array value whose elements are all of the type of the left argument.
+The first element is actually the left argument; the second element
+comes from bytes of memory immediately following those that hold the
+first element, and so on. Here is an example. If a program says
+
+@@example
+int *array = (int *) malloc (len * sizeof (int));
+@@end example
+
+@@noindent
+you can print the contents of @@code{array} with
+
+@@example
+p *array@@@@len
+@@end example
+
+The left operand of @@samp{@@@@} must reside in memory. Array values made
+with @@samp{@@@@} in this way behave just like other arrays in terms of
+subscripting, and are coerced to pointers when used in expressions.
+(It would probably appear in an expression via the value history,
+after you had printed it out.)
+
+@@node Formats, Memory, Arrays, Data
+@@section Formats
+
+@@cindex formatted output
+@@cindex output formats
+GDB normally prints all values according to their data types. Sometimes
+this is not what you want. For example, you might want to print a number
+in hex, or a pointer in decimal. Or you might want to view data in memory
+at a certain address as a character string or an instruction. These things
+can be done with @@dfn{output formats}.
+
+The simplest use of output formats is to say how to print a value
+already computed. This is done by starting the arguments of the
+@@samp{print} command with a slash and a format letter. The format
+letters supported are:
+
+@@table @@samp
+@@item x
+Regard the bits of the value as an integer, and print the integer in
+hexadecimal.
+
+@@item d
+Print as integer in signed decimal.
+
+@@item u
+Print as integer in unsigned decimal.
+
+@@item o
+Print as integer in octal.
+
+@@item a
+Print as an address, both absolute in hex and then relative
+to a symbol defined as an address below it.
+
+@@item c
+Regard as an integer and print it as a character constant.
+
+@@item f
+Regard the bits of the value as a floating point number and print
+using typical floating point syntax.
+@@end table
+
+For example, to print the program counter in hex (@@pxref{Registers}), type
+
+@@example
+p/x $pc
+@@end example
+
+@@noindent
+Note that no space is required before the slash; this is because command
+names in GDB cannot contain a slash.
+
+To reprint the last value in the value history with a different format,
+you can use the @@samp{print} command with just a format and no
+expression. For example, @@samp{p/x} reprints the last value in hex.
+
+@@node Memory, Auto Display, Formats, Data
+@@subsection Examining Memory
+
+@@cindex examining memory
+@@kindex x
+The command @@samp{x} (for `examine') can be used to examine memory under
+explicit control of formats, without reference to the program's data types.
+
+@@samp{x} is followed by a slash and an output format specification,
+followed by an expression for an address. The expression need not have
+a pointer value (though it may); it is used as an integer, as the
+address of a byte of memory. @@xref{Expressions} for more information
+on expressions.
+
+The output format in this case specifies both how big a unit of memory
+to examine and how to print the contents of that unit. It is done
+with one or two of the following letters:
+
+These letters specify just the size of unit to examine:
+
+@@table @@samp
+@@item b
+Examine individual bytes.
+
+@@item h
+Examine halfwords (two bytes each).
+
+@@item w
+Examine words (four bytes each).
+
+@@cindex word
+Many assemblers and cpu designers still use `word' for a 16-bit quantity,
+as a holdover from specific predecessor machines of the 1970's that really
+did use two-byte words. But more generally the term `word' has always
+referred to the size of quantity that a machine normally operates on and
+stores in its registers. This is 32 bits for all the machines that GNU
+runs on.
+
+@@item g
+Examine giant words (8 bytes).
+@@end table
+
+These letters specify just the way to print the contents:
+
+@@table @@samp
+@@item x
+Print as integers in unsigned hexadecimal.
+
+@@item d
+Print as integers in signed decimal.
+
+@@item u
+Print as integers in unsigned decimal.
+
+@@item o
+Print as integers in unsigned octal.
+
+@@item a
+Print as an address, both absolute in hex and then relative
+to a symbol defined as an address below it.
+
+@@item c
+Print as character constants.
+
+@@item f
+Print as floating point. This works only with sizes @@samp{w} and
+@@samp{g}.
+
+@@item s
+Print a null-terminated string of characters. The specified unit size
+is ignored; instead, the unit is however many bytes it takes to reach
+a null character (including the null character).
+
+@@item i
+Print a machine instruction in assembler syntax (or nearly). The
+specified unit size is ignored; the number of bytes in an instruction
+varies depending on the type of machine, the opcode and the addressing
+modes used.
+@@end table
+
+If either the manner of printing or the size of unit fails to be specified,
+the default is to use the same one that was used last. If you don't want
+to use any letters after the slash, you can omit the slash as well.
+
+You can also omit the address to examine. Then the address used is
+just after the last unit examined. This is why string and instruction
+formats actually compute a unit-size based on the data: so that the
+next string or instruction examined will start in the right place.
+The @@samp{print} command sometimes sets the default address for
+the @@samp{x} command; when the value printed resides in memory, the
+default is set to examine the same location. @@samp{info line} also
+sets the default for @@samp{x}, to the address of the start of the
+machine code for the specified line and @@samp{info breakpoints} sets
+it to the address of the last breakpoint listed.
+
+When you use @@key{RET} to repeat an @@samp{x} command, it does not repeat
+exactly the same: the address specified previously (if any) is ignored, so
+that the repeated command examines the successive locations in memory
+rather than the same ones.
+
+You can examine several consecutive units of memory with one command by
+writing a repeat-count after the slash (before the format letters, if any).
+The repeat count must be a decimal integer. It has the same effect as
+repeating the @@samp{x} command that many times except that the output may
+be more compact with several units per line.
+
+@@example
+x/10i $pc
+@@end example
+
+@@noindent
+Prints ten instructions starting with the one to be executed next in the
+selected frame. After doing this, you could print another ten following
+instructions with
+
+@@example
+x/10
+@@end example
+
+@@noindent
+in which the format and address are allowed to default.
+
+@@kindex $_
+@@kindex $__
+The addresses and contents printed by the @@samp{x} command are not put in
+the value history because there is often too much of them and they would
+get in the way. Instead, GDB makes these values available for subsequent
+use in expressions as values of the convenience variables @@samp{$_} and
+@@samp{$__}.
+
+After an @@samp{x} command, the last address examined is available for use
+in expressions in the convenience variable @@samp{$_}. The contents of that
+address, as examined, are available in the convenience variable @@samp{$__}.
+
+If the @@samp{x} command has a repeat count, the address and contents saved
+are from the last memory unit printed; this is not the same as the last
+address printed if several units were printed on the last line of output.
+
+@@node Auto Display, Value History, Memory, Data
+@@section Automatic Display
+
+If you find that you want to print the value of an expression frequently
+(to see how it changes), you might want to add it to the @@dfn{automatic
+display list} so that GDB will print its value each time the program stops.
+Each expression added to the list is given a number to identify it;
+to remove an expression from the list, you specify that number.
+The automatic display looks like this:
+
+@@example
+2: foo = 38
+3: bar[5] = (struct hack *) 0x3804
+@@end example
+
+@@noindent
+showing item numbers, expressions and their current values.
+
+@@table @@code
+@@item display @@var{exp}
+@@kindex display
+Add the expression @@var{exp} to the list of expressions to display
+each time the program stops. @@xref{Expressions}.
+
+@@item display/@@var{fmt} @@var{exp}
+For @@var{fmt} specifying only a display format and not a size or
+count, add the expression @@var{exp} to the auto-display list but
+arranges to display it each time in the specified format @@var{fmt}.
+
+@@item display/@@var{fmt} @@var{addr}
+For @@var{fmt} @@samp{i} or @@samp{s}, or including a unit-size or a
+number of units, add the expression @@var{addr} as a memory address to
+be examined each time the program stops. Examining means in effect
+doing @@samp{x/@@var{fmt} @@var{addr}}. @@xref{Memory}.
+
+@@item undisplay @@var{dnums}@@dots{}
+@@kindex undisplay
+@@item delete display @@var{dnums}@@dots{}
+@@kindex delete display
+Remove item numbers @@var{dnums} from the list of expressions to display.
+
+@@item disable display @@var{dnums}@@dots{}
+@@kindex disable display
+Disable the display of item numbers @@var{dnums}. A disabled display item
+has no effect but is not forgotten. It may be later enabled.
+
+@@item enable display @@var{dnums}@@dots{}
+@@kindex enable display
+Enable display of item numbers @@var{dnums}. It becomes effective once
+again in auto display of its expression, until you specify otherwise.
+
+@@item display
+Display the current values of the expressions on the list, just as is
+done when the program stops.
+
+@@item info display
+@@kindex info display
+Print the list of expressions to display automatically, each one
+with its item number, but without showing the values.
+@@end table
+
+@@node Value History, Convenience Vars, Auto Display, Data
+@@section Value History
+
+@@cindex value history
+Every value printed by the @@samp{print} command is saved for the entire
+session in GDB's @@dfn{value history} so that you can refer to it in
+other expressions.
+
+@@cindex $
+@@cindex $$
+The values printed are given @@dfn{history numbers} for you to refer to them
+by. These are successive integers starting with 1. @@samp{print} shows you
+the history number assigned to a value by printing @@samp{$@@var{n} = }
+before the value; here @@var{n} is the history number.
+
+To refer to any previous value, use @@samp{$} followed by the value's
+history number. The output printed by @@samp{print} is designed to remind
+you of this. Just @@samp{$} refers to the most recent value in the history,
+and @@samp{$$} refers to the value before that.
+
+For example, suppose you have just printed a pointer to a structure and
+want to see the contents of the structure. It suffices to type
+
+@@example
+p *$
+@@end example
+
+If you have a chain of structures where the component @@samp{next} points
+to the next one, you can print the contents of the next one with
+
+@@example
+p *$.next
+@@end example
+
+It might be useful to repeat this command many times by typing @@key{RET}.
+
+Note that the history records values, not expressions. If the value of
+@@code{x} is 4 and you type
+
+@@example
+print x
+set x=5
+@@end example
+
+@@noindent
+then the value recorded in the value history by the @@samp{print} command
+remains 4 even though @@code{x}'s value has changed.
+
+@@table @@code
+@@item info history
+@@kindex info history
+Print the last ten values in the value history, with their item
+numbers. This is like @@samp{p $$9} repeated ten times, except that
+@@samp{info history} does not change the history.
+
+@@item info history @@var{n}
+Print ten history values centered on history item number @@var{n}.
+@@end table
+
+@@node Convenience Vars, Registers, Value History, Data
+@@section Convenience Variables
+
+@@cindex convenience variables
+GDB provides @@dfn{convenience variables} that you can use within GDB to
+hold on to a value and refer to it later. These variables exist entirely
+within GDB; they are not part of your program, and setting a convenience
+variable has no effect on further execution of your program. That's why
+you can use them freely.
+
+Convenience variables have names starting with @@samp{$}. Any name starting
+with @@samp{$} can be used for a convenience variable, unless it is one of
+the predefined set of register names (@@pxref{Registers}).
+
+You can save a value in a convenience variable with an assignment
+expression, just as you would set a variable in your program. Example:
+
+@@example
+set $foo = *object_ptr
+@@end example
+
+@@noindent
+would save in @@samp{$foo} the value contained in the object pointed to by
+@@code{object_ptr}.
+
+Using a convenience variable for the first time creates it; but its value
+is @@code{void} until you assign a new value. You can alter the value with
+another assignment at any time.
+
+Convenience variables have no fixed types. You can assign a convenience
+variable any type of value, even if it already has a value of a different
+type. The convenience variable as an expression has whatever type its
+current value has.
+
+@@table @@code
+@@item info convenience
+@@kindex info convenience
+Print a list of convenience variables used so far, and their values.
+Abbreviated @@samp{i con}.
+@@end table
+
+One of the ways to use a convenience variable is as a counter to be
+incremented or a pointer to be advanced. For example:
+
+@@example
+set $i = 0
+print bar[$i++]->contents
+@@i{@@dots{}repeat that command by typing @@key{RET}.}
+@@end example
+
+Some convenience variables are created automatically by GDB and given
+values likely to be useful.
+
+@@table @@samp
+@@item $_
+The variable @@samp{$_} is automatically set by the @@samp{x} command to
+the last address examined (@@pxref{Memory}). Other commands which
+provide a default address for @@samp{x} to examine also set @@samp{$_}
+to that address; these commands include @@samp{info line} and @@samp{info
+breakpoint}.
+
+@@item $__
+The variable @@samp{$__} is automatically set by the @@samp{x} command
+to the value found in the last address examined.
+@@end table
+
+@@node Registers,, Convenience Vars, Data
+@@section Registers
+
+@@cindex registers
+Machine register contents can be referred to in expressions as variables
+with names starting with @@samp{$}. The names of registers are different
+for each machine; use @@samp{info registers} to see the names used on your
+machine. The names @@samp{$pc} and @@samp{$sp} are used on all machines for
+the program counter register and the stack pointer. Often @@samp{$fp} is
+used for a register that contains a pointer to the current stack frame.
+
+GDB always considers the contents of an ordinary register as an integer
+when the register is examined in this way. Some machines have special
+registers which can hold nothing but floating point; these registers are
+considered floating point. There is no way to refer to the contents of an
+ordinary register as floating point value (although you can @@emph{print}
+it as a floating point value with @@samp{print/f $@@var{regname}}).
+
+Some registers have distinct ``raw'' and ``virtual'' data formats. This
+means that the data format in which the register contents are saved by the
+operating system is not the same one that your program normally sees. For
+example, the registers of the 68881 floating point coprocessor are always
+saved in ``extended'' format, but virtually all C programs expect to work with
+``double'' format. In such cases, GDB normally works with the virtual
+format only (the format that makes sense for your program), but the
+@@samp{info registers} command prints the data in both formats.
+
+Register values are relative to the selected stack frame
+(@@pxref{Selection}). This means that you get the value that the register
+would contain if all stack frames farther in were exited and their saved
+registers restored. In order to see the real contents of all registers,
+you must select the innermost frame (with @@samp{frame 0}).
+
+Some registers are never saved (typically those numbered zero or one)
+because they are used for returning function values; for these registers,
+relativization makes no difference.
+
+@@table @@code
+@@item info registers
+@@kindex info registers
+Print the names and relativized values of all registers.
+
+@@item info registers @@var{regname}
+Print the relativized value of register @@var{regname}. @@var{regname}
+may be any register name valid on the machine you are using, with
+or without the initial @@samp{$}.
+@@end table
+
+@@subsection Examples
+
+You could print the program counter in hex with
+
+@@example
+p/x $pc
+@@end example
+
+@@noindent
+or print the instruction to be executed next with
+
+@@example
+x/i $pc
+@@end example
+
+@@noindent
+or add four to the stack pointer with
+
+@@example
+set $sp += 4
+@@end example
+
+@@noindent
+The last is a way of removing one word from the stack, on machines where
+stacks grow downward in memory (most machines, nowadays). This assumes
+that the innermost stack frame is selected. Setting @@samp{$sp} is
+not allowed when other stack frames are selected.
+
+@@node Symbols, Altering, Data, Top
+@@chapter Examining the Symbol Table
+
+The commands described in this section allow you to make inquiries for
+information about the symbols (names of variables, functions and types)
+defined in your program. This information is found by GDB in the symbol
+table loaded by the @@samp{symbol-file} command; it is inherent in the text
+of your program and does not change as the program executes.
+
+@@table @@code
+@@item whatis @@var{exp}
+@@kindex whatis
+Print the data type of expression @@var{exp}. @@var{exp} is not
+actually evaluated, and any side-effecting operations (such as
+assignments or function calls) inside it do not take place.
+@@xref{Expressions}.
+
+@@item whatis
+Print the data type of @@samp{$}, the last value in the value history.
+
+@@item info address @@var{symbol}
+@@kindex info address
+Describe where the data for @@var{symbol} is stored. For register
+variables, this says which register. For other automatic variables,
+this prints the stack-frame offset at which the variable is always
+stored. Note the contrast with @@samp{print &@@var{symbol}}, which does
+not work at all for register variables and for automatic variables
+prints the exact address of the current instantiation of the variable.
+
+@@item ptype @@var{typename}
+@@kindex ptype
+Print a description of data type @@var{typename}. @@var{typename} may be
+the name of a type, or for C code it may have the form
+@@samp{struct @@var{struct-tag}}, @@samp{union @@var{union-tag}} or
+@@samp{enum @@var{enum-tag}}.@@refill
+
+@@item info sources
+@@kindex info sources
+Print the names of all source files in the program for which there
+is debugging information.
+
+@@item info functions
+@@kindex info functions
+Print the names and data types of all defined functions.
+
+@@item info functions @@var{regexp}
+Print the names and data types of all defined functions
+whose names contain a match for regular expression @@var{regexp}.
+Thus, @@samp{info fun step} finds all functions whose names
+include @@samp{step}; @@samp{info fun ^step} finds those whose names
+start with @@samp{step}.
+
+@@item info variables
+@@kindex info variables
+Print the names and data types of all variables that are declared
+outside of functions.
+
+@@item info variables @@var{regexp}
+Print the names and data types of all variables, declared outside of
+functions, whose names contain a match for regular expression
+@@var{regexp}.
+
+@@item info types
+@@kindex info types
+Print all data types that are defined in the program.
+
+@@item info types @@var{regexp}
+Print all data types that are defined in the program whose names
+contain a match for regular expression @@var{regexp}.
+
+@@item info methods
+@@item info methods @@var{regexp}
+@@kindex info methods
+The @@samp{info-methods} command permits the user to examine all defined
+methods within C@@code{++} program, or (with the @@var{regexp} argument) a
+specific set of methods found in the various C@@code{++} classes. Many
+C@@code{++} classes which implement a large number of differently typed
+methods implement a large number of methods as well. Thus, the
+@@samp{ptype} command can give the user a tremendous overdose of
+information about what methods are associated with a given class. The
+@@samp{info-methods} command filters these methods do to only those
+methods which match the regular-expression search key.
+
+@@item printsyms @@var{filename}
+@@kindex printsyms
+Write a complete dump of the debugger's symbol data into the
+file @@var{filename}.
+@@end table
+
+@@node Altering, Sequences, Symbols, Top
+@@chapter Altering Execution
+
+There are several ways to alter the execution of your program with GDB
+commands.
+
+@@menu
+* Assignment:: Altering variable values or memory contents.
+* Jumping:: Altering control flow.
+* Signaling:: Making signals happen in the program.
+* Returning:: Making a function return prematurely.
+@@end menu
+
+@@node Assignment, Jumping, Altering, Altering
+@@section Assignment to Variables
+
+@@cindex assignment
+@@cindex setting variables
+To alter the value of a variable, evaluate an assignment expression.
+@@xref{Expressions}. For example,
+
+@@example
+print x=4
+@@end example
+
+@@noindent
+would store the value 4 into the variable @@code{x}, and then print
+the value of the assignment expression (which is 4).
+
+@@kindex set
+@@kindex set variable
+If you are not interested in seeing the value of the assignment, use the
+@@samp{set} command instead of the @@samp{print} command. @@samp{set} is
+really the same as @@samp{print} except that the expression's value is not
+printed and is not put in the value history (@@pxref{Value History}). The
+expression is evaluated only for side effects.
+
+Note that if the beginning of the argument string of the @@samp{set} command
+appears identical to a @@samp{set} subcommand, it may be necessary to use
+the @@samp{set variable} command. This command is identical to @@samp{set}
+except for its lack of subcommands.
+
+GDB allows more implicit conversions in assignments than C does; you can
+freely store an integer value into a pointer variable or vice versa, and
+any structure can be converted to any other structure that is the same
+length or shorter.
+
+In C, all the other assignment operators such as @@samp{+=} and @@samp{++}
+are supported as well.
+
+To store into arbitrary places in memory, use the @@samp{@@{@@dots{}@@}}
+construct to generate a value of specified type at a specified address
+(@@pxref{Expressions}). For example,
+
+@@example
+set @@{int@@}0x83040 = 4
+@@end example
+
+@@node Jumping, Signaling, Assignment, Altering
+@@section Continuing at a Different Address
+
+@@table @@code
+@@item jump @@var{linenum}
+@@kindex jump
+Resume execution at line number @@var{linenum}. Execution may stop
+immediately if there is a breakpoint there.
+
+The @@samp{jump} command does not change the current stack frame, or
+the stack pointer, or the contents of any memory location or any
+register other than the program counter. If line @@var{linenum} is in
+a different function from the one currently executing, the results may
+be wild if the two functions expect different patterns of arguments or
+of local variables. For this reason, the @@samp{jump} command requests
+confirmation if the specified line is not in the function currently
+executing. However, even wild results are predictable based on
+changing the program counter.
+
+@@item jump *@@var{address}
+Resume execution at the instruction at address @@var{address}.
+@@end table
+
+A similar effect can be obtained by storing a new value into the register
+@@samp{$pc}, but not exactly the same.
+
+@@example
+set $pc = 0x485
+@@end example
+
+@@noindent
+specifies the address at which execution will resume, but does not resume
+execution. That does not happen until you use the @@samp{cont} command or a
+stepping command (@@pxref{Stepping}).
+
+@@node Signaling, Returning, Jumping, Altering
+@@section Giving the Program a Signal
+
+@@table @@code
+@@item signal @@var{signalnum}
+@@kindex signal
+Resume execution where the program stopped, but give it immediately
+the signal number @@var{signalnum}.
+
+Alternatively, if @@var{signalnum} is zero, continue execution and give
+no signal. This is useful when the program has received a signal
+but you don't want the program to see that signal; the @@samp{cont} command
+would signal the program.
+@@end table
+
+@@node Returning,, Signaling, Altering
+@@section Returning from a Function
+
+@@cindex returning from a function
+@@kindex return
+You can make any function call return immediately, using the @@samp{return}
+command.
+
+First select the stack frame that you wish to return from
+(@@pxref{Selection}). Then type the @@samp{return} command. If you wish to
+specify the value to be returned, give that as an argument.
+
+This pops the selected stack frame (and any other frames inside of it),
+leaving its caller as the innermost remaining frame. That frame becomes
+selected. The specified value is stored in the registers used for
+returning values of functions.
+
+The @@samp{return} command does not resume execution; it leaves the program
+stopped in the state that would exist if the function had just returned.
+Contrast this with the @@samp{finish} command (@@pxref{Stepping}), which
+resumes execution @@i{until} the selected stack frame returns naturally.
+
+@@node Sequences, Emacs, Altering, Top
+@@chapter Canned Sequences of Commands
+
+GDB provides two ways to store sequences of commands for execution as a
+unit: user-defined commands and command files.
+
+@@menu
+* Define:: User-defined commands.
+* Command Files:: Command files.
+* Output:: Controlled output commands useful in
+ user-defined commands and command files.
+@@end menu
+
+@@node Define, Command Files, Sequences, Sequences
+@@section User-Defined Commands
+
+@@cindex user-defined commands
+A @@dfn{user-defined command} is a sequence of GDB commands to which you
+assign a new name as a command. This is done with the @@samp{define}
+command.
+
+@@table @@code
+@@item define @@var{commandname}
+@@kindex define
+Define a command named @@var{commandname}. If there is already a command
+by that name, you are asked to confirm that you want to redefine it.
+
+The definition of the command is made up of other GDB command lines,
+which are given following the @@samp{define} command. The end of these
+commands is marked by a line containing @@samp{end}.
+
+@@item document @@var{commandname}
+@@kindex document
+Give documentation to the user-defined command @@var{commandname}. The
+command @@var{commandname} must already be defined. This command reads
+lines of documentation just as @@samp{define} reads the lines of the
+command definition, ending with @@samp{end}. After the @@samp{document} command is finished,
+@@samp{help} on command @@var{commandname} will print the documentation
+you have specified.
+
+You may use the @@samp{document} command again to change the
+documentation of a command. Redefining the command with @@samp{define}
+does not change the documentation.
+@@end table
+
+User-defined commands do not take arguments. When they are executed, the
+commands of the definition are not printed. An error in any command
+stops execution of the user-defined command.
+
+Commands that would ask for confirmation if used interactively proceed
+without asking when used inside a user-defined command. Many GDB commands
+that normally print messages to say what they are doing omit the messages
+when used in user-defined command.
+
+@@node Command Files, Output, Define, Sequences
+@@section Command Files
+
+@@cindex command files
+A command file for GDB is a file of lines that are GDB commands. Comments
+(lines starting with @@samp{#}) may also be included. An empty line in a
+command file does nothing; it does not mean to repeat the last command, as
+it would from the terminal.
+
+@@cindex init file
+@@cindex .gdbinit
+When GDB starts, it automatically executes its @@dfn{init files}, command
+files named @@file{.gdbinit}. GDB reads the init file (if any) in your home
+directory and then the init file (if any) in the current working
+directory. (The init files are not executed if the @@samp{-nx} option
+is given.) You can also request the execution of a command file with the
+@@samp{source} command:
+
+@@table @@code
+@@item source @@var{filename}
+@@kindex source
+Execute the command file @@var{filename}.
+@@end table
+
+The lines in a command file are executed sequentially. They are not
+printed as they are executed. An error in any command terminates execution
+of the command file.
+
+Commands that would ask for confirmation if used interactively proceed
+without asking when used in a command file. Many GDB commands that
+normally print messages to say what they are doing omit the messages
+when used in a command file.
+
+@@node Output,, Command Files, Sequences
+@@section Commands for Controlled Output
+
+During the execution of a command file or a user-defined command, the only
+output that appears is what is explicitly printed by the commands of the
+definition. This section describes three commands useful for generating
+exactly the output you want.
+
+@@table @@code
+@@item echo @@var{text}
+@@kindex echo
+Print @@var{text}. Nonprinting characters can be included in
+@@var{text} using C escape sequences, such as @@samp{\n} to print a
+newline. @@b{No newline will be printed unless you specify one.}
+
+A backslash at the end of @@var{text} is ignored. It is useful for
+outputting a string ending in spaces, since trailing spaces are
+trimmed from all arguments. A backslash at the beginning preserves
+leading spaces in the same way, because @@samp{\ } as an escape
+sequence stands for a space. Thus, to print @@samp{ and foo = }, do
+
+@@example
+echo \ and foo = \
+@@end example
+
+@@item output @@var{expression}
+@@kindex output
+Print the value of @@var{expression} and nothing but that value: no
+newlines, no @@samp{$@@var{nn} = }. The value is not entered in the
+value history either. @@xref{Expressions} for more information
+on expressions.
+
+@@item output/@@var{fmt} @@var{expression}
+Print the value of @@var{expression} in format @@var{fmt}.
+@@xref{Formats}, for more information.
+
+@@item printf @@var{string}, @@var{expressions}@@dots{}
+@@kindex printf
+Print the values of the @@var{expressions} under the control of
+@@var{string}. The @@var{expressions} are separated by commas and may
+be either numbers or pointers. Their values are printed as specified
+by @@var{string}, exactly as if the program were to execute
+
+@@example
+printf (@@var{string}, @@var{expressions}@@dots{});
+@@end example
+
+For example, you can print two values in hex like this:
+
+@@example
+printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo
+@@end example
+
+The only backslash-escape sequences that you can use in the string are
+the simple ones that consist of backslash followed by a letter.
+@@end table
+
+@@node Emacs, Remote, Sequences, Top
+@@chapter Using GDB under GNU Emacs
+
+A special interface allows you to use GNU Emacs to view (and
+edit) the source files for the program you are debugging with
+GDB.
+
+To use this interface, use the command @@kbd{M-x gdb} in Emacs.
+Give the executable file you want to debug as an argument. This
+command starts a GDB process as a subprocess of Emacs, with input
+and output through a newly created Emacs buffer.
+
+Using this GDB process is just like using GDB normally except for two things:
+
+@@itemize @@bullet
+@@item
+All ``terminal'' input and output goes through the Emacs buffer. This
+applies both to GDB commands and their output, and to the input and
+output done by the program you are debugging.
+
+This is useful because it means that you can copy the text of previous
+commands and input them again; you can even use parts of the output
+in this way.
+
+All the facilities of Emacs's Shell mode are available for this purpose.
+
+@@item
+GDB displays source code through Emacs. Each time GDB displays a
+stack frame, Emacs automatically finds the source file for that frame
+and puts an arrow (@@samp{=>}) at the left margin of the current line.
+
+Explicit GDB @@samp{list} or search commands still produce output as
+usual, but you probably will have no reason to use them.
+@@end itemize
+
+In the GDB I/O buffer, you can use these special Emacs commands:
+
+@@table @@kbd
+@@item M-s
+Execute to another source line, like the GDB @@samp{step} command.
+
+@@item M-n
+Execute to next source line in this function, skipping all function
+calls, like the GDB @@samp{next} command.
+
+@@item M-i
+Execute one instruction, like the GDB @@samp{stepi} command.
+
+@@item M-u
+Move up one stack frame (and display that frame's source file in
+Emacs), like the GDB @@samp{up} command.
+
+@@item M-d
+Move down one stack frame (and display that frame's source file in
+Emacs), like the GDB @@samp{down} command. (This means that you cannot
+delete words in the usual fashion in the GDB buffer; I am guessing you
+won't often want to do that.)
+
+@@item C-c C-f
+Execute until exit from the selected stack frame, like the GDB
+@@samp{finish} command.
+@@end table
+
+In any source file, the Emacs command @@kbd{C-x SPC} (@@code{gdb-break})
+tells GDB to set a breakpoint on the source line point is on.
+
+The source files displayed in Emacs are in ordinary Emacs buffers
+which are visiting the source files in the usual way. You can edit
+the files with these buffers if you wish; but keep in mind that GDB
+communicates with Emacs in terms of line numbers. If you add or
+delete lines from the text, the line numbers that GDB knows will cease
+to correspond properly to the code.
+
+@@node Remote, Commands, Emacs, Top
+@@chapter Remote Kernel Debugging
+
+GDB has a special facility for debugging a remote machine via a serial
+connection. This can be used for kernel debugging.
+
+The program to be debugged on the remote machine needs to contain a
+debugging device driver which talks to GDB over the serial line using the
+protocol described below. The same version of GDB that is used ordinarily
+can be used for this.
+
+@@menu
+* Remote Commands:: Commands used to start and finish remote debugging.
+@@end menu
+
+For details of the communication protocol, see the comments in the GDB
+source file @@file{remote.c}.
+
+@@node Remote Commands,, Remote, Remote
+@@section Commands for Remote Debugging
+
+To start remote debugging, first run GDB and specify as an executable file
+the program that is running in the remote machine. This tells GDB how
+to find the program's symbols and the contents of its pure text. Then
+establish communication using the @@samp{attach} command with a device
+name rather than a pid as an argument. For example:
+
+@@example
+attach /dev/ttyd
+@@end example
+
+@@noindent
+if the serial line is connected to the device named @@file{/dev/ttyd}. This
+will stop the remote machine if it is not already stopped.
+
+Now you can use all the usual commands to examine and change data and to
+step and continue the remote program.
+
+To resume the remote program and stop debugging it, use the @@samp{detach}
+command.
+
+@@node Commands, Concepts, Remote, Top
+@@unnumbered Command Index
+
+@@printindex ky
+
+@@node Concepts,, Commands, Top
+@@unnumbered Concept Index
+
+@@printindex cp
+
+@@contents
+@@bye
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d617 3
+a619 2
+inferior. If you wish to evaluate a function simply for it's side
+affects, you may use the @@samp{set} command. @@xref{Assignment}.
+d1101 4
+a1104 3
+A condition is just a boolean expression in your programming language.
+A breakpoint with a condition evaluates the expression each time the
+program reaches it, and the program stops only if the condition is true.
+d1126 1
+d1259 6
+a1264 5
+is a condition expression that will change @@code{x} as needed, then always
+have the value 0 so the program will not stop. Loss of input is avoided
+here because break conditions are evaluated without changing the terminal
+modes. When you want to have nontrivial conditions for performing the side
+effects, the operators @@samp{&&}, @@samp{||} and @@samp{?@@: @@dots{} :@@:} may be useful.
+d1269 3
+a1271 3
+Under Unix, breakpoints cannot be used in a program if any other process
+is running that program. Attempting to run or continue the program with
+a breakpoint in this case will cause GDB to stop it.
+d1875 2
+d2047 2
+a2048 1
+address of a byte of memory.
+d2196 1
+a2196 1
+each time the program stops.
+d2382 1
+a2382 1
+saved in ``extended'' format, but all C programs expect to work with
+d2451 1
+d2544 1
+a2544 1
+For example,
+d2628 3
+a2630 3
+no signal. This may be useful when the program has received a signal
+and the @@samp{cont} command would allow the program to see that
+signal.
+d2691 1
+a2691 1
+command definition. After the @@samp{document} command is finished,
+d2771 2
+a2772 1
+value history either.
+@
diff --git a/gdb/RCS/gdbcore.h,v b/gdb/RCS/gdbcore.h,v
new file mode 100644
index 0000000..872e5af9
--- /dev/null
+++ b/gdb/RCS/gdbcore.h,v
@@ -0,0 +1,105 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.02.09.23.23.12; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.09.22.43.14; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Create gdbcore.h with external variables that relate to core files.
+@
+text
+@/* Machine independent variables that describe the core file under GDB.
+ Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+/* File names of core file and executable file. */
+
+extern char *corefile;
+extern char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+extern int corechan;
+extern int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+extern int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+extern CORE_ADDR data_start;
+extern CORE_ADDR data_end;
+extern CORE_ADDR stack_start;
+extern CORE_ADDR stack_end;
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+extern CORE_ADDR text_start;
+extern CORE_ADDR text_end;
+
+extern CORE_ADDR exec_data_start;
+extern CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+extern int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+extern int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+extern int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+extern int stack_offset;
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d1 68
+@
diff --git a/gdb/RCS/inflow.c,v b/gdb/RCS/inflow.c,v
new file mode 100644
index 0000000..972b615
--- /dev/null
+++ b/gdb/RCS/inflow.c,v
@@ -0,0 +1,636 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.3
+date 89.03.27.20.12.35; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.02.09.23.23.40; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.09.22.28.04; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@General portability changes. Make various local terminal control
+parameter processing #ifdef the particular IOCTL used to get them.
+This handles various Sys V/Berkeley merges. Also avoid vfork
+and <sys/fcntl.h>.
+@
+text
+@/* Low level interface to ptrace, for GDB when running under Unix.
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+
+#ifdef HAVE_TERMIO
+#include <termio.h>
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+#else
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sgtty.h>
+#define TERMINAL struct sgttyb
+#endif
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+extern int original_stack_limit;
+#endif /* SET_STACK_LIMIT_HUGE */
+
+extern int errno;
+
+/* Nonzero if we are debugging an attached outside process
+ rather than an inferior. */
+
+int attach_flag;
+
+
+/* Record terminal status separately for debugger and inferior. */
+
+static TERMINAL sg_inferior;
+static TERMINAL sg_ours;
+
+static int tflags_inferior;
+static int tflags_ours;
+
+#ifdef TIOCGETC
+static struct tchars tc_inferior;
+static struct tchars tc_ours;
+#endif
+
+#ifdef TIOCGLTC
+static struct ltchars ltc_inferior;
+static struct ltchars ltc_ours;
+#endif /* TIOCGLTC */
+
+#ifdef TIOCLGET
+static int lmode_inferior;
+static int lmode_ours;
+#endif
+
+#ifdef TIOCGPGRP
+static int pgrp_inferior;
+static int pgrp_ours;
+#else
+static int (*sigint_ours) ();
+static int (*sigquit_ours) ();
+#endif /* TIOCGPGRP */
+
+/* Copy of inferior_io_terminal when inferior was last started. */
+static char *inferior_thisrun_terminal;
+
+static void terminal_ours_1 ();
+
+/* Nonzero if our terminal settings are in effect.
+ Zero if the inferior's settings are in effect. */
+static int terminal_is_ours;
+
+/* Initialize the terminal settings we record for the inferior,
+ before we actually run the inferior. */
+
+void
+terminal_init_inferior ()
+{
+ if (remote_debugging)
+ return;
+
+ sg_inferior = sg_ours;
+ tflags_inferior = tflags_ours;
+
+#ifdef TIOCGETC
+ tc_inferior = tc_ours;
+#endif
+
+#ifdef TIOCGLTC
+ ltc_inferior = ltc_ours;
+#endif
+
+#ifdef TIOCLGET
+ lmode_inferior = lmode_ours;
+#endif
+
+#ifdef TIOCGPGRP
+ pgrp_inferior = inferior_pid;
+#endif /* TIOCGPGRP */
+
+ terminal_is_ours = 1;
+}
+
+/* Put the inferior's terminal settings into effect.
+ This is preparation for starting or resuming the inferior. */
+
+void
+terminal_inferior ()
+{
+ if (remote_debugging)
+ return;
+
+ if (terminal_is_ours) /* && inferior_thisrun_terminal == 0) */
+ {
+ fcntl (0, F_SETFL, tflags_inferior);
+ fcntl (0, F_SETFL, tflags_inferior);
+ ioctl (0, TIOCSETN, &sg_inferior);
+#ifdef TIOCGETC
+ ioctl (0, TIOCSETC, &tc_inferior);
+#endif
+#ifdef TIOCGLTC
+ ioctl (0, TIOCSLTC, &ltc_inferior);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLSET, &lmode_inferior);
+#endif
+
+#ifdef TIOCGPGRP
+ ioctl (0, TIOCSPGRP, &pgrp_inferior);
+#else
+ sigint_ours = (int (*) ()) signal (SIGINT, SIG_IGN);
+ sigquit_ours = (int (*) ()) signal (SIGQUIT, SIG_IGN);
+#endif /* TIOCGPGRP */
+ }
+ terminal_is_ours = 0;
+}
+
+/* Put some of our terminal settings into effect,
+ enough to get proper results from our output,
+ but do not change into or out of RAW mode
+ so that no input is discarded.
+
+ After doing this, either terminal_ours or terminal_inferior
+ should be called to get back to a normal state of affairs. */
+
+void
+terminal_ours_for_output ()
+{
+ if (remote_debugging)
+ return;
+
+ terminal_ours_1 (1);
+}
+
+/* Put our terminal settings into effect.
+ First record the inferior's terminal settings
+ so they can be restored properly later. */
+
+void
+terminal_ours ()
+{
+ if (remote_debugging)
+ return;
+
+ terminal_ours_1 (0);
+}
+
+static void
+terminal_ours_1 (output_only)
+ int output_only;
+{
+#ifdef TIOCGPGRP
+ /* Ignore this signal since it will happen when we try to set the pgrp. */
+ int (*osigttou) ();
+#endif /* TIOCGPGRP */
+
+ if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */
+ {
+ terminal_is_ours = 1;
+
+#ifdef TIOCGPGRP
+ osigttou = signal (SIGTTOU, SIG_IGN);
+
+ ioctl (0, TIOCGPGRP, &pgrp_inferior);
+ ioctl (0, TIOCSPGRP, &pgrp_ours);
+
+ signal (SIGTTOU, osigttou);
+#else
+ signal (SIGINT, sigint_ours);
+ signal (SIGQUIT, sigquit_ours);
+#endif /* TIOCGPGRP */
+
+ tflags_inferior = fcntl (0, F_GETFL, 0);
+ ioctl (0, TIOCGETP, &sg_inferior);
+
+#ifdef TIOCGETC
+ ioctl (0, TIOCGETC, &tc_inferior);
+#endif
+#ifdef TIOCGLTC
+ ioctl (0, TIOCGLTC, &ltc_inferior);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLGET, &lmode_inferior);
+#endif
+ }
+
+#ifdef HAVE_TERMIO
+ sg_ours.c_lflag |= ICANON;
+ if (output_only && !(sg_inferior.c_lflag & ICANON))
+ sg_ours.c_lflag &= ~ICANON;
+#else /* not HAVE_TERMIO */
+ sg_ours.sg_flags &= ~RAW & ~CBREAK;
+ if (output_only)
+ sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags;
+#endif /* not HAVE_TERMIO */
+
+ fcntl (0, F_SETFL, tflags_ours);
+ fcntl (0, F_SETFL, tflags_ours);
+ ioctl (0, TIOCSETN, &sg_ours);
+
+#ifdef TIOCGETC
+ ioctl (0, TIOCSETC, &tc_ours);
+#endif
+#ifdef TIOCGLTC
+ ioctl (0, TIOCSLTC, &ltc_ours);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLSET, &lmode_ours);
+#endif
+
+
+#ifdef HAVE_TERMIO
+ sg_ours.c_lflag |= ICANON;
+#else /* not HAVE_TERMIO */
+ sg_ours.sg_flags &= ~RAW & ~CBREAK;
+#endif /* not HAVE_TERMIO */
+}
+
+static void
+term_status_command ()
+{
+ register int i;
+
+ if (remote_debugging)
+ {
+ printf ("No terminal status when remote debugging.\n");
+ return;
+ }
+
+ printf ("Inferior's terminal status (currently saved by GDB):\n");
+
+#ifdef HAVE_TERMIO
+
+ printf ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n",
+ tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag);
+ printf ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n",
+ sg_inferior.c_cflag, sg_inferior.c_lflag, sg_inferior.c_line);
+ printf ("c_cc: ");
+ for (i = 0; (i < NCC); i += 1)
+ printf ("0x%x ", sg_inferior.c_cc[i]);
+ printf ("\n");
+
+#else /* not HAVE_TERMIO */
+
+ printf ("fcntl flags = 0x%x, sgttyb.sg_flags = 0x%x, owner pid = %d.\n",
+ tflags_inferior, sg_inferior.sg_flags, pgrp_inferior);
+
+#endif /* not HAVE_TERMIO */
+
+#ifdef TIOCGETC
+ printf ("tchars: ");
+ for (i = 0; i < sizeof (struct tchars); i++)
+ printf ("0x%x ", ((char *)&tc_inferior)[i]);
+ printf ("\n");
+#endif
+
+#ifdef TIOCGLTC
+ printf ("ltchars: ");
+ for (i = 0; i < sizeof (struct ltchars); i++)
+ printf ("0x%x ", ((char *)&ltc_inferior)[i]);
+ printf ("\n");
+ ioctl (0, TIOCSLTC, &ltc_ours);
+#endif
+
+#ifdef TIOCLGET
+ printf ("lmode: %x\n", lmode_inferior);
+#endif
+}
+
+static void
+new_tty (ttyname)
+ char *ttyname;
+{
+ register int tty;
+ register int fd;
+
+#ifdef TIOCNOTTY
+ /* Disconnect the child process from our controlling terminal. */
+ tty = open("/dev/tty", O_RDWR);
+ if (tty > 0)
+ {
+ ioctl(tty, TIOCNOTTY, 0);
+ close(tty);
+ }
+#endif
+
+ /* Now open the specified new terminal. */
+
+ tty = open(ttyname, O_RDWR);
+ if (tty == -1)
+ _exit(1);
+
+ dup2(tty, 0);
+ dup2(tty, 1);
+ dup2(tty, 2);
+ close(tty);
+}
+
+/* Start an inferior process and returns its pid.
+ ALLARGS is a string containing shell command to run the program.
+ ENV is the environment vector to pass. */
+
+#ifndef SHELL_FILE
+#define SHELL_FILE "/bin/sh"
+#endif
+
+int
+create_inferior (allargs, env)
+ char *allargs;
+ char **env;
+{
+ int pid;
+ char *shell_command;
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int errno;
+
+ /* If desired, concat something onto the front of ALLARGS.
+ SHELL_COMMAND is the result. */
+#ifdef SHELL_COMMAND_CONCAT
+ shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + strlen (allargs) + 1);
+ strcpy (shell_command, SHELL_COMMAND_CONCAT);
+ strcat (shell_command, allargs);
+#else
+ shell_command = allargs;
+#endif
+
+ /* exec is said to fail if the executable is open. */
+ close_exec_file ();
+
+ pid = fork ();
+ if (pid < 0)
+ perror_with_name ("fork");
+
+ if (pid == 0)
+ {
+#ifdef TIOCGPGRP
+ /* Run inferior in a separate process group. */
+ setpgrp (getpid (), getpid ());
+#endif /* TIOCGPGRP */
+
+#ifdef SET_STACK_LIMIT_HUGE
+ /* Reset the stack limit back to what it was. */
+ {
+ struct rlimit rlim;
+
+ getrlimit (RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = original_stack_limit;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+
+ inferior_thisrun_terminal = inferior_io_terminal;
+ if (inferior_io_terminal != 0)
+ new_tty (inferior_io_terminal);
+
+/* Not needed on Sun, at least, and loses there
+ because it clobbers the superior. */
+/*??? signal (SIGQUIT, SIG_DFL);
+ signal (SIGINT, SIG_DFL); */
+
+ call_ptrace (0);
+ execle (SHELL_FILE, "sh", "-c", shell_command, 0, env);
+
+ fprintf (stderr, "Cannot exec %s: %s.\n", SHELL_FILE,
+ errno < sys_nerr ? sys_errlist[errno] : "unknown error");
+ fflush (stderr);
+ _exit (0177);
+ }
+ return pid;
+}
+
+/* Kill the inferior process. Make us have no inferior. */
+
+static void
+kill_command ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ error ("The program is not being run.");
+ if (!query ("Kill the inferior process? "))
+ error ("Not confirmed.");
+ kill_inferior ();
+}
+
+void
+inferior_died ()
+{
+ inferior_pid = 0;
+ attach_flag = 0;
+ mark_breakpoints_out ();
+ select_frame ( (FRAME) 0, -1);
+ reopen_exec_file ();
+ if (have_core_file_p ())
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+}
+
+static void
+try_writing_regs_command ()
+{
+ register int i;
+ register int value;
+ extern int errno;
+
+ if (inferior_pid == 0)
+ error ("There is no inferior process now.");
+
+ for (i = 0; ; i += 2)
+ {
+ QUIT;
+ errno = 0;
+ value = call_ptrace (3, inferior_pid, i, 0);
+ call_ptrace (6, inferior_pid, i, value);
+ if (errno == 0)
+ {
+ printf (" Succeeded with address 0x%x; value 0x%x (%d).\n",
+ i, value, value);
+ }
+ else if ((i & 0377) == 0)
+ printf (" Failed at 0x%x.\n", i);
+ }
+}
+
+void
+_initialize_inflow ()
+{
+ add_com ("term-status", class_obscure, term_status_command,
+ "Print info on inferior's saved terminal status.");
+
+ add_com ("try-writing-regs", class_obscure, try_writing_regs_command,
+ "Try writing all locations in inferior's system block.\n\
+Report which ones can be written.");
+
+ add_com ("kill", class_run, kill_command,
+ "Kill execution of program being debugged.");
+
+ inferior_pid = 0;
+
+ ioctl (0, TIOCGETP, &sg_ours);
+ fcntl (0, F_GETFL, tflags_ours);
+
+#ifdef TIOCGETC
+ ioctl (0, TIOCGETC, &tc_ours);
+#endif
+#ifdef TIOCGLTC
+ ioctl (0, TIOCGLTC, &ltc_ours);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLGET, &lmode_ours);
+#endif
+
+#ifdef TIOCGPGRP
+ ioctl (0, TIOCGPGRP, &pgrp_ours);
+#endif /* TIOCGPGRP */
+
+ terminal_is_ours = 1;
+}
+
+@
+
+
+1.2
+log
+@When the inferior process dies, deselect the current frame so that
+the "where" ("backtrace") command will not think there's a stack.
+@
+text
+@d27 1
+a27 1
+#include <sys/fcntl.h>
+a34 6
+/* May be unnecessary since many parts of inflow.c
+ have migrated to *-infdep.c */
+#ifdef USG
+#include <sys/user.h>
+#endif
+
+d73 1
+a73 1
+#ifdef TIOCGLTC
+d76 3
+d81 3
+d86 1
+a86 1
+#endif /* TIOCGLTC */
+d117 4
+a121 1
+ tc_inferior = tc_ours;
+d123 3
+d127 1
+a127 1
+#endif /* TIOCGLTC */
+d150 3
+a153 1
+ ioctl (0, TIOCSETC, &tc_inferior);
+d155 2
+d158 1
+a158 1
+#endif /* TIOCGLTC */
+d228 3
+a231 1
+ ioctl (0, TIOCGETC, &tc_inferior);
+d233 2
+d236 1
+a236 1
+#endif /* TIOCGLTC */
+d253 3
+a256 1
+ ioctl (0, TIOCSETC, &tc_ours);
+d258 2
+d261 1
+a261 1
+#endif /* TIOCGLTC */
+d297 6
+a302 3
+ printf ("fcntl flags = 0x%x, lmode = 0x%x,\nsgttyb.sg_flags = 0x%x, owner pid = %d.\n",
+ tflags_inferior, lmode_inferior,
+ sg_inferior.sg_flags, pgrp_inferior);
+d307 3
+d314 2
+d317 3
+a319 1
+#endif /* not HAVE_TERMIO */
+d383 1
+a383 1
+ pid = vfork ();
+d385 1
+a385 1
+ perror_with_name ("vfork");
+d497 3
+a500 1
+ ioctl (0, TIOCGETC, &tc_ours);
+d502 2
+d505 1
+a505 1
+#endif /* TIOCGLTC */
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d418 1
+@
diff --git a/gdb/RCS/infrun.c,v b/gdb/RCS/infrun.c,v
new file mode 100644
index 0000000..983922f
--- /dev/null
+++ b/gdb/RCS/infrun.c,v
@@ -0,0 +1,1855 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.3
+date 89.03.27.20.15.05; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.02.09.23.25.40; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.09.17.11.52; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@A/UX-specific change: define X_OK since Apple fucked it up.
+@
+text
+@/* Start and stop the inferior process, for GDB.
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+/* Notes on the algorithm used in wait_for_inferior to determine if we
+ just did a subroutine call when stepping. We have the following
+ information at that point:
+
+ Current and previous (just before this step) pc.
+ Current and previous sp.
+ Current and previous start of current function.
+
+ If the start's of the functions don't match, then
+
+ a) We did a subroutine call.
+
+ In this case, the pc will be at the beginning of a function.
+
+ b) We did a subroutine return.
+
+ Otherwise.
+
+ c) We did a longjmp.
+
+ If we did a longjump, we were doing "nexti", since a next would
+ have attempted to skip over the assembly language routine in which
+ the longjmp is coded and would have simply been the equivalent of a
+ continue. I consider this ok behaivior. We'd like one of two
+ things to happen if we are doing a nexti through the longjmp()
+ routine: 1) It behaves as a stepi, or 2) It acts like a continue as
+ above. Given that this is a special case, and that anybody who
+ thinks that the concept of sub calls is meaningful in the context
+ of a longjmp, I'll take either one. Let's see what happens.
+
+ Acts like a subroutine return. I can handle that with no problem
+ at all.
+
+ -->So: If the current and previous beginnings of the current
+ function don't match, *and* the pc is at the start of a function,
+ we've done a subroutine call. If the pc is not at the start of a
+ function, we *didn't* do a subroutine call.
+
+ -->If the beginnings of the current and previous function do match,
+ either:
+
+ a) We just did a recursive call.
+
+ In this case, we would be at the very beginning of a
+ function and 1) it will have a prologue (don't jump to
+ before prologue, or 2) (we assume here that it doesn't have
+ a prologue) there will have been a change in the stack
+ pointer over the last instruction. (Ie. it's got to put
+ the saved pc somewhere. The stack is the usual place. In
+ a recursive call a register is only an option if there's a
+ prologue to do something with it. This is even true on
+ register window machines; the prologue sets up the new
+ window. It might not be true on a register window machine
+ where the call instruction moved the register window
+ itself. Hmmm. One would hope that the stack pointer would
+ also change. If it doesn't, somebody send me a note, and
+ I'll work out a more general theory.
+ randy@@wheaties.ai.mit.edu). This is true (albeit slipperly
+ so) on all machines I'm aware of:
+
+ m68k: Call changes stack pointer. Regular jumps don't.
+
+ sparc: Recursive calls must have frames and therefor,
+ prologues.
+
+ vax: All calls have frames and hence change the
+ stack pointer.
+
+ b) We did a return from a recursive call. I don't see that we
+ have either the ability or the need to distinguish this
+ from an ordinary jump. The stack frame will be printed
+ when and if the frame pointer changes; if we are in a
+ function without a frame pointer, it's the users own
+ lookout.
+
+ c) We did a jump within a function. We assume that this is
+ true if we didn't do a recursive call.
+
+ d) We are in no-man's land ("I see no symbols here"). We
+ don't worry about this; it will make calls look like simple
+ jumps (and the stack frames will be printed when the frame
+ pointer moves), which is a reasonably non-violent response.
+
+#if 0
+ We skip this; it causes more problems than it's worth.
+#ifdef SUN4_COMPILER_FEATURE
+ We do a special ifdef for the sun 4, forcing it to single step
+ into calls which don't have prologues. This means that we can't
+ nexti over leaf nodes, we can probably next over them (since they
+ won't have debugging symbols, usually), and we can next out of
+ functions returning structures (with a "call .stret4" at the end).
+#endif
+#endif
+*/
+
+
+
+
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "wait.h"
+
+#include <stdio.h>
+#include <signal.h>
+
+/* unistd.h is needed to #define X_OK */
+#ifdef USG
+#include <unistd.h>
+#else
+#include <sys/file.h>
+#endif
+
+/* The idiots at Apple only define X_OK if POSIX is defined. Fuck 'em. */
+#ifndef X_OK
+#define X_OK 1 /* Execute permission for access() */
+#endif
+
+#ifdef UMAX_PTRACE
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#endif /* UMAX_PTRACE */
+
+extern char *sys_siglist[];
+extern int errno;
+
+/* Tables of how to react to signals; the user sets them. */
+
+static char signal_stop[NSIG];
+static char signal_print[NSIG];
+static char signal_program[NSIG];
+
+/* Nonzero if breakpoints are now inserted in the inferior. */
+
+static int breakpoints_inserted;
+
+/* Function inferior was in as of last step command. */
+
+static struct symbol *step_start_function;
+
+/* This is the sequence of bytes we insert for a breakpoint. */
+
+static char break_insn[] = BREAKPOINT;
+
+/* Nonzero => address for special breakpoint for resuming stepping. */
+
+static CORE_ADDR step_resume_break_address;
+
+/* Original contents of the byte where the special breakpoint is. */
+
+static char step_resume_break_shadow[sizeof break_insn];
+
+/* Nonzero means the special breakpoint is a duplicate
+ so it has not itself been inserted. */
+
+static int step_resume_break_duplicate;
+
+/* Nonzero if we are expecting a trace trap and should proceed from it.
+ 2 means expecting 2 trace traps and should continue both times.
+ That occurs when we tell sh to exec the program: we will get
+ a trap after the exec of sh and a second when the program is exec'd. */
+
+static int trap_expected;
+
+/* Nonzero if the next time we try to continue the inferior, it will
+ step one instruction and generate a spurious trace trap.
+ This is used to compensate for a bug in HP-UX. */
+
+static int trap_expected_after_continue;
+
+/* Nonzero means expecting a trace trap
+ and should stop the inferior and return silently when it happens. */
+
+int stop_after_trap;
+
+/* Nonzero means expecting a trace trap due to attaching to a process. */
+
+int stop_after_attach;
+
+/* Nonzero if pc has been changed by the debugger
+ since the inferior stopped. */
+
+int pc_changed;
+
+/* Nonzero if debugging a remote machine via a serial link or ethernet. */
+
+int remote_debugging;
+
+/* Save register contents here when about to pop a stack dummy frame. */
+
+char stop_registers[REGISTER_BYTES];
+
+/* Nonzero if program stopped due to error trying to insert breakpoints. */
+
+static int breakpoints_failed;
+
+/* Nonzero if inferior is in sh before our program got exec'd. */
+
+static int running_in_shell;
+
+/* Nonzero after stop if current stack frame should be printed. */
+
+static int stop_print_frame;
+
+#ifdef NO_SINGLE_STEP
+extern int one_stepped; /* From machine dependent code */
+extern void single_step (); /* Same. */
+#endif /* NO_SINGLE_STEP */
+
+static void insert_step_breakpoint ();
+static void remove_step_breakpoint ();
+static void wait_for_inferior ();
+static void normal_stop ();
+
+
+/* Clear out all variables saying what to do when inferior is continued.
+ First do this, then set the ones you want, then call `proceed'. */
+
+void
+clear_proceed_status ()
+{
+ trap_expected = 0;
+ step_range_start = 0;
+ step_range_end = 0;
+ step_frame_address = 0;
+ step_over_calls = -1;
+ step_resume_break_address = 0;
+ stop_after_trap = 0;
+ stop_after_attach = 0;
+
+ /* Discard any remaining commands left by breakpoint we had stopped at. */
+ clear_breakpoint_commands ();
+}
+
+/* Basic routine for continuing the program in various fashions.
+
+ ADDR is the address to resume at, or -1 for resume where stopped.
+ SIGNAL is the signal to give it, or 0 for none,
+ or -1 for act according to how it stopped.
+ STEP is nonzero if should trap after one instruction.
+ -1 means return after that and print nothing.
+ You should probably set various step_... variables
+ before calling here, if you are stepping.
+
+ You should call clear_proceed_status before calling proceed. */
+
+void
+proceed (addr, signal, step)
+ CORE_ADDR addr;
+ int signal;
+ int step;
+{
+ int oneproc = 0;
+
+ if (step > 0)
+ step_start_function = find_pc_function (read_pc ());
+ if (step < 0)
+ stop_after_trap = 1;
+
+ if (addr == -1)
+ {
+ /* If there is a breakpoint at the address we will resume at,
+ step one instruction before inserting breakpoints
+ so that we do not stop right away. */
+
+ if (!pc_changed && breakpoint_here_p (read_pc ()))
+ oneproc = 1;
+ }
+ else
+ {
+ write_register (PC_REGNUM, addr);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, addr + 4);
+#endif
+ }
+
+ if (trap_expected_after_continue)
+ {
+ /* If (step == 0), a trap will be automatically generated after
+ the first instruction is executed. Force step one
+ instruction to clear this condition. This should not occur
+ if step is nonzero, but it is harmless in that case. */
+ oneproc = 1;
+ trap_expected_after_continue = 0;
+ }
+
+ if (oneproc)
+ /* We will get a trace trap after one instruction.
+ Continue it automatically and insert breakpoints then. */
+ trap_expected = 1;
+ else
+ {
+ int temp = insert_breakpoints ();
+ if (temp)
+ {
+ print_sys_errmsg ("ptrace", temp);
+ error ("Cannot insert breakpoints.\n\
+The same program may be running in another process.");
+ }
+ breakpoints_inserted = 1;
+ }
+
+ /* Install inferior's terminal modes. */
+ terminal_inferior ();
+
+ if (signal >= 0)
+ stop_signal = signal;
+ /* If this signal should not be seen by program,
+ give it zero. Used for debugging signals. */
+ else if (stop_signal < NSIG && !signal_program[stop_signal])
+ stop_signal= 0;
+
+ /* Resume inferior. */
+ resume (oneproc || step, stop_signal);
+
+ /* Wait for it to stop (if not standalone)
+ and in any case decode why it stopped, and act accordingly. */
+
+ wait_for_inferior ();
+ normal_stop ();
+}
+
+/* Writing the inferior pc as a register calls this function
+ to inform infrun that the pc has been set in the debugger. */
+
+void
+writing_pc (val)
+ CORE_ADDR val;
+{
+ stop_pc = val;
+ pc_changed = 1;
+}
+
+/* Start an inferior process for the first time.
+ Actually it was started by the fork that created it,
+ but it will have stopped one instruction after execing sh.
+ Here we must get it up to actual execution of the real program. */
+
+void
+start_inferior ()
+{
+ /* We will get a trace trap after one instruction.
+ Continue it automatically. Eventually (after shell does an exec)
+ it will get another trace trap. Then insert breakpoints and continue. */
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+ trap_expected = START_INFERIOR_TRAPS_EXPECTED;
+#else
+ trap_expected = 2;
+#endif
+
+ running_in_shell = 0; /* Set to 1 at first SIGTRAP, 0 at second. */
+ trap_expected_after_continue = 0;
+ breakpoints_inserted = 0;
+ mark_breakpoints_out ();
+
+ /* Set up the "saved terminal modes" of the inferior
+ based on what modes we are starting it with. */
+ terminal_init_inferior ();
+
+ /* Install inferior's terminal modes. */
+ terminal_inferior ();
+
+ if (remote_debugging)
+ {
+ trap_expected = 0;
+ fetch_inferior_registers();
+ set_current_frame (create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+ stop_frame_address = FRAME_FP (get_current_frame());
+ inferior_pid = 3;
+ if (insert_breakpoints())
+ fatal("Can't insert breakpoints");
+ breakpoints_inserted = 1;
+ proceed(-1, -1, 0);
+ }
+ else
+ {
+ wait_for_inferior ();
+ normal_stop ();
+ }
+}
+
+/* Start remote-debugging of a machine over a serial link. */
+
+void
+start_remote ()
+{
+ clear_proceed_status ();
+ running_in_shell = 0;
+ trap_expected = 0;
+ inferior_pid = 3;
+ breakpoints_inserted = 0;
+ mark_breakpoints_out ();
+ wait_for_inferior ();
+ normal_stop();
+}
+
+#ifdef ATTACH_DETACH
+
+/* Attach to process PID, then initialize for debugging it
+ and wait for the trace-trap that results from attaching. */
+
+void
+attach_program (pid)
+ int pid;
+{
+ attach (pid);
+ inferior_pid = pid;
+
+ mark_breakpoints_out ();
+ terminal_init_inferior ();
+ clear_proceed_status ();
+ stop_after_attach = 1;
+ /*proceed (-1, 0, -2);*/
+ wait_for_inferior ();
+ normal_stop ();
+}
+#endif /* ATTACH_DETACH */
+
+/* Wait for control to return from inferior to debugger.
+ If inferior gets a signal, we may decide to start it up again
+ instead of returning. That is why there is a loop in this function.
+ When this function actually returns it means the inferior
+ should be left stopped and GDB should read more commands. */
+
+static void
+wait_for_inferior ()
+{
+ register int pid;
+ WAITTYPE w;
+ CORE_ADDR pc;
+ int tem;
+ int another_trap;
+ int random_signal;
+ CORE_ADDR stop_sp, prev_sp;
+ CORE_ADDR prev_func_start, stop_func_start;
+ CORE_ADDR prologue_pc;
+ int stop_step_resume_break;
+ CORE_ADDR step_resume_break_sp;
+ int newmisc;
+ int newfun_pc;
+ struct symbol *newfun;
+ struct symtab_and_line sal;
+ int prev_pc;
+ extern CORE_ADDR text_end;
+
+ prev_pc = read_pc ();
+ prev_func_start = get_pc_function_start (prev_pc) + FUNCTION_START_OFFSET;
+ prev_sp = read_register (SP_REGNUM);
+
+ while (1)
+ {
+ /* Clean up saved state that will become invalid */
+ pc_changed = 0;
+ flush_cached_frames ();
+
+ if (remote_debugging)
+ remote_wait (&w);
+ else
+ {
+ pid = wait (&w);
+ if (pid != inferior_pid)
+ continue;
+ }
+
+ /* See if the process still exists; clean up if it doesn't. */
+ if (WIFEXITED (w))
+ {
+ terminal_ours_for_output ();
+ if (WRETCODE (w))
+ printf ("\nProgram exited with code 0%o.\n", WRETCODE (w));
+ else
+ printf ("\nProgram exited normally.\n");
+ fflush (stdout);
+ inferior_died ();
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0; /* Clear single_step state since proc gone */
+#endif /* NO_SINGLE_STEP */
+ stop_print_frame = 0;
+ break;
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ kill_inferior ();
+ stop_print_frame = 0;
+ stop_signal = WTERMSIG (w);
+ terminal_ours_for_output ();
+ printf ("\nProgram terminated with signal %d, %s\n",
+ stop_signal,
+ stop_signal < NSIG
+ ? sys_siglist[stop_signal]
+ : "(undocumented)");
+ printf ("The inferior process no longer exists.\n");
+ fflush (stdout);
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0; /* Clear single_step state since proc gone */
+#endif /* NO_SINGLE_STEP */
+ break;
+ }
+
+#ifdef NO_SINGLE_STEP
+ if (one_stepped)
+ single_step (0); /* This actually cleans up the ss */
+#endif /* NO_SINGLE_STEP */
+
+ fetch_inferior_registers ();
+ stop_pc = read_pc ();
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+#ifdef CONVEX_PTRACE
+ /* pop frame stored by user-mode trap, if present */
+ if (stop_pc == BREAK_TRAP_ADDR)
+ {
+ POP_FRAME;
+ stop_pc = read_pc () - 2;
+ write_register (PC_REGNUM, stop_pc);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, stop_pc + 4);
+#endif
+ pc_changed = 0;
+ }
+ else if (stop_pc > STACK_END_ADDR)
+ {
+ POP_FRAME;
+ stop_pc = read_pc ();
+ }
+#endif /* CONVEX_PTRACE */
+ stop_frame_address = FRAME_FP (get_current_frame ());
+ stop_sp = read_register (SP_REGNUM);
+ stop_func_start =
+ get_pc_function_start (stop_pc) + FUNCTION_START_OFFSET;
+ another_trap = 0;
+ stop_breakpoint = 0;
+ stop_step = 0;
+ stop_stack_dummy = 0;
+ stop_print_frame = 1;
+ stop_step_resume_break = 0;
+ random_signal = 0;
+ stopped_by_random_signal = 0;
+ breakpoints_failed = 0;
+
+ /* Look at the cause of the stop, and decide what to do.
+ The alternatives are:
+ 1) break; to really stop and return to the debugger,
+ 2) drop through to start up again
+ (set another_trap to 1 to single step once)
+ 3) set random_signal to 1, and the decision between 1 and 2
+ will be made according to the signal handling tables. */
+
+ stop_signal = WSTOPSIG (w);
+
+ /* First, distinguish signals caused by the debugger from signals
+ that have to do with the program's own actions.
+ Note that breakpoint insns may cause SIGTRAP or SIGILL
+ or SIGEMT, depending on the operating system version.
+ Here we detect when a SIGILL or SIGEMT is really a breakpoint
+ and change it to SIGTRAP. */
+
+ if (stop_signal == SIGTRAP
+#ifndef CONVEX_PTRACE
+ || (breakpoints_inserted &&
+ (stop_signal == SIGILL
+ || stop_signal == SIGEMT))
+#endif /* not CONVEX_PTRACE */
+ || stop_after_attach)
+ {
+ if (stop_signal == SIGTRAP && stop_after_trap)
+ {
+ stop_print_frame = 0;
+ break;
+ }
+ if (stop_after_attach)
+ break;
+ /* Don't even think about breakpoints
+ if still running the shell that will exec the program
+ or if just proceeded over a breakpoint. */
+ if (stop_signal == SIGTRAP && trap_expected)
+ stop_breakpoint = 0;
+ else
+ {
+ /* See if there is a breakpoint at the current PC. */
+#if DECR_PC_AFTER_BREAK
+ /* Notice the case of stepping through a jump
+ that leads just after a breakpoint.
+ Don't confuse that with hitting the breakpoint.
+ What we check for is that 1) stepping is going on
+ and 2) the pc before the last insn does not match
+ the address of the breakpoint before the current pc. */
+ if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK
+ && step_range_end && !step_resume_break_address))
+#endif /* DECR_PC_AFTER_BREAK not zero */
+ {
+ /* For condition exprs. */
+ select_frame (get_current_frame (), 0);
+ stop_breakpoint =
+ breakpoint_stop_status (stop_pc, stop_frame_address);
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
+ if (stop_breakpoint && DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, stop_pc + 4);
+#endif
+ pc_changed = 0;
+ }
+ }
+ /* See if we stopped at the special breakpoint for
+ stepping over a subroutine call. */
+ if (stop_pc - DECR_PC_AFTER_BREAK
+ == step_resume_break_address)
+ {
+ stop_step_resume_break = 1;
+ if (DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
+ pc_changed = 0;
+ }
+ }
+ }
+
+ if (stop_signal == SIGTRAP)
+ random_signal
+ = !(stop_breakpoint || trap_expected
+ || stop_step_resume_break
+#ifndef CONVEX_PTRACE
+ || (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#else
+ || stop_pc == text_end - 2
+#endif
+ || (step_range_end && !step_resume_break_address));
+ else
+ {
+ random_signal
+ = !(stop_breakpoint
+ || stop_step_resume_break
+#ifdef news800
+ || (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#endif
+
+ );
+ if (!random_signal)
+ stop_signal = SIGTRAP;
+ }
+ }
+ else
+ random_signal = 1;
+
+ /* For the program's own signals, act according to
+ the signal handling tables. */
+
+ if (random_signal
+ && !(running_in_shell && stop_signal == SIGSEGV))
+ {
+ /* Signal not for debugging purposes. */
+ int printed = 0;
+
+ stopped_by_random_signal = 1;
+
+ if (stop_signal >= NSIG
+ || signal_print[stop_signal])
+ {
+ printed = 1;
+ terminal_ours_for_output ();
+ printf ("\nProgram received signal %d, %s\n",
+ stop_signal,
+ stop_signal < NSIG
+ ? sys_siglist[stop_signal]
+ : "(undocumented)");
+ fflush (stdout);
+ }
+ if (stop_signal >= NSIG
+ || signal_stop[stop_signal])
+ break;
+ /* If not going to stop, give terminal back
+ if we took it away. */
+ else if (printed)
+ terminal_inferior ();
+ }
+
+ /* Handle cases caused by hitting a breakpoint. */
+
+ if (!random_signal
+ && (stop_breakpoint || stop_step_resume_break))
+ {
+ /* Does a breakpoint want us to stop? */
+ if (stop_breakpoint && stop_breakpoint != -1
+ && stop_breakpoint != -0x1000001)
+ {
+ /* 0x1000000 is set in stop_breakpoint as returned by
+ breakpoint_stop_status to indicate a silent
+ breakpoint. */
+ if ((stop_breakpoint > 0 ? stop_breakpoint :
+ -stop_breakpoint)
+ & 0x1000000)
+ {
+ stop_print_frame = 0;
+ if (stop_breakpoint > 0)
+ stop_breakpoint -= 0x1000000;
+ else
+ stop_breakpoint += 0x1000000;
+ }
+ break;
+ }
+ /* But if we have hit the step-resumption breakpoint,
+ remove it. It has done its job getting us here.
+ The sp test is to make sure that we don't get hung
+ up in recursive calls in functions without frame
+ pointers. If the stack pointer isn't outside of
+ where the breakpoint was set (within a routine to be
+ stepped over), we're in the middle of a recursive
+ call. Not true for reg window machines (sparc)
+ because the must change frames to call things and
+ the stack pointer doesn't have to change if it
+ the bp was set in a routine without a frame (pc can
+ be stored in some other window).
+
+ The removal of the sp test is to allow calls to
+ alloca. Nasty things were happening. Oh, well,
+ gdb can only handle one level deep of lack of
+ frame pointer. */
+ if (stop_step_resume_break
+ && (step_frame_address == 0
+ || (stop_frame_address == step_frame_address
+#if 0
+#ifndef HAVE_REGISTER_WINDOWS
+ && step_resume_break_sp INNER_THAN stop_sp
+#endif
+#endif
+ )))
+ {
+ remove_step_breakpoint ();
+ step_resume_break_address = 0;
+ }
+ /* Otherwise, must remove breakpoints and single-step
+ to get us past the one we hit. */
+ else
+ {
+ remove_breakpoints ();
+ remove_step_breakpoint ();
+ breakpoints_inserted = 0;
+ another_trap = 1;
+ }
+
+ /* We come here if we hit a breakpoint but should not
+ stop for it. Possibly we also were stepping
+ and should stop for that. So fall through and
+ test for stepping. But, if not stepping,
+ do not stop. */
+ }
+
+ /* If this is the breakpoint at the end of a stack dummy,
+ just stop silently. */
+#ifndef CONVEX_PTRACE
+ if (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#else
+ /* "stack" dummy must be in text segment for Convex Unix */
+ if (stop_pc == text_end - 2)
+#endif
+ {
+ stop_print_frame = 0;
+ stop_stack_dummy = 1;
+#ifdef HP9K320
+ trap_expected_after_continue = 1;
+#endif
+ break;
+ }
+
+ if (step_resume_break_address)
+ /* Having a step-resume breakpoint overrides anything
+ else having to do with stepping commands until
+ that breakpoint is reached. */
+ ;
+ /* If stepping through a line, keep going if still within it. */
+ else if (!random_signal
+ && step_range_end
+ && stop_pc >= step_range_start
+ && stop_pc < step_range_end
+ /* The step range might include the start of the
+ function, so if we are at the start of the
+ step range and either the stack or frame pointers
+ just changed, we've stepped outside */
+ && !(stop_pc == step_range_start
+ && stop_frame_address
+ && (stop_sp != prev_sp
+ || stop_frame_address != step_frame_address)))
+ {
+ /* Don't step through the return from a function
+ unless that is the first instruction stepped through. */
+ if (ABOUT_TO_RETURN (stop_pc))
+ {
+ stop_step = 1;
+ break;
+ }
+ }
+
+ /* We stepped out of the stepping range. See if that was due
+ to a subroutine call that we should proceed to the end of. */
+ else if (!random_signal && step_range_end)
+ {
+ if (stop_func_start)
+ {
+ prologue_pc = stop_func_start;
+ SKIP_PROLOGUE (prologue_pc);
+ }
+
+ /* ==> See comments at top of file on this algorithm. <==*/
+
+ if (stop_pc == stop_func_start
+ && (stop_func_start != prev_func_start
+ || prologue_pc != stop_func_start
+ || stop_sp != prev_sp))
+ {
+ newfun = find_pc_function (stop_pc);
+ /* It's a subroutine call */
+ if (step_over_calls > 0 || (step_over_calls && newfun == 0))
+ {
+ /* A subroutine call has happened. */
+ /* Set a special breakpoint after the return */
+ step_resume_break_address =
+ SAVED_PC_AFTER_CALL (get_current_frame ());
+ step_resume_break_duplicate
+ = breakpoint_here_p (step_resume_break_address);
+ step_resume_break_sp = stop_sp;
+ if (breakpoints_inserted)
+ insert_step_breakpoint ();
+ }
+ /* Subroutine call with source code we should not step over.
+ Do step to the first line of code in it. */
+ else if (step_over_calls)
+ {
+ SKIP_PROLOGUE (stop_func_start);
+ sal = find_pc_line (stop_func_start, 0);
+ /* Use the step_resume_break to step until
+ the end of the prologue, even if that involves jumps
+ (as it seems to on the vax under 4.2). */
+ /* If the prologue ends in the middle of a source line,
+ continue to the end of that source line.
+ Otherwise, just go to end of prologue. */
+#ifdef convex
+ /* no, don't either. It skips any code that's
+ legitimately on the first line. */
+#else
+ if (sal.end && sal.pc != stop_func_start)
+ stop_func_start = sal.end;
+#endif
+
+ if (stop_func_start == stop_pc)
+ {
+ /* We are already there: stop now. */
+ stop_step = 1;
+ break;
+ }
+ else
+ /* Put the step-breakpoint there and go until there. */
+ {
+ step_resume_break_address = stop_func_start;
+ step_resume_break_sp = stop_sp;
+
+ step_resume_break_duplicate
+ = breakpoint_here_p (step_resume_break_address);
+ if (breakpoints_inserted)
+ insert_step_breakpoint ();
+ /* Do not specify what the fp should be when we stop
+ since on some machines the prologue
+ is where the new fp value is established. */
+ step_frame_address = 0;
+ /* And make sure stepping stops right away then. */
+ step_range_end = step_range_start;
+ }
+ }
+ else
+ {
+ /* We get here only if step_over_calls is 0 and we
+ just stepped into a subroutine. I presume
+ that step_over_calls is only 0 when we're
+ supposed to be stepping at the assembly
+ language level.*/
+ stop_step = 1;
+ break;
+ }
+ }
+ /* No subroutince call; stop now. */
+ else
+ {
+ stop_step = 1;
+ break;
+ }
+ }
+
+ /* Save the pc before execution, to compare with pc after stop. */
+ prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
+ prev_func_start = stop_func_start; /* Ok, since if DECR_PC_AFTER
+ BREAK is defined, the
+ original pc would not have
+ been at the start of a
+ function. */
+ prev_sp = stop_sp;
+
+ /* If we did not do break;, it means we should keep
+ running the inferior and not return to debugger. */
+
+ /* If trap_expected is 2, it means continue once more
+ and insert breakpoints at the next trap.
+ If trap_expected is 1 and the signal was SIGSEGV, it means
+ the shell is doing some memory allocation--just resume it
+ with SIGSEGV.
+ Otherwise insert breakpoints now, and possibly single step. */
+
+ if (trap_expected > 1)
+ {
+ trap_expected--;
+ running_in_shell = 1;
+ resume (0, 0);
+ }
+ else if (running_in_shell && stop_signal == SIGSEGV)
+ {
+ resume (0, SIGSEGV);
+ }
+ else
+ {
+ /* Here, we are not awaiting another exec to get
+ the program we really want to debug.
+ Insert breakpoints now, unless we are trying
+ to one-proceed past a breakpoint. */
+ running_in_shell = 0;
+ if (!breakpoints_inserted && !another_trap)
+ {
+ insert_step_breakpoint ();
+ breakpoints_failed = insert_breakpoints ();
+ if (breakpoints_failed)
+ break;
+ breakpoints_inserted = 1;
+ }
+
+ trap_expected = another_trap;
+
+ if (stop_signal == SIGTRAP)
+ stop_signal = 0;
+
+ resume ((step_range_end && !step_resume_break_address)
+ || trap_expected,
+ stop_signal);
+ }
+ }
+}
+
+/* Here to return control to GDB when the inferior stops for real.
+ Print appropriate messages, remove breakpoints, give terminal our modes.
+
+ RUNNING_IN_SHELL nonzero means the shell got a signal before
+ exec'ing the program we wanted to run.
+ STOP_PRINT_FRAME nonzero means print the executing frame
+ (pc, function, args, file, line number and line text).
+ BREAKPOINTS_FAILED nonzero means stop was due to error
+ attempting to insert breakpoints. */
+
+/* FIXME, normal_stop is ALWAYS called immediately after wait_for_inferior.
+ They should probably be merged into a single function, since that
+ would avoid numerous tests (e.g. of inferior_pid). */
+
+static void
+normal_stop ()
+{
+ /* Make sure that the current_frame's pc is correct. This
+ is a correction for setting up the frame info before doing
+ DECR_PC_AFTER_BREAK */
+ if (inferior_pid)
+ (get_current_frame ())->pc = read_pc ();
+
+ if (breakpoints_failed)
+ {
+ terminal_ours_for_output ();
+ print_sys_errmsg ("ptrace", breakpoints_failed);
+ printf ("Stopped; cannot insert breakpoints.\n\
+The same program may be running in another process.\n");
+ }
+
+ if (inferior_pid)
+ remove_step_breakpoint ();
+
+ if (inferior_pid && breakpoints_inserted)
+ if (remove_breakpoints ())
+ {
+ terminal_ours_for_output ();
+ printf ("Cannot remove breakpoints because program is no longer writable.\n\
+It must be running in another process.\n\
+Further execution is probably impossible.\n");
+ }
+
+ breakpoints_inserted = 0;
+
+ /* Delete the breakpoint we stopped at, if it wants to be deleted.
+ Delete any breakpoint that is to be deleted at the next stop. */
+
+ breakpoint_auto_delete (stop_breakpoint);
+
+ /* If an auto-display called a function and that got a signal,
+ delete that auto-display to avoid an infinite recursion. */
+
+ if (stopped_by_random_signal)
+ delete_current_display ();
+
+ if (step_multi && stop_step)
+ return;
+
+ terminal_ours ();
+
+ if (running_in_shell)
+ {
+ if (stop_signal == SIGSEGV)
+ {
+ char *exec_file = (char *) get_exec_file (1);
+
+ if (access (exec_file, X_OK) != 0)
+ printf ("The file \"%s\" is not executable.\n", exec_file);
+ else
+ printf ("\
+You have just encountered a bug in \"sh\". GDB starts your program\n\
+by running \"sh\" with a command to exec your program.\n\
+This is so that \"sh\" will process wildcards and I/O redirection.\n\
+This time, \"sh\" crashed.\n\
+\n\
+One known bug in \"sh\" bites when the environment takes up a lot of space.\n\
+Try \"info env\" to see the environment; then use \"unset-env\" to kill\n\
+some variables whose values are large; then do \"run\" again.\n\
+\n\
+If that works, you might want to put those \"unset-env\" commands\n\
+into a \".gdbinit\" file in this directory so they will happen every time.\n");
+ }
+ /* Don't confuse user with his program's symbols on sh's data. */
+ stop_print_frame = 0;
+ }
+
+ if (inferior_pid == 0)
+ return;
+
+ /* Select innermost stack frame except on return from a stack dummy routine,
+ or if the program has exited. */
+ if (!stop_stack_dummy)
+ {
+ select_frame (get_current_frame (), 0);
+
+ if (stop_print_frame)
+ {
+ if (stop_breakpoint > 0)
+ printf ("\nBpt %d, ", stop_breakpoint);
+ print_sel_frame (stop_step
+ && step_frame_address == stop_frame_address
+ && step_start_function == find_pc_function (stop_pc));
+ /* Display the auto-display expressions. */
+ do_displays ();
+ }
+ }
+
+ /* Save the function value return registers
+ We might be about to restore their previous contents. */
+ read_register_bytes (0, stop_registers, REGISTER_BYTES);
+
+ if (stop_stack_dummy)
+ {
+ /* Pop the empty frame that contains the stack dummy.
+ POP_FRAME ends with a setting of the current frame, so we
+ can use that next. */
+ POP_FRAME;
+ select_frame (get_current_frame (), 0);
+ }
+}
+
+static void
+insert_step_breakpoint ()
+{
+ if (step_resume_break_address && !step_resume_break_duplicate)
+ {
+ read_memory (step_resume_break_address,
+ step_resume_break_shadow, sizeof break_insn);
+ write_memory (step_resume_break_address,
+ break_insn, sizeof break_insn);
+ }
+}
+
+static void
+remove_step_breakpoint ()
+{
+ if (step_resume_break_address && !step_resume_break_duplicate)
+ write_memory (step_resume_break_address, step_resume_break_shadow,
+ sizeof break_insn);
+}
+
+/* Specify how various signals in the inferior should be handled. */
+
+static void
+handle_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register char *p = args;
+ int signum = 0;
+ register int digits, wordlen;
+
+ if (!args)
+ error_no_arg ("signal to handle");
+
+ while (*p)
+ {
+ /* Find the end of the next word in the args. */
+ for (wordlen = 0; p[wordlen] && p[wordlen] != ' ' && p[wordlen] != '\t';
+ wordlen++);
+ for (digits = 0; p[digits] >= '0' && p[digits] <= '9'; digits++);
+
+ /* If it is all digits, it is signal number to operate on. */
+ if (digits == wordlen)
+ {
+ signum = atoi (p);
+ if (signum <= 0 || signum >= NSIG)
+ {
+ p[wordlen] = '\0';
+ error ("Invalid signal %s given as argument to \"handle\".", p);
+ }
+ if (signum == SIGTRAP || signum == SIGINT)
+ {
+ if (!query ("Signal %d is used by the debugger.\nAre you sure you want to change it? ", signum))
+ error ("Not confirmed.");
+ }
+ }
+ else if (signum == 0)
+ error ("First argument is not a signal number.");
+
+ /* Else, if already got a signal number, look for flag words
+ saying what to do for it. */
+ else if (!strncmp (p, "stop", wordlen))
+ {
+ signal_stop[signum] = 1;
+ signal_print[signum] = 1;
+ }
+ else if (wordlen >= 2 && !strncmp (p, "print", wordlen))
+ signal_print[signum] = 1;
+ else if (wordlen >= 2 && !strncmp (p, "pass", wordlen))
+ signal_program[signum] = 1;
+ else if (!strncmp (p, "ignore", wordlen))
+ signal_program[signum] = 0;
+ else if (wordlen >= 3 && !strncmp (p, "nostop", wordlen))
+ signal_stop[signum] = 0;
+ else if (wordlen >= 4 && !strncmp (p, "noprint", wordlen))
+ {
+ signal_print[signum] = 0;
+ signal_stop[signum] = 0;
+ }
+ else if (wordlen >= 4 && !strncmp (p, "nopass", wordlen))
+ signal_program[signum] = 0;
+ else if (wordlen >= 3 && !strncmp (p, "noignore", wordlen))
+ signal_program[signum] = 1;
+ /* Not a number and not a recognized flag word => complain. */
+ else
+ {
+ p[wordlen] = 0;
+ error ("Unrecognized flag word: \"%s\".", p);
+ }
+
+ /* Find start of next word. */
+ p += wordlen;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+
+ if (from_tty)
+ {
+ /* Show the results. */
+ printf ("Number\tStop\tPrint\tPass to program\tDescription\n");
+ printf ("%d\t", signum);
+ printf ("%s\t", signal_stop[signum] ? "Yes" : "No");
+ printf ("%s\t", signal_print[signum] ? "Yes" : "No");
+ printf ("%s\t\t", signal_program[signum] ? "Yes" : "No");
+ printf ("%s\n", sys_siglist[signum]);
+ }
+}
+
+/* Print current contents of the tables set by the handle command. */
+
+static void
+signals_info (signum_exp)
+ char *signum_exp;
+{
+ register int i;
+ printf ("Number\tStop\tPrint\tPass to program\tDescription\n");
+
+ if (signum_exp)
+ {
+ i = parse_and_eval_address (signum_exp);
+ printf ("%d\t", i);
+ printf ("%s\t", signal_stop[i] ? "Yes" : "No");
+ printf ("%s\t", signal_print[i] ? "Yes" : "No");
+ printf ("%s\t\t", signal_program[i] ? "Yes" : "No");
+ printf ("%s\n", sys_siglist[i]);
+ return;
+ }
+
+ printf ("\n");
+ for (i = 0; i < NSIG; i++)
+ {
+ QUIT;
+ if (i > 0 && i % 16 == 0)
+ {
+ printf ("[Type Return to see more]");
+ fflush (stdout);
+ gdb_read_line (0, 0);
+ }
+ printf ("%d\t", i);
+ printf ("%s\t", signal_stop[i] ? "Yes" : "No");
+ printf ("%s\t", signal_print[i] ? "Yes" : "No");
+ printf ("%s\t\t", signal_program[i] ? "Yes" : "No");
+ printf ("%s\n", sys_siglist[i]);
+ }
+
+ printf ("\nUse the \"handle\" command to change these tables.\n");
+}
+
+/* Save all of the information associated with the inferior<==>gdb
+ connection. INF_STATUS is a pointer to a "struct inferior_status"
+ (defined in inferior.h). */
+
+struct command_line *get_breakpoint_commands ();
+
+void
+save_inferior_status (inf_status, restore_stack_info)
+ struct inferior_status *inf_status;
+ int restore_stack_info;
+{
+ inf_status->pc_changed = pc_changed;
+ inf_status->stop_signal = stop_signal;
+ inf_status->stop_pc = stop_pc;
+ inf_status->stop_frame_address = stop_frame_address;
+ inf_status->stop_breakpoint = stop_breakpoint;
+ inf_status->stop_step = stop_step;
+ inf_status->stop_stack_dummy = stop_stack_dummy;
+ inf_status->stopped_by_random_signal = stopped_by_random_signal;
+ inf_status->trap_expected = trap_expected;
+ inf_status->step_range_start = step_range_start;
+ inf_status->step_range_end = step_range_end;
+ inf_status->step_frame_address = step_frame_address;
+ inf_status->step_over_calls = step_over_calls;
+ inf_status->step_resume_break_address = step_resume_break_address;
+ inf_status->stop_after_trap = stop_after_trap;
+ inf_status->stop_after_attach = stop_after_attach;
+ inf_status->breakpoint_commands = get_breakpoint_commands ();
+ inf_status->restore_stack_info = restore_stack_info;
+
+ bcopy (stop_registers, inf_status->stop_registers, REGISTER_BYTES);
+
+ record_selected_frame (&(inf_status->selected_frame_address),
+ &(inf_status->selected_level));
+ return;
+}
+
+void
+restore_inferior_status (inf_status)
+ struct inferior_status *inf_status;
+{
+ FRAME fid;
+ int level = inf_status->selected_level;
+
+ pc_changed = inf_status->pc_changed;
+ stop_signal = inf_status->stop_signal;
+ stop_pc = inf_status->stop_pc;
+ stop_frame_address = inf_status->stop_frame_address;
+ stop_breakpoint = inf_status->stop_breakpoint;
+ stop_step = inf_status->stop_step;
+ stop_stack_dummy = inf_status->stop_stack_dummy;
+ stopped_by_random_signal = inf_status->stopped_by_random_signal;
+ trap_expected = inf_status->trap_expected;
+ step_range_start = inf_status->step_range_start;
+ step_range_end = inf_status->step_range_end;
+ step_frame_address = inf_status->step_frame_address;
+ step_over_calls = inf_status->step_over_calls;
+ step_resume_break_address = inf_status->step_resume_break_address;
+ stop_after_trap = inf_status->stop_after_trap;
+ stop_after_attach = inf_status->stop_after_attach;
+ set_breakpoint_commands (inf_status->breakpoint_commands);
+
+ bcopy (inf_status->stop_registers, stop_registers, REGISTER_BYTES);
+
+ if (inf_status->restore_stack_info)
+ {
+ fid = find_relative_frame (get_current_frame (),
+ &level);
+
+ if (FRAME_FP (fid) != inf_status->selected_frame_address ||
+ level != 0)
+ {
+ fprintf (stderr, "Unable to restore previously selected frame.\n");
+ select_frame (get_current_frame (), 0);
+ return;
+ }
+
+ select_frame (fid, inf_status->selected_level);
+ }
+ return;
+}
+
+
+void
+_initialize_infrun ()
+{
+ register int i;
+
+ add_info ("signals", signals_info,
+ "What debugger does when program gets various signals.\n\
+Specify a signal number as argument to print info on that signal only.");
+
+ add_com ("handle", class_run, handle_command,
+ "Specify how to handle a signal.\n\
+Args are signal number followed by flags.\n\
+Flags allowed are \"stop\", \"print\", \"pass\",\n\
+ \"nostop\", \"noprint\" or \"nopass\".\n\
+Print means print a message if this signal happens.\n\
+Stop means reenter debugger if this signal happens (implies print).\n\
+Pass means let program see this signal; otherwise program doesn't know.\n\
+Pass and Stop may be combined.");
+
+ for (i = 0; i < NSIG; i++)
+ {
+ signal_stop[i] = 1;
+ signal_print[i] = 1;
+ signal_program[i] = 1;
+ }
+
+ /* Signals caused by debugger's own actions
+ should not be given to the program afterwards. */
+ signal_program[SIGTRAP] = 0;
+ signal_program[SIGINT] = 0;
+
+ /* Signals that are not errors should not normally enter the debugger. */
+#ifdef SIGALRM
+ signal_stop[SIGALRM] = 0;
+ signal_print[SIGALRM] = 0;
+#endif /* SIGALRM */
+#ifdef SIGVTALRM
+ signal_stop[SIGVTALRM] = 0;
+ signal_print[SIGVTALRM] = 0;
+#endif /* SIGVTALRM */
+#ifdef SIGPROF
+ signal_stop[SIGPROF] = 0;
+ signal_print[SIGPROF] = 0;
+#endif /* SIGPROF */
+#ifdef SIGCHLD
+ signal_stop[SIGCHLD] = 0;
+ signal_print[SIGCHLD] = 0;
+#endif /* SIGCHLD */
+#ifdef SIGCLD
+ signal_stop[SIGCLD] = 0;
+ signal_print[SIGCLD] = 0;
+#endif /* SIGCLD */
+#ifdef SIGIO
+ signal_stop[SIGIO] = 0;
+ signal_print[SIGIO] = 0;
+#endif /* SIGIO */
+#ifdef SIGURG
+ signal_stop[SIGURG] = 0;
+ signal_print[SIGURG] = 0;
+#endif /* SIGURG */
+}
+
+@
+
+
+1.2
+log
+@Avoid accessing inferior process if it just exited or terminated with
+a signal. Clean up stack frame stuff in that case too, so that the
+various stack commands ("i frame", "up", "frame", "where") don't get
+confused.
+@
+text
+@d137 5
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d472 4
+d485 35
+a524 2
+ pc_changed = 0;
+ flush_cached_frames ();
+d569 1
+a569 30
+ if (WIFEXITED (w))
+ {
+ terminal_ours_for_output ();
+ if (WRETCODE (w))
+ printf ("\nProgram exited with code 0%o.\n", WRETCODE (w));
+ else
+ printf ("\nProgram exited normally.\n");
+ fflush (stdout);
+ inferior_died ();
+ stop_print_frame = 0;
+ break;
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ kill_inferior ();
+ stop_print_frame = 0;
+ stop_signal = WTERMSIG (w);
+ terminal_ours_for_output ();
+ printf ("\nProgram terminated with signal %d, %s\n",
+ stop_signal,
+ stop_signal < NSIG
+ ? sys_siglist[stop_signal]
+ : "(undocumented)");
+ printf ("The inferior process no longer exists.\n");
+ fflush (stdout);
+ break;
+ }
+ else
+ {
+ stop_signal = WSTOPSIG (w);
+d571 6
+a576 6
+ /* First, distinguish signals caused by the debugger from signals
+ that have to do with the program's own actions.
+ Note that breakpoint insns may cause SIGTRAP or SIGILL
+ or SIGEMT, depending on the operating system version.
+ Here we detect when a SIGILL or SIGEMT is really a breakpoint
+ and change it to SIGTRAP. */
+d578 1
+a578 1
+ if (stop_signal == SIGTRAP
+d580 3
+a582 3
+ || (breakpoints_inserted &&
+ (stop_signal == SIGILL
+ || stop_signal == SIGEMT))
+d584 15
+a598 1
+ || stop_after_attach)
+d600 1
+a600 15
+ if (stop_signal == SIGTRAP && stop_after_trap)
+ {
+ stop_print_frame = 0;
+ break;
+ }
+ if (stop_after_attach)
+ break;
+ /* Don't even think about breakpoints
+ if still running the shell that will exec the program
+ or if just proceeded over a breakpoint. */
+ if (stop_signal == SIGTRAP && trap_expected)
+ stop_breakpoint = 0;
+ else
+ {
+ /* See if there is a breakpoint at the current PC. */
+d602 8
+a609 8
+ /* Notice the case of stepping through a jump
+ that leads just after a breakpoint.
+ Don't confuse that with hitting the breakpoint.
+ What we check for is that 1) stepping is going on
+ and 2) the pc before the last insn does not match
+ the address of the breakpoint before the current pc. */
+ if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK
+ && step_range_end && !step_resume_break_address))
+d611 9
+d621 2
+a622 11
+ /* For condition exprs. */
+ select_frame (get_current_frame (), 0);
+ stop_breakpoint =
+ breakpoint_stop_status (stop_pc, stop_frame_address);
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
+ if (stop_breakpoint && DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
+d624 1
+a624 1
+ write_register (NPC_REGNUM, stop_pc + 4);
+d626 1
+a626 2
+ pc_changed = 0;
+ }
+d628 12
+a639 12
+ /* See if we stopped at the special breakpoint for
+ stepping over a subroutine call. */
+ if (stop_pc - DECR_PC_AFTER_BREAK
+ == step_resume_break_address)
+ {
+ stop_step_resume_break = 1;
+ if (DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
+ pc_changed = 0;
+ }
+d642 1
+d644 4
+a647 4
+ if (stop_signal == SIGTRAP)
+ random_signal
+ = !(stop_breakpoint || trap_expected
+ || stop_step_resume_break
+d649 2
+a650 2
+ || (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+d652 1
+a652 1
+ || stop_pc == text_end - 2
+d654 6
+a659 6
+ || (step_range_end && !step_resume_break_address));
+ else
+ {
+ random_signal
+ = !(stop_breakpoint
+ || stop_step_resume_break
+d661 2
+a662 2
+ || (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+d665 3
+a667 4
+ );
+ if (!random_signal)
+ stop_signal = SIGTRAP;
+ }
+d669 3
+a671 2
+ else
+ random_signal = 1;
+d673 2
+a674 2
+ /* For the program's own signals, act according to
+ the signal handling tables. */
+d676 50
+a725 19
+ if (random_signal
+ && !(running_in_shell && stop_signal == SIGSEGV))
+ {
+ /* Signal not for debugging purposes. */
+ int printed = 0;
+
+ stopped_by_random_signal = 1;
+
+ if (stop_signal >= NSIG
+ || signal_print[stop_signal])
+ {
+ printed = 1;
+ terminal_ours_for_output ();
+ printf ("\nProgram received signal %d, %s\n",
+ stop_signal,
+ stop_signal < NSIG
+ ? sys_siglist[stop_signal]
+ : "(undocumented)");
+ fflush (stdout);
+d727 1
+a727 7
+ if (stop_signal >= NSIG
+ || signal_stop[stop_signal])
+ break;
+ /* If not going to stop, give terminal back
+ if we took it away. */
+ else if (printed)
+ terminal_inferior ();
+d729 20
+a748 45
+
+ /* Handle cases caused by hitting a breakpoint. */
+
+ if (!random_signal
+ && (stop_breakpoint || stop_step_resume_break))
+ {
+ /* Does a breakpoint want us to stop? */
+ if (stop_breakpoint && stop_breakpoint != -1
+ && stop_breakpoint != -0x1000001)
+ {
+ /* 0x1000000 is set in stop_breakpoint as returned by
+ breakpoint_stop_status to indicate a silent
+ breakpoint. */
+ if ((stop_breakpoint > 0 ? stop_breakpoint :
+ -stop_breakpoint)
+ & 0x1000000)
+ {
+ stop_print_frame = 0;
+ if (stop_breakpoint > 0)
+ stop_breakpoint -= 0x1000000;
+ else
+ stop_breakpoint += 0x1000000;
+ }
+ break;
+ }
+ /* But if we have hit the step-resumption breakpoint,
+ remove it. It has done its job getting us here.
+ The sp test is to make sure that we don't get hung
+ up in recursive calls in functions without frame
+ pointers. If the stack pointer isn't outside of
+ where the breakpoint was set (within a routine to be
+ stepped over), we're in the middle of a recursive
+ call. Not true for reg window machines (sparc)
+ because the must change frames to call things and
+ the stack pointer doesn't have to change if it
+ the bp was set in a routine without a frame (pc can
+ be stored in some other window).
+
+ The removal of the sp test is to allow calls to
+ alloca. Nasty things were happening. Oh, well,
+ gdb can only handle one level deep of lack of
+ frame pointer. */
+ if (stop_step_resume_break
+ && (step_frame_address == 0
+ || (stop_frame_address == step_frame_address
+d751 1
+a751 1
+ && step_resume_break_sp INNER_THAN stop_sp
+d754 13
+a766 20
+ )))
+ {
+ remove_step_breakpoint ();
+ step_resume_break_address = 0;
+ }
+ /* Otherwise, must remove breakpoints and single-step
+ to get us past the one we hit. */
+ else
+ {
+ remove_breakpoints ();
+ remove_step_breakpoint ();
+ breakpoints_inserted = 0;
+ another_trap = 1;
+ }
+
+ /* We come here if we hit a breakpoint but should not
+ stop for it. Possibly we also were stepping
+ and should stop for that. So fall through and
+ test for stepping. But, if not stepping,
+ do not stop. */
+d769 9
+a777 2
+ /* If this is the breakpoint at the end of a stack dummy,
+ just stop silently. */
+d779 2
+a780 2
+ if (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+d782 2
+a783 2
+ /* "stack" dummy must be in text segment for Convex Unix */
+ if (stop_pc == text_end - 2)
+d785 3
+a787 3
+ {
+ stop_print_frame = 0;
+ stop_stack_dummy = 1;
+d789 1
+a789 1
+ trap_expected_after_continue = 1;
+d791 2
+a792 2
+ break;
+ }
+d794 22
+a815 18
+ if (step_resume_break_address)
+ /* Having a step-resume breakpoint overrides anything
+ else having to do with stepping commands until
+ that breakpoint is reached. */
+ ;
+ /* If stepping through a line, keep going if still within it. */
+ else if (!random_signal
+ && step_range_end
+ && stop_pc >= step_range_start
+ && stop_pc < step_range_end
+ /* The step range might include the start of the
+ function, so if we are at the start of the
+ step range and either the stack or frame pointers
+ just changed, we've stepped outside */
+ && !(stop_pc == step_range_start
+ && stop_frame_address
+ && (stop_sp != prev_sp
+ || stop_frame_address != step_frame_address)))
+d817 2
+a818 7
+ /* Don't step through the return from a function
+ unless that is the first instruction stepped through. */
+ if (ABOUT_TO_RETURN (stop_pc))
+ {
+ stop_step = 1;
+ break;
+ }
+d820 1
+d822 43
+a864 43
+ /* We stepped out of the stepping range. See if that was due
+ to a subroutine call that we should proceed to the end of. */
+ else if (!random_signal && step_range_end)
+ {
+ if (stop_func_start)
+ {
+ prologue_pc = stop_func_start;
+ SKIP_PROLOGUE (prologue_pc);
+ }
+
+ /* ==> See comments at top of file on this algorithm. <==*/
+
+ if (stop_pc == stop_func_start
+ && (stop_func_start != prev_func_start
+ || prologue_pc != stop_func_start
+ || stop_sp != prev_sp))
+ {
+ newfun = find_pc_function (stop_pc);
+ /* It's a subroutine call */
+ if (step_over_calls > 0 || (step_over_calls && newfun == 0))
+ {
+ /* A subroutine call has happened. */
+ /* Set a special breakpoint after the return */
+ step_resume_break_address =
+ SAVED_PC_AFTER_CALL (get_current_frame ());
+ step_resume_break_duplicate
+ = breakpoint_here_p (step_resume_break_address);
+ step_resume_break_sp = stop_sp;
+ if (breakpoints_inserted)
+ insert_step_breakpoint ();
+ }
+ /* Subroutine call with source code we should not step over.
+ Do step to the first line of code in it. */
+ else if (step_over_calls)
+ {
+ SKIP_PROLOGUE (stop_func_start);
+ sal = find_pc_line (stop_func_start, 0);
+ /* Use the step_resume_break to step until
+ the end of the prologue, even if that involves jumps
+ (as it seems to on the vax under 4.2). */
+ /* If the prologue ends in the middle of a source line,
+ continue to the end of that source line.
+ Otherwise, just go to end of prologue. */
+d866 2
+a867 2
+ /* no, don't either. It skips any code that's
+ legitimately on the first line. */
+d869 2
+a870 2
+ if (sal.end && sal.pc != stop_func_start)
+ stop_func_start = sal.end;
+d872 6
+a877 24
+
+ if (stop_func_start == stop_pc)
+ {
+ /* We are already there: stop now. */
+ stop_step = 1;
+ break;
+ }
+ else
+ /* Put the step-breakpoint there and go until there. */
+ {
+ step_resume_break_address = stop_func_start;
+ step_resume_break_sp = stop_sp;
+
+ step_resume_break_duplicate
+ = breakpoint_here_p (step_resume_break_address);
+ if (breakpoints_inserted)
+ insert_step_breakpoint ();
+ /* Do not specify what the fp should be when we stop
+ since on some machines the prologue
+ is where the new fp value is established. */
+ step_frame_address = 0;
+ /* And make sure stepping stops right away then. */
+ step_range_end = step_range_start;
+ }
+d880 1
+d882 13
+a894 7
+ /* We get here only if step_over_calls is 0 and we
+ just stepped into a subroutine. I presume
+ that step_over_calls is only 0 when we're
+ supposed to be stepping at the assembly
+ language level.*/
+ stop_step = 1;
+ break;
+a896 1
+ /* No subroutince call; stop now. */
+d899 5
+d908 6
+d983 4
+d993 2
+a994 1
+ (get_current_frame ())->pc = read_pc ();
+@
diff --git a/gdb/RCS/m-aux.h,v b/gdb/RCS/m-aux.h,v
new file mode 100644
index 0000000..2bf0702
--- /dev/null
+++ b/gdb/RCS/m-aux.h,v
@@ -0,0 +1,591 @@
+head 1.4;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.4
+date 89.04.26.00.51.42; author gnu; state Exp;
+branches ;
+next 1.3;
+
+1.3
+date 89.03.27.20.16.05; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.03.26.20.13.28; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.13.19.16.52; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.4
+log
+@(1) Defined the big-endianness of the target machine.
+(2) Define float to be IEEE compatible.
+(3) Define invalid floats to be NaNs.
+@
+text
+@/* Parameters for execution on A/UX, for GDB, the GNU debugger.
+ Copyright (C) 1989 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#ifndef aux
+#define aux
+#endif
+
+/* It's a USG system */
+#define USG
+
+/* Assembler instructions in USG "SGS" (sw generation system) format */
+#define USG_SGS_ASM
+
+/* Debugger information will be in COFF format. */
+#define COFF_FORMAT
+#define COFF_NO_LONG_FILE_NAMES
+
+/* Terminal interface via termio */
+#define HAVE_TERMIO
+
+/* Unisoft fucked up the include files */
+#define UNISOFT_ASSHOLES
+
+/* Big or Little-Endian target machine
+ BITS: defined if bit #0 is the high-order bit of a byte.
+ BYTES:defined if byte#0 is the high-order byte of an int.
+ WORDS:defined if word#0 is the high-order word of a double. */
+#define BITS_BIG_ENDIAN
+#define BYTES_BIG_ENDIAN
+#define WORDS_BIG_ENDIAN
+
+/* Floating point is IEEE compatible */
+#define IEEE_FLOAT
+
+/* Offset from address of function to start of its code.
+ Zero on most machines. */
+
+#define FUNCTION_START_OFFSET 0
+
+/* Advance PC across any function entry prologue instructions
+ to reach some "real" code. */
+
+#define SKIP_PROLOGUE(pc) \
+{ register int op = read_memory_integer (pc, 2); \
+ if (op == 0047126) \
+ pc += 4; /* Skip link #word */ \
+ else if (op == 0044016) \
+ pc += 6; /* Skip link #long */ \
+}
+
+/* Immediately after a function call, return the saved pc.
+ Can't go through the frames for this because on some machines
+ the new frame is not set up until the new function executes
+ some instructions. */
+
+#define SAVED_PC_AFTER_CALL(frame) \
+read_memory_integer (read_register (SP_REGNUM), 4)
+
+/* Address of end of stack space. */
+
+#define STACK_END_ADDR 0x20000000
+
+/* Stack grows downward. */
+
+#define INNER_THAN <
+
+/* Sequence of bytes for breakpoint instruction. */
+/* A/UX uses "trap &1" */
+
+#define BREAKPOINT {0x4e, 0x41}
+
+/* Amount PC must be decremented by after a breakpoint.
+ This is often the number of bytes in BREAKPOINT
+ but not always. */
+
+#define DECR_PC_AFTER_BREAK 0
+
+/* Nonzero if instruction at PC is a return instruction. */
+
+#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75)
+
+/* Return 1 if P points to an invalid floating point value. */
+/* FIXME, it's not clear what "invalid" means here. I take it to mean
+ "something that coredumps gdb if gdb tries to manipulate it" */
+
+#define INVALID_FLOAT(p, len) is_nan(p, len)
+
+/* Largest integer type */
+#define LONGEST long
+
+/* Name of the builtin type for the LONGEST type above. */
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+
+/* Say how long (ordinary) registers are. */
+
+#define REGISTER_TYPE long
+
+/* Number of machine registers */
+
+#define NUM_REGS 29
+
+/* Initializer for an array of names of registers.
+ There should be NUM_REGS strings in this initializer. */
+
+#define REGISTER_NAMES \
+ {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \
+ "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \
+ "ps", "pc", \
+ "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \
+ "fpcontrol", "fpstatus", "fpiaddr" }
+
+/* Register numbers of various important registers.
+ Note that some of these values are "real" register numbers,
+ and correspond to the general registers of the machine,
+ and some are "phony" register numbers which are too large
+ to be actual register numbers as far as the user is concerned
+ but do serve to get the desired values when passed to read_register. */
+
+#define FP_REGNUM 14 /* Contains address of executing stack frame */
+#define SP_REGNUM 15 /* Contains address of top of stack */
+#define PS_REGNUM 16 /* Contains processor status */
+#define PC_REGNUM 17 /* Contains program counter */
+#define FP0_REGNUM 18 /* Floating point register 0 */
+#define FPC_REGNUM 26 /* 68881 control register */
+
+/* This is a piece of magic that is given a register number REGNO
+ and as BLOCKEND the address in the system of the end of the user structure
+ and stores in ADDR the address in the kernel or core dump
+ of that register. */
+
+#define REGISTER_U_ADDR(addr, blockend, regno) { \
+ struct user u; \
+ if (regno <= SP_REGNUM) \
+ addr = blockend + regno * 4; \
+ else if (regno == PS_REGNUM) \
+ addr = blockend + RPS * 4; /* From reg.h */ \
+ else if (regno == PC_REGNUM) \
+ addr = blockend + PC * 4; /* From reg.h */ \
+ else if (regno < FPC_REGNUM) \
+ addr = (char *) u.u_fpdreg [regno-FP0_REGNUM] - (char *)&u; \
+ else \
+ addr = (char *)&u.u_fpsysreg[regno-FPC_REGNUM] - (char *)&u; \
+}
+
+/* Describe the pointer in each stack frame to the previous stack frame
+ (its caller). */
+/* Total amount of space needed to store our copies of the machine's
+ register state, the array `registers'. */
+#define REGISTER_BYTES (16*4+8*12+8+20)
+
+/* Index within `registers' of the first byte of the space for
+ register N. */
+
+#define REGISTER_BYTE(N) \
+ ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \
+ : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \
+ : (N) * 4)
+
+/* Number of bytes of storage in the actual machine representation
+ for register N. On the 68000, all regs are 4 bytes
+ except the floating point regs which are 12 bytes. */
+/* Note that the unsigned cast here forces the result of the
+ subtractiion to very high positive values if N < FP0_REGNUM */
+
+#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4)
+
+/* Number of bytes of storage in the program's representation
+ for register N. On the 68000, all regs are 4 bytes
+ except the floating point regs which are 8-byte doubles. */
+
+#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4)
+
+/* Largest value REGISTER_RAW_SIZE can have. */
+
+#define MAX_REGISTER_RAW_SIZE 12
+
+/* Largest value REGISTER_VIRTUAL_SIZE can have. */
+
+#define MAX_REGISTER_VIRTUAL_SIZE 8
+
+/* Nonzero if register N requires conversion
+ from raw format to virtual format. */
+
+#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8)
+
+/* Convert data from raw format for register REGNUM
+ to virtual format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
+{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
+ convert_from_68881 ((FROM), (TO)); \
+ else \
+ bcopy ((FROM), (TO), 4); }
+
+/* Convert data from virtual format for register REGNUM
+ to raw format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
+{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
+ convert_to_68881 ((FROM), (TO)); \
+ else \
+ bcopy ((FROM), (TO), 4); }
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+
+#define REGISTER_VIRTUAL_TYPE(N) \
+ (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
+
+/* Store the address of the place in which to copy the structure the
+ subroutine will return. This is called from call_function. */
+
+#define STORE_STRUCT_RETURN(ADDR, SP) \
+ { write_register (9, (ADDR)); }
+
+/* Extract from an array REGBUF containing the (raw) register state
+ a function return value of type TYPE, and copy that, in virtual format,
+ into VALBUF. */
+
+#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
+ bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE))
+
+/* Write into appropriate registers a function return value
+ of type TYPE, given in virtual format. */
+
+#define STORE_RETURN_VALUE(TYPE,VALBUF) \
+ write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
+
+/* Extract from an array REGBUF containing the (raw) register state
+ the address in which a function should return its structure value,
+ as a CORE_ADDR (or an expression that can be used as one). */
+
+#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
+
+
+/* Describe the pointer in each stack frame to the previous stack frame
+ (its caller). */
+
+/* FRAME_CHAIN takes a frame's nominal address
+ and produces the frame's chain-pointer.
+
+ FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
+ and produces the nominal address of the caller frame.
+
+ However, if FRAME_CHAIN_VALID returns zero,
+ it means the given frame is the outermost one and has no caller.
+ In that case, FRAME_CHAIN_COMBINE is not used. */
+
+/* In the case of the 68k, the frame's nominal address
+ is the address of a 4-byte word containing the calling frame's address. */
+
+#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
+
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
+
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+
+/* Define other aspects of the stack frame. */
+
+#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
+
+#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
+
+#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
+
+/* Set VAL to the number of args passed to frame described by FI.
+ Can set VAL to -1, meaning no way to tell. */
+
+/* We can't tell how many args there are
+ now that the C compiler delays popping them. */
+#define FRAME_NUM_ARGS(val,fi) (val = -1)
+
+#if 0
+#define FRAME_NUM_ARGS(val, fi) \
+{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
+ register int insn = 0177777 & read_memory_integer (pc, 2); \
+ val = 0; \
+ if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
+ val = read_memory_integer (pc + 2, 2); \
+ else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \
+ || (insn & 0170777) == 0050117) /* addqw */ \
+ { val = (insn >> 9) & 7; if (val == 0) val = 8; } \
+ else if (insn == 0157774) /* addal #WW, sp */ \
+ val = read_memory_integer (pc + 2, 4); \
+ val >>= 2; }
+#endif
+
+/* Return number of bytes at start of arglist that are not really args. */
+
+#define FRAME_ARGS_SKIP 8
+
+/* Put here the code to store, into a struct frame_saved_regs,
+ the addresses of the saved registers of frame described by FRAME_INFO.
+ This includes special registers such as pc and fp saved in special
+ ways in the stack frame. sp is even more special:
+ the address we return for it IS the sp for the next frame. */
+
+#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
+{ register int regnum; \
+ register int regmask; \
+ register CORE_ADDR next_addr; \
+ register CORE_ADDR pc; \
+ int nextinsn; \
+ bzero (&frame_saved_regs, sizeof frame_saved_regs); \
+ if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
+ && (frame_info)->pc <= (frame_info)->frame) \
+ { next_addr = (frame_info)->frame; \
+ pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
+ else \
+ { pc = get_pc_function_start ((frame_info)->pc); \
+ /* Verify we have a link a6 instruction next; \
+ if not we lose. If we win, find the address above the saved \
+ regs using the amount of storage from the link instruction. */\
+ if (044016 == read_memory_integer (pc, 2)) \
+ next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \
+ else if (047126 == read_memory_integer (pc, 2)) \
+ next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \
+ else goto lose; \
+ /* If have an addal #-n, sp next, adjust next_addr. */ \
+ if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
+ next_addr += read_memory_integer (pc += 2, 4), pc += 4; \
+ } \
+ /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \
+ regmask = read_memory_integer (pc + 2, 2); \
+ /* But before that can come an fmovem. Check for it. */ \
+ nextinsn = 0xffff & read_memory_integer (pc, 2); \
+ if (0xf227 == nextinsn \
+ && (regmask & 0xff00) == 0xe000) \
+ { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \
+ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \
+ if (regmask & 1) \
+ (frame_saved_regs).regs[regnum] = (next_addr -= 12); \
+ regmask = read_memory_integer (pc + 2, 2); } \
+ if (0044327 == read_memory_integer (pc, 2)) \
+ { pc += 4; /* Regmask's low bit is for register 0, the first written */ \
+ for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \
+ if (regmask & 1) \
+ (frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \
+ else if (0044347 == read_memory_integer (pc, 2)) \
+ { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \
+ for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \
+ if (regmask & 1) \
+ (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
+ else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) \
+ { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \
+ (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
+ /* fmovemx to index of sp may follow. */ \
+ regmask = read_memory_integer (pc + 2, 2); \
+ nextinsn = 0xffff & read_memory_integer (pc, 2); \
+ if (0xf236 == nextinsn \
+ && (regmask & 0xff00) == 0xf000) \
+ { pc += 10; /* Regmask's low bit is for register fp0, the first written */ \
+ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \
+ if (regmask & 1) \
+ (frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \
+ regmask = read_memory_integer (pc + 2, 2); } \
+ /* clrw -(sp); movw ccr,-(sp) may follow. */ \
+ if (0x426742e7 == read_memory_integer (pc, 4)) \
+ (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
+ lose: ; \
+ (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
+ (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
+ (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
+}
+
+/* Things needed for making the inferior call functions. */
+
+/* Push an empty stack frame, to record the current PC, etc. */
+
+#define PUSH_DUMMY_FRAME \
+{ register CORE_ADDR sp = read_register (SP_REGNUM); \
+ register int regnum; \
+ char raw_buffer[12]; \
+ sp = push_word (sp, read_register (PC_REGNUM)); \
+ sp = push_word (sp, read_register (FP_REGNUM)); \
+ write_register (FP_REGNUM, sp); \
+ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
+ { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \
+ sp = push_bytes (sp, raw_buffer, 12); } \
+ for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
+ sp = push_word (sp, read_register (regnum)); \
+ sp = push_word (sp, read_register (PS_REGNUM)); \
+ write_register (SP_REGNUM, sp); }
+
+/* Discard from the stack the innermost frame,
+ restoring all saved registers. */
+
+#define POP_FRAME \
+{ register FRAME frame = get_current_frame (); \
+ register CORE_ADDR fp; \
+ register int regnum; \
+ struct frame_saved_regs fsr; \
+ struct frame_info *fi; \
+ char raw_buffer[12]; \
+ fi = get_frame_info (frame); \
+ fp = fi->frame; \
+ get_frame_saved_regs (fi, &fsr); \
+ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
+ if (fsr.regs[regnum]) \
+ { read_memory (fsr.regs[regnum], raw_buffer, 12); \
+ write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\
+ for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
+ if (fsr.regs[regnum]) \
+ write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
+ if (fsr.regs[PS_REGNUM]) \
+ write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
+ write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
+ write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
+ write_register (SP_REGNUM, fp + 8); \
+ flush_cached_frames (); \
+ set_current_frame (create_new_frame (read_register (FP_REGNUM),\
+ read_pc ())); }
+
+/* This sequence of words is the instructions
+ fmovem 0xff,-(sp)
+ moveml 0xfffc,-(sp)
+ clrw -(sp)
+ movew ccr,-(sp)
+ /..* The arguments are pushed at this point by GDB;
+ no code is needed in the dummy for this.
+ The CALL_DUMMY_START_OFFSET gives the position of
+ the following jsr instruction. *../
+ jsr @@#32323232
+ addl #69696969,sp
+ trap #15
+ nop
+Note this is 28 bytes.
+We actually start executing at the jsr, since the pushing of the
+registers is done by PUSH_DUMMY_FRAME. If this were real code,
+the arguments for the function called by the jsr would be pushed
+between the moveml and the jsr, and we could allow it to execute through.
+But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done,
+and we cannot allow the moveml to push the registers again lest they be
+taken for the arguments. */
+
+#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71}
+
+#define CALL_DUMMY_LENGTH 28
+
+#define CALL_DUMMY_START_OFFSET 12
+
+/* Insert the specified number of args and function address
+ into a call sequence of the above form stored at DUMMYNAME. */
+
+#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
+{ *(int *)((char *) dummyname + 20) = nargs * 4; \
+ *(int *)((char *) dummyname + 14) = fun; }
+
+/* Interface definitions for kernel debugger KDB. */
+
+/* Map machine fault codes into signal numbers.
+ First subtract 0, divide by 4, then index in a table.
+ Faults for which the entry in this table is 0
+ are not handled by KDB; the program's own trap handler
+ gets to handle then. */
+
+#define FAULT_CODE_ORIGIN 0
+#define FAULT_CODE_UNITS 4
+#define FAULT_TABLE \
+{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \
+ 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ SIGILL }
+
+/* Start running with a stack stretching from BEG to END.
+ BEG and END should be symbols meaningful to the assembler.
+ This is used only for kdb. */
+
+#define INIT_STACK(beg, end) \
+{ asm (".globl end"); \
+ asm ("movel #end, sp"); \
+ asm ("movel #0,a6"); }
+
+/* Push the frame pointer register on the stack. */
+#define PUSH_FRAME_PTR \
+ asm ("movel a6,sp@@-");
+
+/* Copy the top-of-stack to the frame pointer register. */
+#define POP_FRAME_PTR \
+ asm ("movl sp@@,a6");
+
+/* After KDB is entered by a fault, push all registers
+ that GDB thinks about (all NUM_REGS of them),
+ so that they appear in order of ascending GDB register number.
+ The fault code will be on the stack beyond the last register. */
+
+#define PUSH_REGISTERS \
+{ asm ("clrw -(sp)"); \
+ asm ("pea sp@@(10)"); \
+ asm ("movem #0xfffe,sp@@-"); }
+
+/* Assuming the registers (including processor status) have been
+ pushed on the stack in order of ascending GDB register number,
+ restore them and return to the address in the saved PC register. */
+
+#define POP_REGISTERS \
+{ asm ("subil #8,sp@@(28)"); \
+ asm ("movem sp@@,#0xffff"); \
+ asm ("rte"); }
+@
+
+
+1.3
+log
+@Fix DECR_PC_AFTER_BREAK; A/UX reports breaks at the breakpoint addr,
+not there+2.
+@
+text
+@d41 11
+d100 2
+d103 1
+a103 1
+#define INVALID_FLOAT(p, len) 1 /* FIXME! Just a first guess; not checked */
+@
+
+
+1.2
+log
+@Mostly works!
+@
+text
+@d82 1
+a82 1
+#define DECR_PC_AFTER_BREAK 2
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d1 504
+@
diff --git a/gdb/RCS/m-hp9k320.h,v b/gdb/RCS/m-hp9k320.h,v
new file mode 100644
index 0000000..8df1709
--- /dev/null
+++ b/gdb/RCS/m-hp9k320.h,v
@@ -0,0 +1,607 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.03.27.20.17.11; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.20.19.29.58; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Change "HPUX_ASM" define to "USG_SGS_ASM", since it's really the USG
+Software Generation System assembler that we're fighting here.
+.,
+@
+text
+@/* Parameters for execution on an HP 9000 model 320, for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#ifndef HP9K320
+#define HP9K320
+#endif
+
+/* Set flag to indicate whether HP's assembler is in use. */
+#ifdef __GNU__
+#ifdef __HPUX_ASM__
+#define USG_SGS_ASM
+#endif
+#else
+#define USG_SGS_ASM
+#endif
+
+/* Define this for versions of hp-ux older than 6.0 */
+/* #define HPUX_VERSION_5 */
+
+/* define USG if you are using sys5 /usr/include's */
+#define USG
+
+#define HAVE_TERMIO
+
+/* Get rid of any system-imposed stack limit if possible. */
+
+/* #define SET_STACK_LIMIT_HUGE */
+
+/* Define this if the C compiler puts an underscore at the front
+ of external names before giving them to the linker. */
+
+#define NAMES_HAVE_UNDERSCORE
+
+/* Debugger information will be in DBX format. */
+
+#define READ_DBX_FORMAT
+
+/* Offset from address of function to start of its code.
+ Zero on most machines. */
+
+#define FUNCTION_START_OFFSET 0
+
+/* Advance PC across any function entry prologue instructions
+ to reach some "real" code. */
+
+#define SKIP_PROLOGUE(pc) \
+{ register int op = read_memory_integer (pc, 2); \
+ if (op == 0047126) \
+ pc += 4; /* Skip link #word */ \
+ else if (op == 0044016) \
+ pc += 6; /* Skip link #long */ \
+}
+
+/* Immediately after a function call, return the saved pc.
+ Can't go through the frames for this because on some machines
+ the new frame is not set up until the new function executes
+ some instructions. */
+
+#define SAVED_PC_AFTER_CALL(frame) \
+read_memory_integer (read_register (SP_REGNUM), 4)
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#ifdef HPUX_VERSION_5
+#define KERNEL_U_ADDR 0x00979000
+#else
+#define KERNEL_U_ADDR 0x00C01000
+#endif
+
+/* Address of end of stack space. */
+
+#define STACK_END_ADDR 0xFFF00000
+
+/* Stack grows downward. */
+
+#define INNER_THAN <
+
+/* Sequence of bytes for breakpoint instruction. */
+
+#define BREAKPOINT {0x4e, 0x41}
+
+/* Amount PC must be decremented by after a breakpoint.
+ This is often the number of bytes in BREAKPOINT
+ but not always. */
+
+#define DECR_PC_AFTER_BREAK 2
+
+/* Nonzero if instruction at PC is a return instruction. */
+
+#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75)
+
+/* Return 1 if P points to an invalid floating point value. */
+
+#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
+
+/* Largest integer type */
+#define LONGEST long
+
+/* Name of the builtin type for the LONGEST type above. */
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+
+/* Say how long (ordinary) registers are. */
+
+#define REGISTER_TYPE long
+
+/* Number of machine registers */
+
+#define NUM_REGS 29
+
+/* Initializer for an array of names of registers.
+ There should be NUM_REGS strings in this initializer. */
+
+#define REGISTER_NAMES \
+ {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \
+ "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \
+ "ps", "pc", \
+ "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \
+ "fpcontrol", "fpstatus", "fpiaddr" }
+
+/* Register numbers of various important registers.
+ Note that some of these values are "real" register numbers,
+ and correspond to the general registers of the machine,
+ and some are "phony" register numbers which are too large
+ to be actual register numbers as far as the user is concerned
+ but do serve to get the desired values when passed to read_register. */
+
+#define FP_REGNUM 14 /* Contains address of executing stack frame */
+#define SP_REGNUM 15 /* Contains address of top of stack */
+#define PS_REGNUM 16 /* Contains processor status */
+#define PC_REGNUM 17 /* Contains program counter */
+#define FP0_REGNUM 18 /* Floating point register 0 */
+#define FPC_REGNUM 26 /* 68881 control register */
+
+/* Total amount of space needed to store our copies of the machine's
+ register state, the array `registers'. */
+#define REGISTER_BYTES (16*4+8*12+8+12)
+
+/* Index within `registers' of the first byte of the space for
+ register N. */
+
+#define REGISTER_BYTE(N) \
+ ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \
+ : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \
+ : (N) * 4)
+
+/* Number of bytes of storage in the actual machine representation
+ for register N. On the 68000, all regs are 4 bytes
+ except the floating point regs which are 12 bytes. */
+
+#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4)
+
+/* Number of bytes of storage in the program's representation
+ for register N. On the 68000, all regs are 4 bytes
+ except the floating point regs which are 8-byte doubles. */
+
+#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4)
+
+/* Largest value REGISTER_RAW_SIZE can have. */
+
+#define MAX_REGISTER_RAW_SIZE 12
+
+/* Largest value REGISTER_VIRTUAL_SIZE can have. */
+
+#define MAX_REGISTER_VIRTUAL_SIZE 8
+
+/* Nonzero if register N requires conversion
+ from raw format to virtual format. */
+
+#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8)
+
+/* Convert data from raw format for register REGNUM
+ to virtual format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
+{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
+ convert_from_68881 ((FROM), (TO)); \
+ else \
+ bcopy ((FROM), (TO), 4); }
+
+/* Convert data from virtual format for register REGNUM
+ to raw format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
+{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
+ convert_to_68881 ((FROM), (TO)); \
+ else \
+ bcopy ((FROM), (TO), 4); }
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+
+#define REGISTER_VIRTUAL_TYPE(N) \
+ (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
+
+/* Store the address of the place in which to copy the structure the
+ subroutine will return. This is called from call_function. */
+
+#define STORE_STRUCT_RETURN(ADDR, SP) \
+ { write_register (9, (ADDR)); }
+
+/* Extract from an array REGBUF containing the (raw) register state
+ a function return value of type TYPE, and copy that, in virtual format,
+ into VALBUF. */
+
+#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
+ bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE))
+
+/* Write into appropriate registers a function return value
+ of type TYPE, given in virtual format. */
+
+#define STORE_RETURN_VALUE(TYPE,VALBUF) \
+ write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
+
+/* Extract from an array REGBUF containing the (raw) register state
+ the address in which a function should return its structure value,
+ as a CORE_ADDR (or an expression that can be used as one). */
+
+#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
+
+#define REGISTER_ADDR(u_ar0, regno) \
+ (((regno) < PS_REGNUM) \
+ ? (&((struct exception_stack *) (u_ar0))->e_regs[(regno + R0)]) \
+ : (((regno) == PS_REGNUM) \
+ ? ((int *) (&((struct exception_stack *) (u_ar0))->e_PS)) \
+ : (&((struct exception_stack *) (u_ar0))->e_PC)))
+
+#define FP_REGISTER_ADDR(u, regno) \
+ (((char *) \
+ (((regno) < FPC_REGNUM) \
+ ? (&u.u_pcb.pcb_mc68881[FMC68881_R0 + (((regno) - FP0_REGNUM) * 3)]) \
+ : (&u.u_pcb.pcb_mc68881[FMC68881_C + ((regno) - FPC_REGNUM)]))) \
+ - ((char *) (& u)))
+
+/* It is safe to look for symsegs on a Sun, because Sun's ld
+ does not screw up with random garbage at end of file. */
+
+#define READ_GDB_SYMSEGS
+
+/* Describe the pointer in each stack frame to the previous stack frame
+ (its caller). */
+
+/* FRAME_CHAIN takes a frame's nominal address
+ and produces the frame's chain-pointer.
+
+ FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
+ and produces the nominal address of the caller frame.
+
+ However, if FRAME_CHAIN_VALID returns zero,
+ it means the given frame is the outermost one and has no caller.
+ In that case, FRAME_CHAIN_COMBINE is not used. */
+
+/* In the case of the Sun, the frame's nominal address
+ is the address of a 4-byte word containing the calling frame's address. */
+
+#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
+
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
+
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+
+/* Define other aspects of the stack frame. */
+
+#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
+
+#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
+
+#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
+
+/* Set VAL to the number of args passed to frame described by FI.
+ Can set VAL to -1, meaning no way to tell. */
+
+/* We can't tell how many args there are
+ now that the C compiler delays popping them. */
+#define FRAME_NUM_ARGS(val,fi) (val = -1)
+
+#if 0
+#define FRAME_NUM_ARGS(val, fi) \
+{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
+ register int insn = 0177777 & read_memory_integer (pc, 2); \
+ val = 0; \
+ if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
+ val = read_memory_integer (pc + 2, 2); \
+ else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \
+ || (insn & 0170777) == 0050117) /* addqw */ \
+ { val = (insn >> 9) & 7; if (val == 0) val = 8; } \
+ else if (insn == 0157774) /* addal #WW, sp */ \
+ val = read_memory_integer (pc + 2, 4); \
+ val >>= 2; }
+#endif
+
+/* Return number of bytes at start of arglist that are not really args. */
+
+#define FRAME_ARGS_SKIP 8
+
+/* Put here the code to store, into a struct frame_saved_regs,
+ the addresses of the saved registers of frame described by FRAME_INFO.
+ This includes special registers such as pc and fp saved in special
+ ways in the stack frame. sp is even more special:
+ the address we return for it IS the sp for the next frame. */
+
+#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
+{ register int regnum; \
+ register int regmask; \
+ register CORE_ADDR next_addr; \
+ register CORE_ADDR pc; \
+ int nextinsn; \
+ bzero (&frame_saved_regs, sizeof frame_saved_regs); \
+ if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
+ && (frame_info)->pc <= (frame_info)->frame) \
+ { next_addr = (frame_info)->frame; \
+ pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
+ else \
+ { pc = get_pc_function_start ((frame_info)->pc); \
+ /* Verify we have a link a6 instruction next; \
+ if not we lose. If we win, find the address above the saved \
+ regs using the amount of storage from the link instruction. */\
+ if (044016 == read_memory_integer (pc, 2)) \
+ next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \
+ else if (047126 == read_memory_integer (pc, 2)) \
+ next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \
+ else goto lose; \
+ /* If have an addal #-n, sp next, adjust next_addr. */ \
+ if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
+ next_addr += read_memory_integer (pc += 2, 4), pc += 4; \
+ } \
+ /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \
+ regmask = read_memory_integer (pc + 2, 2); \
+ /* But before that can come an fmovem. Check for it. */ \
+ nextinsn = 0xffff & read_memory_integer (pc, 2); \
+ if (0xf227 == nextinsn \
+ && (regmask & 0xff00) == 0xe000) \
+ { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \
+ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \
+ if (regmask & 1) \
+ (frame_saved_regs).regs[regnum] = (next_addr -= 12); \
+ regmask = read_memory_integer (pc + 2, 2); } \
+ if (0044327 == read_memory_integer (pc, 2)) \
+ { pc += 4; /* Regmask's low bit is for register 0, the first written */ \
+ for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \
+ if (regmask & 1) \
+ (frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \
+ else if (0044347 == read_memory_integer (pc, 2)) \
+ { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \
+ for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \
+ if (regmask & 1) \
+ (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
+ else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \
+ { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \
+ (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
+ /* fmovemx to index of sp may follow. */ \
+ regmask = read_memory_integer (pc + 2, 2); \
+ nextinsn = 0xffff & read_memory_integer (pc, 2); \
+ if (0xf236 == nextinsn \
+ && (regmask & 0xff00) == 0xf000) \
+ { pc += 10; /* Regmask's low bit is for register fp0, the first written */ \
+ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \
+ if (regmask & 1) \
+ (frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \
+ regmask = read_memory_integer (pc + 2, 2); } \
+ /* clrw -(sp); movw ccr,-(sp) may follow. */ \
+ if (0x426742e7 == read_memory_integer (pc, 4)) \
+ (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
+ lose: ; \
+ (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
+ (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
+ (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
+}
+
+/* Things needed for making the inferior call functions. */
+
+/* Push an empty stack frame, to record the current PC, etc. */
+
+#define PUSH_DUMMY_FRAME \
+{ register CORE_ADDR sp = read_register (SP_REGNUM); \
+ register int regnum; \
+ char raw_buffer[12]; \
+ sp = push_word (sp, read_register (PC_REGNUM)); \
+ sp = push_word (sp, read_register (FP_REGNUM)); \
+ write_register (FP_REGNUM, sp); \
+ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
+ { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \
+ sp = push_bytes (sp, raw_buffer, 12); } \
+ for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
+ sp = push_word (sp, read_register (regnum)); \
+ sp = push_word (sp, read_register (PS_REGNUM)); \
+ write_register (SP_REGNUM, sp); }
+
+/* Discard from the stack the innermost frame,
+ restoring all saved registers. */
+
+#define POP_FRAME \
+{ register FRAME frame = get_current_frame (); \
+ register CORE_ADDR fp; \
+ register int regnum; \
+ struct frame_saved_regs fsr; \
+ struct frame_info *fi; \
+ char raw_buffer[12]; \
+ fi = get_frame_info (frame); \
+ fp = fi->frame; \
+ get_frame_saved_regs (fi, &fsr); \
+ for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
+ if (fsr.regs[regnum]) \
+ { read_memory (fsr.regs[regnum], raw_buffer, 12); \
+ write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\
+ for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
+ if (fsr.regs[regnum]) \
+ write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
+ if (fsr.regs[PS_REGNUM]) \
+ write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
+ write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
+ write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
+ write_register (SP_REGNUM, fp + 8); \
+ flush_cached_frames (); \
+ set_current_frame (create_new_frame (read_register (FP_REGNUM),\
+ read_pc ()));}
+
+/* This sequence of words is the instructions
+ fmovem 0xff,-(sp)
+ moveml 0xfffc,-(sp)
+ clrw -(sp)
+ movew ccr,-(sp)
+ /..* The arguments are pushed at this point by GDB;
+ no code is needed in the dummy for this.
+ The CALL_DUMMY_START_OFFSET gives the position of
+ the following jsr instruction. *../
+ jsr @@#32323232
+ addl #69696969,sp
+ bpt
+ nop
+Note this is 28 bytes.
+We actually start executing at the jsr, since the pushing of the
+registers is done by PUSH_DUMMY_FRAME. If this were real code,
+the arguments for the function called by the jsr would be pushed
+between the moveml and the jsr, and we could allow it to execute through.
+But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done,
+and we cannot allow the moveml to push the registers again lest they be
+taken for the arguments. */
+
+#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e414e71}
+
+#define CALL_DUMMY_LENGTH 28
+
+#define CALL_DUMMY_START_OFFSET 12
+
+/* Insert the specified number of args and function address
+ into a call sequence of the above form stored at DUMMYNAME. */
+
+#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
+{ *(int *)((char *) dummyname + 20) = nargs * 4; \
+ *(int *)((char *) dummyname + 14) = fun; }
+
+/* Interface definitions for kernel debugger KDB. */
+
+/* Map machine fault codes into signal numbers.
+ First subtract 0, divide by 4, then index in a table.
+ Faults for which the entry in this table is 0
+ are not handled by KDB; the program's own trap handler
+ gets to handle then. */
+
+#define FAULT_CODE_ORIGIN 0
+#define FAULT_CODE_UNITS 4
+#define FAULT_TABLE \
+{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \
+ 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ SIGILL }
+
+#ifndef HPUX_ASM
+
+/* Start running with a stack stretching from BEG to END.
+ BEG and END should be symbols meaningful to the assembler.
+ This is used only for kdb. */
+
+#define INIT_STACK(beg, end) \
+{ asm (".globl end"); \
+ asm ("movel $ end, sp"); \
+ asm ("clrl fp"); }
+
+/* Push the frame pointer register on the stack. */
+#define PUSH_FRAME_PTR \
+ asm ("movel fp, -(sp)");
+
+/* Copy the top-of-stack to the frame pointer register. */
+#define POP_FRAME_PTR \
+ asm ("movl (sp), fp");
+
+/* After KDB is entered by a fault, push all registers
+ that GDB thinks about (all NUM_REGS of them),
+ so that they appear in order of ascending GDB register number.
+ The fault code will be on the stack beyond the last register. */
+
+#define PUSH_REGISTERS \
+{ asm ("clrw -(sp)"); \
+ asm ("pea 10(sp)"); \
+ asm ("movem $ 0xfffe,-(sp)"); }
+
+/* Assuming the registers (including processor status) have been
+ pushed on the stack in order of ascending GDB register number,
+ restore them and return to the address in the saved PC register. */
+
+#define POP_REGISTERS \
+{ asm ("subil $8,28(sp)"); \
+ asm ("movem (sp),$ 0xffff"); \
+ asm ("rte"); }
+
+#else /* HPUX_ASM */
+
+/* Start running with a stack stretching from BEG to END.
+ BEG and END should be symbols meaningful to the assembler.
+ This is used only for kdb. */
+
+#define INIT_STACK(beg, end) \
+{ asm ("global end"); \
+ asm ("mov.l &end,%sp"); \
+ asm ("clr.l %a6"); }
+
+/* Push the frame pointer register on the stack. */
+#define PUSH_FRAME_PTR \
+ asm ("mov.l %fp,-(%sp)");
+
+/* Copy the top-of-stack to the frame pointer register. */
+#define POP_FRAME_PTR \
+ asm ("mov.l (%sp),%fp");
+
+/* After KDB is entered by a fault, push all registers
+ that GDB thinks about (all NUM_REGS of them),
+ so that they appear in order of ascending GDB register number.
+ The fault code will be on the stack beyond the last register. */
+
+#define PUSH_REGISTERS \
+{ asm ("clr.w -(%sp)"); \
+ asm ("pea 10(%sp)"); \
+ asm ("movm.l &0xfffe,-(%sp)"); }
+
+/* Assuming the registers (including processor status) have been
+ pushed on the stack in order of ascending GDB register number,
+ restore them and return to the address in the saved PC register. */
+
+#define POP_REGISTERS \
+{ asm ("subi.l &8,28(%sp)"); \
+ asm ("mov.m (%sp),&0xffff"); \
+ asm ("rte"); }
+
+#endif /* HPUX_ASM */
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d28 1
+a28 1
+#define HPUX_ASM
+d31 1
+a31 1
+#define HPUX_ASM
+@
diff --git a/gdb/RCS/m-sparc.h,v b/gdb/RCS/m-sparc.h,v
new file mode 100644
index 0000000..1720dfe
--- /dev/null
+++ b/gdb/RCS/m-sparc.h,v
@@ -0,0 +1,747 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.3
+date 89.04.26.00.52.29; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.03.16.21.10.29; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.14.15.28.32; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@(1) Define big-endianness of SPARC.
+(2) Define IEEE compatible float.
+@
+text
+@/* Parameters for execution on a Sun 4, for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@@mcc.com)
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#ifndef sun4
+#define sun4
+#endif
+
+/* Get rid of any system-imposed stack limit if possible. */
+
+#define SET_STACK_LIMIT_HUGE
+
+/* Define this if the C compiler puts an underscore at the front
+ of external names before giving them to the linker. */
+
+#define NAMES_HAVE_UNDERSCORE
+
+/* Debugger information will be in DBX format. */
+
+#define READ_DBX_FORMAT
+
+/* Big or Little-Endian target machine
+ BITS: defined if bit #0 is the high-order bit of a byte.
+ BYTES:defined if byte#0 is the high-order byte of an int.
+ WORDS:defined if word#0 is the high-order word of a double. */
+#define BITS_BIG_ENDIAN
+#define BYTES_BIG_ENDIAN
+#define WORDS_BIG_ENDIAN
+
+/* Floating point is IEEE compatible. */
+#define IEEE_FLOAT
+
+/* Offset from address of function to start of its code.
+ Zero on most machines. */
+
+#define FUNCTION_START_OFFSET 0
+
+/* Advance PC across any function entry prologue instructions
+ to reach some "real" code. */
+
+#define SKIP_PROLOGUE(pc) \
+ { pc = skip_prologue (pc); }
+
+/* Immediately after a function call, return the saved pc.
+ Can't go through the frames for this because on some machines
+ the new frame is not set up until the new function executes
+ some instructions. */
+
+/* On the Sun 4 under SunOS, the compile will leave a fake insn which
+ encodes the structure size being returned. If we detect such
+ a fake insn, step past it. */
+
+#define PC_ADJUST(pc) ((read_memory_integer (pc + 8, 4) & 0xfffffe00) == 0 ? \
+ pc+12 : pc+8)
+
+#define SAVED_PC_AFTER_CALL(frame) PC_ADJUST (read_register (RP_REGNUM))
+
+/* Address of end of stack space. */
+
+#define STACK_END_ADDR 0xf8000000
+
+/* Stack grows downward. */
+
+#define INNER_THAN <
+
+/* Stack has strict alignment. */
+
+#define STACK_ALIGN(ADDR) (((ADDR)+7)&-8)
+
+/* Sequence of bytes for breakpoint instruction. */
+
+#define BREAKPOINT {0x91, 0xd0, 0x20, 0x01}
+
+/* Amount PC must be decremented by after a breakpoint.
+ This is often the number of bytes in BREAKPOINT
+ but not always. */
+
+#define DECR_PC_AFTER_BREAK 0
+
+/* Nonzero if instruction at PC is a return instruction. */
+/* For SPARC, this is either a "jmpl %o7+8,%g0" or "jmpl %i7+8,%g0".
+
+ Note: this does not work for functions returning structures under SunOS. */
+#define ABOUT_TO_RETURN(pc) \
+ ((read_memory_integer (pc, 4)|0x00040000) == 0x81c7e008)
+
+/* Return 1 if P points to an invalid floating point value. */
+
+#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
+
+/* Largest integer type */
+#define LONGEST long
+
+/* Name of the builtin type for the LONGEST type above. */
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+
+/* Say how long (ordinary) registers are. */
+
+#define REGISTER_TYPE long
+
+/* Number of machine registers */
+
+#define NUM_REGS 72
+
+/* Initializer for an array of names of registers.
+ There should be NUM_REGS strings in this initializer. */
+
+#define REGISTER_NAMES \
+{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", \
+ "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", \
+ "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", \
+ "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", \
+ \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
+ \
+ "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" };
+
+/* Register numbers of various important registers.
+ Note that some of these values are "real" register numbers,
+ and correspond to the general registers of the machine,
+ and some are "phony" register numbers which are too large
+ to be actual register numbers as far as the user is concerned
+ but do serve to get the desired values when passed to read_register. */
+
+#define FP_REGNUM 30 /* Contains address of executing stack frame */
+#define RP_REGNUM 15 /* Contains return address value, *before* \
+ any windows get switched. */
+#define SP_REGNUM 14 /* Contains address of top of stack, \
+ which is also the bottom of the frame. */
+#define Y_REGNUM 64 /* Temp register for multiplication, etc. */
+#define PS_REGNUM 65 /* Contains processor status */
+#define PC_REGNUM 68 /* Contains program counter */
+#define NPC_REGNUM 69 /* Contains next PC */
+#define FP0_REGNUM 32 /* Floating point register 0 */
+#define FPS_REGNUM 70 /* Floating point status register */
+#define CPS_REGNUM 71 /* Coprocessor status register */
+
+/* Total amount of space needed to store our copies of the machine's
+ register state, the array `registers'. */
+#define REGISTER_BYTES (32*4+32*4+8*4)
+
+/* Index within `registers' of the first byte of the space for
+ register N. */
+/* ?? */
+#define REGISTER_BYTE(N) ((N)*4)
+
+/* The SPARC processor has register windows. */
+
+#define HAVE_REGISTER_WINDOWS
+
+/* Is this register part of the register window system? A yes answer
+ implies that 1) The name of this register will not be the same in
+ other frames, and 2) This register is automatically "saved" (out
+ registers shifting into ins counts) upon subroutine calls and thus
+ there is no need to search more than one stack frame for it. */
+
+#define REGISTER_IN_WINDOW_P(regnum) \
+ ((regnum) >= 8 && (regnum) < 32)
+
+/* Number of bytes of storage in the actual machine representation
+ for register N. */
+
+/* On the SPARC, all regs are 4 bytes. */
+
+#define REGISTER_RAW_SIZE(N) (4)
+
+/* Number of bytes of storage in the program's representation
+ for register N. */
+
+/* On the SPARC, all regs are 4 bytes. */
+
+#define REGISTER_VIRTUAL_SIZE(N) (4)
+
+/* Largest value REGISTER_RAW_SIZE can have. */
+
+#define MAX_REGISTER_RAW_SIZE 8
+
+/* Largest value REGISTER_VIRTUAL_SIZE can have. */
+
+#define MAX_REGISTER_VIRTUAL_SIZE 8
+
+/* Nonzero if register N requires conversion
+ from raw format to virtual format. */
+
+#define REGISTER_CONVERTIBLE(N) (0)
+
+/* Convert data from raw format for register REGNUM
+ to virtual format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
+{ bcopy ((FROM), (TO), 4); }
+
+/* Convert data from virtual format for register REGNUM
+ to raw format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
+{ bcopy ((FROM), (TO), 4); }
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+
+#define REGISTER_VIRTUAL_TYPE(N) \
+ ((N) < 32 ? builtin_type_int : (N) < 64 ? builtin_type_float : \
+ builtin_type_int)
+
+/* Store the address of the place in which to copy the structure the
+ subroutine will return. This is called from call_function. */
+
+#define STORE_STRUCT_RETURN(ADDR, SP) \
+ { write_memory ((SP)+(16*4), &(ADDR), 4); }
+
+/* Extract from an array REGBUF containing the (raw) register state
+ a function return value of type TYPE, and copy that, in virtual format,
+ into VALBUF. */
+
+#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
+ bcopy (((int *)(REGBUF))+8, (VALBUF), TYPE_LENGTH (TYPE))
+
+/* Write into appropriate registers a function return value
+ of type TYPE, given in virtual format. */
+/* On sparc, values are returned in register %o0. */
+#define STORE_RETURN_VALUE(TYPE,VALBUF) \
+ write_register_bytes (REGISTER_BYTE (8), VALBUF, TYPE_LENGTH (TYPE))
+
+/* Extract from an array REGBUF containing the (raw) register state
+ the address in which a function should return its structure value,
+ as a CORE_ADDR (or an expression that can be used as one). */
+
+#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \
+ (read_memory_integer (((int *)(REGBUF))[SP_REGNUM]+(16*4), 4))
+
+/* Enable use of alternate code to read and write registers. */
+
+#define NEW_SUN_PTRACE
+
+/* Enable use of alternate code for Sun's format of core dump file. */
+
+#define NEW_SUN_CORE
+
+/* Do implement the attach and detach commands. */
+
+#define ATTACH_DETACH
+
+/* It is safe to look for symsegs on a Sun, because Sun's ld
+ does not screw up with random garbage at end of file. */
+
+#define READ_GDB_SYMSEGS
+
+
+/* Describe the pointer in each stack frame to the previous stack frame
+ (its caller). */
+#include <machine/reg.h>
+
+#define GET_RWINDOW_REG(FRAME, REG) \
+ (read_memory_integer (&((struct rwindow *)FRAME)->REG, 4))
+
+/* FRAME_CHAIN takes a frame's nominal address
+ and produces the frame's chain-pointer.
+
+ FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
+ and produces the nominal address of the caller frame.
+
+ However, if FRAME_CHAIN_VALID returns zero,
+ it means the given frame is the outermost one and has no caller.
+ In that case, FRAME_CHAIN_COMBINE is not used. */
+
+/* In the case of the Sun 4, the frame-chain's nominal address
+ is held in the frame pointer register.
+
+ On the Sun4, the frame (in %fp) is %sp for the previous frame.
+ From the previous frame's %sp, we can find the previous frame's
+ %fp: it is in the save area just above the previous frame's %sp.
+
+ If we are setting up an arbitrary frame, we'll need to know where
+ it ends. Hence the following. This part of the frame cache
+ structure should be checked before it is assumed that this frame's
+ bottom is in the stack pointer.
+
+ If there isn't a frame below this one, the bottom of this frame is
+ in the stack pointer.
+
+ If there is a frame below this one, and the frame pointers are
+ identical, it's a leaf frame and the bottoms are the same also.
+
+ Otherwise the bottom of this frame is the top of the next frame. */
+
+#define EXTRA_FRAME_INFO FRAME_ADDR bottom;
+#define INIT_EXTRA_FRAME_INFO(fci) \
+ (fci)->bottom = \
+ ((fci)->next ? \
+ ((fci)->frame == (fci)->next_frame ? \
+ (fci)->next->bottom : (fci)->next->frame) : \
+ read_register (SP_REGNUM));
+
+#define FRAME_CHAIN(thisframe) \
+ GET_RWINDOW_REG ((thisframe)->frame, rw_in[6])
+
+/* Avoid checking FRAME_SAVED_PC since that screws us due to
+ improperly set up saved PC on a signal trampoline call */
+#if 0
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
+#else
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0)
+#endif
+
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+
+/* Define other aspects of the stack frame. */
+
+/* Where is the PC for a specific frame */
+
+#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME)
+
+/* If the argument is on the stack, it will be here. */
+#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
+
+#define FRAME_STRUCT_ARGS_ADDRESS(fi) ((fi)->frame)
+
+#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
+
+/* Set VAL to the number of args passed to frame described by FI.
+ Can set VAL to -1, meaning no way to tell. */
+
+/* We can't tell how many args there are
+ now that the C compiler delays popping them. */
+#define FRAME_NUM_ARGS(val,fi) (val = -1)
+
+/* Return number of bytes at start of arglist that are not really args. */
+
+#define FRAME_ARGS_SKIP 68
+
+/* Put here the code to store, into a struct frame_saved_regs,
+ the addresses of the saved registers of frame described by FRAME_INFO.
+ This includes special registers such as pc and fp saved in special
+ ways in the stack frame. sp is even more special:
+ the address we return for it IS the sp for the next frame.
+
+ Note that on register window machines, we are currently making the
+ assumption that window registers are being saved somewhere in the
+ frame in which they are being used. If they are stored in an
+ inferior frame, find_saved_register will break.
+
+ On the Sun 4, the only time all registers are saved is when
+ a dummy frame is involved. Otherwise, the only saved registers
+ are the LOCAL and IN registers which are saved as a result
+ of the "save/restore" opcodes. This condition is determined
+ by address rather than by value. */
+
+#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \
+{ register int regnum; \
+ register CORE_ADDR pc; \
+ FRAME_ADDR frame = read_register (FP_REGNUM); \
+ FRAME fid = FRAME_INFO_ID (fi); \
+ if (!fid) fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS"); \
+ bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \
+ if ((fi)->pc >= frame - CALL_DUMMY_LENGTH - 0x140 \
+ && (fi)->pc <= frame) \
+ { \
+ for (regnum = 1; regnum < 8; regnum++) \
+ (frame_saved_regs).regs[regnum] = \
+ frame + regnum * 4 - 0xa0; \
+ for (regnum = 24; regnum < 32; regnum++) \
+ (frame_saved_regs).regs[regnum] = \
+ frame + (regnum - 24) * 4 - 0xc0; \
+ for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++) \
+ (frame_saved_regs).regs[regnum] = \
+ frame + (regnum - FP0_REGNUM) * 4 - 0x80; \
+ for (regnum = 64; regnum < NUM_REGS; regnum++) \
+ (frame_saved_regs).regs[regnum] = \
+ frame + (regnum - 64) * 4 - 0xe0; \
+ frame = (fi)->bottom ? \
+ (fi)->bottom : read_register (SP_REGNUM); \
+ } \
+ else \
+ { \
+ frame = (fi)->bottom ? \
+ (fi)->bottom : read_register (SP_REGNUM); \
+ for (regnum = 16; regnum < 32; regnum++) \
+ (frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \
+ } \
+ if ((fi)->next) \
+ { \
+ /* Pull off either the next frame pointer or \
+ the stack pointer */ \
+ FRAME_ADDR next_next_frame = \
+ ((fi)->next->bottom ? \
+ (fi)->next->bottom : \
+ read_register (SP_REGNUM)); \
+ for (regnum = 8; regnum < 16; regnum++) \
+ (frame_saved_regs).regs[regnum] = next_next_frame + regnum * 4; \
+ } \
+ /* Otherwise, whatever we would get from ptrace(GETREGS) */ \
+ /* is accurate */ \
+ for (regnum = 30; regnum < 32; regnum++) \
+ (frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \
+ (frame_saved_regs).regs[SP_REGNUM] = frame; \
+ (frame_saved_regs).regs[PC_REGNUM] = frame + 15*4; \
+}
+
+/* Things needed for making the inferior call functions. */
+/*
+ * First of all, let me give my opinion of what the DUMMY_FRAME
+ * actually looks like.
+ *
+ * | |
+ * | |
+ * + - - - - - - - - - - - - - - - - +<-- fp (level 0)
+ * | |
+ * | |
+ * | |
+ * | |
+ * | Frame of innermost program |
+ * | function |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * |---------------------------------|<-- sp (level 0), fp (c)
+ * | |
+ * DUMMY | fp0-31 |
+ * | |
+ * | ------ |<-- fp - 0x80
+ * FRAME | g0-7 |<-- fp - 0xa0
+ * | i0-7 |<-- fp - 0xc0
+ * | other |<-- fp - 0xe0
+ * | ? |
+ * | ? |
+ * |---------------------------------|<-- sp' = fp - 0x140
+ * | |
+ * xcution start | |
+ * sp' + 0x94 -->| CALL_DUMMY (x code) |
+ * | |
+ * | |
+ * |---------------------------------|<-- sp'' = fp - 0x200
+ * | align sp to 8 byte boundary |
+ * | ==> args to fn <== |
+ * Room for | |
+ * i & l's + agg | CALL_DUMMY_STACK_ADJUST = 0x0x44|
+ * |---------------------------------|<-- final sp (variable)
+ * | |
+ * | Where function called will |
+ * | build frame. |
+ * | |
+ * | |
+ *
+ * I understand everything in this picture except what the space
+ * between fp - 0xe0 and fp - 0x140 is used for. Oh, and I don't
+ * understand why there's a large chunk of CALL_DUMMY that never gets
+ * executed (its function is superceeded by PUSH_DUMMY_FRAME; they
+ * are designed to do the same thing).
+ *
+ * PUSH_DUMMY_FRAME saves the registers above sp' and pushes the
+ * register file stack down one.
+ *
+ * call_function then writes CALL_DUMMY, pushes the args onto the
+ * stack, and adjusts the stack pointer.
+ *
+ * run_stack_dummy then starts execution (in the middle of
+ * CALL_DUMMY, as directed by call_function).
+ */
+
+/* Push an empty stack frame, to record the current PC, etc. */
+
+/* Note: to be perfectly correct, we have to restore the
+ IN registers (which were the OUT registers of the calling frame). */
+/* Note that the write's are of registers in the context of the newly
+ pushed frame. Thus the the fp*'s, the g*'s, the i*'s, and
+ the others, of the new frame, are being saved.
+ The locals are new; they don't need to be saved. The i's and l's of
+ the last frame were saved by the do_save_insn in the register
+ file (ie. on the stack, since a context switch happended imm after) */
+/* We note that the return pointer register does not *need* to have
+ the pc saved into it (return from this frame will be accomplished
+ by a POP_FRAME), however, just in case it might be needed, we will
+ leave it. However, we will write the original value of RP into the
+ location on the stack for saving i7 (what rp turns into upon call);
+ this way we don't loose the value with our function call. */
+/* Note that the pc saved must be 8 less than the actual pc, since
+ both POP_FRAME and the normal return sequence on the sparc return
+ to 8 more than the value of RP_REGNUM */
+
+#define PUSH_DUMMY_FRAME \
+{ extern char registers[]; \
+ register int regnum; \
+ CORE_ADDR fp = read_register (FP_REGNUM); \
+ CORE_ADDR pc = read_register (PC_REGNUM) - 8; \
+ CORE_ADDR rp = read_register (RP_REGNUM); \
+ void do_save_insn (); \
+ supply_register (RP_REGNUM, &pc); \
+ do_save_insn (0x140); \
+ fp = read_register (FP_REGNUM); \
+ write_memory (fp - 0x80, &registers[REGISTER_BYTE (FP0_REGNUM)], 32 * 4);\
+ write_memory (fp - 0xa0, &registers[REGISTER_BYTE (0)], 8 * 4); \
+ write_memory (fp - 0xc0, &registers[REGISTER_BYTE (24)], 7 * 4); \
+ write_memory (fp - 0xa4, &rp, 4); \
+ write_memory (fp - 0xe0, &registers[REGISTER_BYTE (64)], 8 * 4); \
+}
+
+/* Discard from the stack the innermost frame,
+ restoring all saved registers.
+ Note that the values stored in fsr by get_frame_saved_regs are *in
+ the context of the inferior frame*. What this means is that the i
+ regs of fsr must be restored into the o regs of the frame popped
+ into. We don't care about the output regs of the inferior frame.
+
+ This is true for dummy frames. Is it true for normal frames? It
+ really does appear so. */
+
+#define POP_FRAME \
+{ register FRAME frame = get_current_frame (); \
+ register CORE_ADDR fp; \
+ register CORE_ADDR pc; \
+ register int regnum; \
+ struct frame_saved_regs fsr; \
+ struct frame_info *fi; \
+ char raw_buffer[REGISTER_BYTES]; \
+ void do_restore_insn (); \
+ fi = get_frame_info (frame); \
+ fp = fi->frame; \
+ get_frame_saved_regs (fi, &fsr); \
+ pc = read_memory_integer (fsr.regs[PC_REGNUM], 4); \
+ do_restore_insn (PC_ADJUST (pc)); \
+ if (fsr.regs[FP0_REGNUM]) \
+ { \
+ read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4); \
+ write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer, 32 * 4); \
+ } \
+ if (fsr.regs[1]) \
+ { \
+ read_memory (fsr.regs[1], raw_buffer, 7 * 4); \
+ write_register_bytes (REGISTER_BYTE (1), raw_buffer, 7 * 4); \
+ } \
+ if (fsr.regs[24]) \
+ { \
+ read_memory (fsr.regs[24], raw_buffer, 8 * 4); \
+ write_register_bytes (REGISTER_BYTE (8), raw_buffer, 8 * 4); \
+ } \
+ if (fsr.regs[PS_REGNUM]) \
+ write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
+ if (fsr.regs[Y_REGNUM]) \
+ write_register (Y_REGNUM, read_memory_integer (fsr.regs[Y_REGNUM], 4)); \
+ if (fsr.regs[NPC_REGNUM]) \
+ write_register (NPC_REGNUM, read_memory_integer (fsr.regs[NPC_REGNUM], 4)); \
+ flush_cached_frames (); \
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM), \
+ read_pc ())); }
+
+/* This sequence of words is the instructions
+
+ save %sp,-0x140,%sp
+ std %f30,[%fp-0x08]
+ std %f28,[%fp-0x10]
+ std %f26,[%fp-0x18]
+ std %f24,[%fp-0x20]
+ std %f22,[%fp-0x28]
+ std %f20,[%fp-0x30]
+ std %f18,[%fp-0x38]
+ std %f16,[%fp-0x40]
+ std %f14,[%fp-0x48]
+ std %f12,[%fp-0x50]
+ std %f10,[%fp-0x58]
+ std %f8,[%fp-0x60]
+ std %f6,[%fp-0x68]
+ std %f4,[%fp-0x70]
+ std %f2,[%fp-0x78]
+ std %f0,[%fp-0x80]
+ std %g6,[%fp-0x88]
+ std %g4,[%fp-0x90]
+ std %g2,[%fp-0x98]
+ std %g0,[%fp-0xa0]
+ std %i6,[%fp-0xa8]
+ std %i4,[%fp-0xb0]
+ std %i2,[%fp-0xb8]
+ std %i0,[%fp-0xc0]
+ nop ! stcsr [%fp-0xc4]
+ nop ! stfsr [%fp-0xc8]
+ nop ! wr %npc,[%fp-0xcc]
+ nop ! wr %pc,[%fp-0xd0]
+ rd %tbr,%o0
+ st %o0,[%fp-0xd4]
+ rd %wim,%o1
+ st %o0,[%fp-0xd8]
+ rd %psr,%o0
+ st %o0,[%fp-0xdc]
+ rd %y,%o0
+ st %o0,[%fp-0xe0]
+
+ /..* The arguments are pushed at this point by GDB;
+ no code is needed in the dummy for this.
+ The CALL_DUMMY_START_OFFSET gives the position of
+ the following ld instruction. *../
+
+ ld [%sp+0x58],%o5
+ ld [%sp+0x54],%o4
+ ld [%sp+0x50],%o3
+ ld [%sp+0x4c],%o2
+ ld [%sp+0x48],%o1
+ call 0x00000000
+ ld [%sp+0x44],%o0
+ nop
+ ta 1
+ nop
+
+ note that this is 192 bytes, which is a multiple of 8 (not only 4) bytes.
+ note that the `call' insn is a relative, not an absolute call.
+ note that the `nop' at the end is needed to keep the trap from
+ clobbering things (if NPC pointed to garbage instead).
+
+We actually start executing at the `sethi', since the pushing of the
+registers (as arguments) is done by PUSH_DUMMY_FRAME. If this were
+real code, the arguments for the function called by the CALL would be
+pushed between the list of ST insns and the CALL, and we could allow
+it to execute through. But the arguments have to be pushed by GDB
+after the PUSH_DUMMY_FRAME is done, and we cannot allow these ST
+insns to be performed again, lest the registers saved be taken for
+arguments. */
+
+#define CALL_DUMMY { 0x9de3bee0, 0xfd3fbff8, 0xf93fbff0, 0xf53fbfe8, \
+ 0xf13fbfe0, 0xed3fbfd8, 0xe93fbfd0, 0xe53fbfc8, \
+ 0xe13fbfc0, 0xdd3fbfb8, 0xd93fbfb0, 0xd53fbfa8, \
+ 0xd13fbfa0, 0xcd3fbf98, 0xc93fbf90, 0xc53fbf88, \
+ 0xc13fbf80, 0xcc3fbf78, 0xc83fbf70, 0xc43fbf68, \
+ 0xc03fbf60, 0xfc3fbf58, 0xf83fbf50, 0xf43fbf48, \
+ 0xf03fbf40, 0x01000000, 0x01000000, 0x01000000, \
+ 0x01000000, 0x91580000, 0xd027bf50, 0x93500000, \
+ 0xd027bf4c, 0x91480000, 0xd027bf48, 0x91400000, \
+ 0xd027bf44, 0xda03a058, 0xd803a054, 0xd603a050, \
+ 0xd403a04c, 0xd203a048, 0x40000000, 0xd003a044, \
+ 0x01000000, 0x91d02001, 0x01000000, 0x01000000}
+
+#define CALL_DUMMY_LENGTH 192
+
+#define CALL_DUMMY_START_OFFSET 148
+
+#define CALL_DUMMY_STACK_ADJUST 68
+
+/* Insert the specified number of args and function address
+ into a call sequence of the above form stored at DUMMYNAME. */
+
+#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
+{ \
+ *(int *)((char *) dummyname+168) = (0x40000000|((fun-(pc+168))>>2)); \
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT \
+ || TYPE_CODE (type) == TYPE_CODE_UNION) \
+ *(int *)((char *) dummyname+176) = (TYPE_LENGTH (type) & 0x1fff); \
+}
+
+
+/* Sparc has no reliable single step ptrace call */
+
+#define NO_SINGLE_STEP 1
+
+/* It does have a wait structure, and it might help things out . . . */
+
+#define HAVE_WAIT_STRUCT
+
+/* Handle a feature in the sun4 compiler ("call .stret4" at the end of
+ functions returning structures). */
+
+#define SUN4_COMPILER_FEATURE
+
+/* We need two arguments (in general) to the "info frame" command.
+ Note that the definition of this macro implies that there exists a
+ function "setup_arbitrary_frame" in mach-dep.c */
+
+#define FRAME_SPECIFICATION_DYADIC
+
+/* KDB stuff flushed for now. */
+@
+
+
+1.2
+log
+@Don't stop the stack trace until the "next frame pointer" is zero.
+@
+text
+@d39 11
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d66 1
+a66 1
+#define STACK_END_ADDR 0xff000000
+d307 3
+d312 4
+@
diff --git a/gdb/RCS/m68k-pinsn.c,v b/gdb/RCS/m68k-pinsn.c,v
new file mode 100644
index 0000000..d8c7f84
--- /dev/null
+++ b/gdb/RCS/m68k-pinsn.c,v
@@ -0,0 +1,824 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.03.27.20.19.34; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.20.19.29.33; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Change HPUX_ASM to USG_SGS_ASM since it's really the Sys V
+"Software Generation System" that we are fighting here.
+@
+text
+@/* Print m68k instructions for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include <stdio.h>
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "opcode.h"
+
+/* 68k instructions are never longer than this many bytes. */
+#define MAXLEN 22
+
+/* Number of elements in the opcode table. */
+#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
+
+extern char *reg_names[];
+char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
+ "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
+
+static unsigned char *print_insn_arg ();
+static unsigned char *print_indexed ();
+static void print_base ();
+static int fetch_arg ();
+
+#define NEXTBYTE(p) (p += 2, ((char *)p)[-1])
+
+#define NEXTWORD(p) \
+ (p += 2, ((((char *)p)[-2]) << 8) + p[-1])
+
+#define NEXTLONG(p) \
+ (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
+
+#define NEXTSINGLE(p) \
+ (p += 4, *((float *)(p - 4)))
+
+#define NEXTDOUBLE(p) \
+ (p += 8, *((double *)(p - 8)))
+
+#define NEXTEXTEND(p) \
+ (p += 12, 0.0) /* Need a function to convert from extended to double
+ precision... */
+
+#define NEXTPACKED(p) \
+ (p += 12, 0.0) /* Need a function to convert from packed to double
+ precision. Actually, it's easier to print a
+ packed number than a double anyway, so maybe
+ there should be a special case to handle this... */
+
+/* Print the m68k instruction at address MEMADDR in debugged memory,
+ on STREAM. Returns length of the instruction, in bytes. */
+
+int
+print_insn (memaddr, stream)
+ CORE_ADDR memaddr;
+ FILE *stream;
+{
+ unsigned char buffer[MAXLEN];
+ register int i;
+ register unsigned char *p;
+ register char *d;
+ register int bestmask;
+ int best;
+
+ read_memory (memaddr, buffer, MAXLEN);
+
+ bestmask = 0;
+ best = -1;
+ for (i = 0; i < NOPCODES; i++)
+ {
+ register unsigned int opcode = m68k_opcodes[i].opcode;
+ register unsigned int match = m68k_opcodes[i].match;
+ if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
+ && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
+ && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
+ && ((0xff & buffer[3] & match) == (0xff & opcode)))
+ {
+ /* Don't use for printout the variants of divul and divsl
+ that have the same register number in two places.
+ The more general variants will match instead. */
+ for (d = m68k_opcodes[i].args; *d; d += 2)
+ if (d[1] == 'D')
+ break;
+
+ /* Don't use for printout the variants of most floating
+ point coprocessor instructions which use the same
+ register number in two places, as above. */
+ if (*d == 0)
+ for (d = m68k_opcodes[i].args; *d; d += 2)
+ if (d[1] == 't')
+ break;
+
+ if (*d == 0 && match > bestmask)
+ {
+ best = i;
+ bestmask = match;
+ }
+ }
+ }
+
+ /* Handle undefined instructions. */
+ if (best < 0)
+ {
+ fprintf (stream, "0%o", (buffer[0] << 8) + buffer[1]);
+ return 2;
+ }
+
+ fprintf (stream, "%s", m68k_opcodes[best].name);
+
+ /* Point at first word of argument data,
+ and at descriptor for first argument. */
+ p = buffer + 2;
+
+ /* Why do this this way? -MelloN */
+ for (d = m68k_opcodes[best].args; *d; d += 2)
+ {
+ if (d[0] == '#')
+ {
+ if (d[1] == 'l' && p - buffer < 6)
+ p = buffer + 6;
+ else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
+ p = buffer + 4;
+ }
+ if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
+ p = buffer + 4;
+ if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
+ p = buffer + 6;
+ }
+
+ d = m68k_opcodes[best].args;
+
+ if (*d)
+ fputc (' ', stream);
+
+ while (*d)
+ {
+ p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream);
+ d += 2;
+ if (*d && *(d - 2) != 'I' && *d != 'k')
+ fprintf (stream, ",");
+ }
+ return p - buffer;
+}
+
+static unsigned char *
+print_insn_arg (d, buffer, p, addr, stream)
+ char *d;
+ unsigned char *buffer;
+ register unsigned char *p;
+ CORE_ADDR addr; /* PC for this arg to be relative to */
+ FILE *stream;
+{
+ register int val;
+ register int place = d[1];
+ int regno;
+ register char *regname;
+ register unsigned char *p1;
+ register double flval;
+ int flt_p;
+
+ switch (*d)
+ {
+ case 'C':
+ fprintf (stream, "ccr");
+ break;
+
+ case 'S':
+ fprintf (stream, "sr");
+ break;
+
+ case 'U':
+ fprintf (stream, "usp");
+ break;
+
+ case 'J':
+ {
+ static struct { char *name; int value; } names[]
+ = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
+ {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
+ {"msp", 0x803}, {"isp", 0x804}};
+
+ val = fetch_arg (buffer, place, 12);
+ for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
+ if (names[regno].value == val)
+ {
+ fprintf (stream, names[regno].name);
+ break;
+ }
+ if (regno < 0)
+ fprintf (stream, "%d", val);
+ }
+ break;
+
+ case 'Q':
+ val = fetch_arg (buffer, place, 3);
+ if (val == 0) val = 8;
+ fprintf (stream, "#%d", val);
+ break;
+
+ case 'M':
+ val = fetch_arg (buffer, place, 8);
+ if (val & 0x80)
+ val = val - 0x100;
+ fprintf (stream, "#%d", val);
+ break;
+
+ case 'T':
+ val = fetch_arg (buffer, place, 4);
+ fprintf (stream, "#%d", val);
+ break;
+
+ case 'D':
+ fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
+ break;
+
+ case 'A':
+ fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3) + 010]);
+ break;
+
+ case 'R':
+ fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
+ break;
+
+ case 'F':
+ fprintf (stream, "fp%d", fetch_arg (buffer, place, 3));
+ break;
+
+ case 'O':
+ val = fetch_arg (buffer, place, 6);
+ if (val & 0x20)
+ fprintf (stream, "%s", reg_names [val & 7]);
+ else
+ fprintf (stream, "%d", val);
+ break;
+
+ case '+':
+ fprintf (stream, "(%s)+", reg_names[fetch_arg (buffer, place, 3) + 8]);
+ break;
+
+ case '-':
+ fprintf (stream, "-(%s)", reg_names[fetch_arg (buffer, place, 3) + 8]);
+ break;
+
+ case 'k':
+ if (place == 'k')
+ fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
+ else if (place == 'C')
+ {
+ val = fetch_arg (buffer, place, 7);
+ if ( val > 63 ) /* This is a signed constant. */
+ val -= 128;
+ fprintf (stream, "{#%d}", val);
+ }
+ else
+ error ("Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+ break;
+
+ case '#':
+ p1 = buffer + 2;
+ if (place == 's')
+ val = fetch_arg (buffer, place, 4);
+ else if (place == 'C')
+ val = fetch_arg (buffer, place, 7);
+ else if (place == '8')
+ val = fetch_arg (buffer, place, 3);
+ else if (place == '3')
+ val = fetch_arg (buffer, place, 8);
+ else if (place == 'b')
+ val = NEXTBYTE (p1);
+ else if (place == 'w')
+ val = NEXTWORD (p1);
+ else if (place == 'l')
+ val = NEXTLONG (p1);
+ else
+ error ("Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+ fprintf (stream, "#%d", val);
+ break;
+
+ case '^':
+ if (place == 's')
+ val = fetch_arg (buffer, place, 4);
+ else if (place == 'C')
+ val = fetch_arg (buffer, place, 7);
+ else if (place == '8')
+ val = fetch_arg (buffer, place, 3);
+ else if (place == 'b')
+ val = NEXTBYTE (p);
+ else if (place == 'w')
+ val = NEXTWORD (p);
+ else if (place == 'l')
+ val = NEXTLONG (p);
+ else
+ error ("Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+ fprintf (stream, "#%d", val);
+ break;
+
+ case 'B':
+ if (place == 'b')
+ val = NEXTBYTE (p);
+ else if (place == 'w')
+ val = NEXTWORD (p);
+ else if (place == 'l')
+ val = NEXTLONG (p);
+ else if (place == 'g')
+ {
+ val = ((char *)buffer)[1];
+ if (val == 0)
+ val = NEXTWORD (p);
+ else if (val == -1)
+ val = NEXTLONG (p);
+ }
+ else if (place == 'c')
+ {
+ if (buffer[1] & 0x40) /* If bit six is one, long offset */
+ val = NEXTLONG (p);
+ else
+ val = NEXTWORD (p);
+ }
+ else
+ error ("Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+
+ print_address (addr + val, stream);
+ break;
+
+ case 'd':
+ val = NEXTWORD (p);
+ fprintf (stream, "%d(%s)", val, reg_names[fetch_arg (buffer, place, 3)]);
+ break;
+
+ case 's':
+ fprintf (stream, "%s", fpcr_names[fetch_arg (buffer, place, 3)]);
+ break;
+
+ case 'I':
+ val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */
+ if (val != 1) /* Unusual coprocessor ID? */
+ fprintf (stream, "(cpid=%d) ", val);
+ if (place == 'i')
+ p += 2; /* Skip coprocessor extended operands */
+ break;
+
+ case '*':
+ case '~':
+ case '%':
+ case ';':
+ case '@@':
+ case '!':
+ case '$':
+ case '?':
+ case '/':
+ case '&':
+
+ if (place == 'd')
+ {
+ val = fetch_arg (buffer, 'x', 6);
+ val = ((val & 7) << 3) + ((val >> 3) & 7);
+ }
+ else
+ val = fetch_arg (buffer, 's', 6);
+
+ /* Get register number assuming address register. */
+ regno = (val & 7) + 8;
+ regname = reg_names[regno];
+ switch (val >> 3)
+ {
+ case 0:
+ fprintf (stream, "%s", reg_names[val]);
+ break;
+
+ case 1:
+ fprintf (stream, "%s", regname);
+ break;
+
+ case 2:
+ fprintf (stream, "(%s)", regname);
+ break;
+
+ case 3:
+ fprintf (stream, "(%s)+", regname);
+ break;
+
+ case 4:
+ fprintf (stream, "-(%s)", regname);
+ break;
+
+ case 5:
+ val = NEXTWORD (p);
+ fprintf (stream, "%d(%s)", val, regname);
+ break;
+
+ case 6:
+ p = print_indexed (regno, p, addr, stream);
+ break;
+
+ case 7:
+ switch (val & 7)
+ {
+ case 0:
+ val = NEXTWORD (p);
+ fprintf (stream, "@@#");
+ print_address (val, stream);
+ break;
+
+ case 1:
+ val = NEXTLONG (p);
+ fprintf (stream, "@@#");
+ print_address (val, stream);
+ break;
+
+ case 2:
+ val = NEXTWORD (p);
+ print_address (addr + val, stream);
+ break;
+
+ case 3:
+ p = print_indexed (-1, p, addr, stream);
+ break;
+
+ case 4:
+ flt_p = 1; /* Assume it's a float... */
+ switch( place )
+ {
+ case 'b':
+ val = NEXTBYTE (p);
+ flt_p = 0;
+ break;
+
+ case 'w':
+ val = NEXTWORD (p);
+ flt_p = 0;
+ break;
+
+ case 'l':
+ val = NEXTLONG (p);
+ flt_p = 0;
+ break;
+
+ case 'f':
+ flval = NEXTSINGLE(p);
+ break;
+
+ case 'F':
+ flval = NEXTDOUBLE(p);
+ break;
+
+ case 'x':
+ flval = NEXTEXTEND(p);
+ break;
+
+ case 'p':
+ flval = NEXTPACKED(p);
+ break;
+
+ default:
+ error ("Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+ }
+ if ( flt_p ) /* Print a float? */
+ fprintf (stream, "#%g", flval);
+ else
+ fprintf (stream, "#%d", val);
+ break;
+
+ default:
+ fprintf (stream, "<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. */
+
+convert_from_68881 (from, to)
+ char *from;
+ double *to;
+{
+#ifdef USG_SGS_ASM
+ asm ("mov.l 8(%a6),%a0");
+ asm ("mov.l 12(%a6),%a1");
+ asm ("fmove.x (%a0),%fp0");
+ asm ("fmove.d %fp0,(%a1)");
+#else /* not USG_SGS_ASM */
+#if 0
+ asm ("movl a6@@(8),a0");
+ asm ("movl a6@@(12),a1");
+ asm ("fmovex a0@@,fp0");
+ asm ("fmoved fp0,a1@@");
+#else
+ /* Hand-assemble those insns since some assemblers lose
+ and some have different syntax. */
+ asm (".word 020156");
+ asm (".word 8");
+ asm (".word 021156");
+ asm (".word 12");
+ asm (".long 0xf2104800");
+ asm (".long 0xf2117400");
+#endif
+#endif /* not USG_SGS_ASM */
+}
+
+/* The converse: convert the double *FROM to an extended float
+ and store where TO points. */
+
+convert_to_68881 (from, to)
+ double *from;
+ char *to;
+{
+#ifdef USG_SGS_ASM
+ asm ("mov.l 8(%a6),%a0");
+ asm ("mov.l 12(%a6),%a1");
+ asm ("fmove.d (%a0),%fp0");
+ asm ("fmove.x %fp0,(%a1)");
+#else /* not USG_SGS_ASM */
+#if 0
+ asm ("movl a6@@(8),a0");
+ asm ("movl a6@@(12),a1");
+ asm ("fmoved a0@@,fp0");
+ asm ("fmovex fp0,a1@@");
+#else
+ /* Hand-assemble those insns since some assemblers lose. */
+ asm (".word 020156");
+ asm (".word 8");
+ asm (".word 021156");
+ asm (".word 12");
+ asm (".long 0xf2105400");
+ asm (".long 0xf2116800");
+#endif
+#endif /* not USG_SGS_ASM */
+}
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d717 1
+a717 1
+#ifdef HPUX_ASM
+d722 1
+a722 1
+#else /* not HPUX_ASM */
+d738 1
+a738 1
+#endif /* not HPUX_ASM */
+d748 1
+a748 1
+#ifdef HPUX_ASM
+d753 1
+a753 1
+#else /* not HPUX_ASM */
+d768 1
+a768 1
+#endif /* not HPUX_ASM */
+@
diff --git a/gdb/RCS/main.c,v b/gdb/RCS/main.c,v
new file mode 100644
index 0000000..1e6fafa
--- /dev/null
+++ b/gdb/RCS/main.c,v
@@ -0,0 +1,1348 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.03.27.21.15.02; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.27.21.11.51; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Fix up "munch" so it generates a name that doesn't match its own
+"grep" conventions. Change main so that it calls the new name,
+and also doesn't use the conventions for functions that should NOT
+be called by init.c.
+@
+text
+@/* Top level for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+#include "defs.h"
+#include "command.h"
+#include "param.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include <sys/file.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/param.h>
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int original_stack_limit;
+#endif
+
+/* Version number of GDB, as a string. */
+
+extern char *version;
+
+/*
+ * Declare all cmd_list_element's
+ */
+
+/* Chain containing all defined commands. */
+
+struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands. */
+
+struct cmd_list_element *infolist;
+
+/* Chain containing all defined enable subcommands. */
+
+struct cmd_list_element *enablelist;
+
+/* Chain containing all defined disable subcommands. */
+
+struct cmd_list_element *disablelist;
+
+/* Chain containing all defined delete subcommands. */
+
+struct cmd_list_element *deletelist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+struct cmd_list_element *setlist;
+
+/* stdio stream that command input is being read from. */
+
+FILE *instream;
+
+/* Current working directory. */
+
+char *current_directory;
+
+/* The directory name is actually stored here (usually). */
+static char dirbuf[MAXPATHLEN];
+
+/* Nonzero if we should refrain from using an X window. */
+
+int inhibit_windows = 0;
+
+/* Function to call before reading a command, if nonzero.
+ The function receives two args: an input stream,
+ and a prompt string. */
+
+void (*window_hook) ();
+
+extern int frame_file_full_name;
+
+void free_command_lines ();
+char *gdb_read_line ();
+static void init_main ();
+static void init_cmd_lists ();
+void command_loop ();
+static void source_command ();
+static void print_gdb_version ();
+
+/* gdb prints this when reading a command interactively */
+static char *prompt;
+
+/* Buffer used for reading command lines, and the size
+ allocated for it so far. */
+
+char *line;
+int linesize;
+
+/* This is how `error' returns to command level. */
+
+jmp_buf to_top_level;
+
+void
+return_to_top_level ()
+{
+ quit_flag = 0;
+ immediate_quit = 0;
+ clear_breakpoint_commands ();
+ clear_momentary_breakpoints ();
+ delete_current_display ();
+ do_cleanups (0);
+ longjmp (to_top_level, 1);
+}
+
+/* Call FUNC with arg ARG, catching any errors.
+ If there is no error, return the value returned by FUNC.
+ If there is an error, return zero after printing ERRSTRING
+ (which is in addition to the specific error message already printed). */
+
+int
+catch_errors (func, arg, errstring)
+ int (*func) ();
+ int arg;
+ char *errstring;
+{
+ jmp_buf saved;
+ int val;
+ struct cleanup *saved_cleanup_chain;
+
+ saved_cleanup_chain = save_cleanups ();
+
+ bcopy (to_top_level, saved, sizeof (jmp_buf));
+
+ if (setjmp (to_top_level) == 0)
+ val = (*func) (arg);
+ else
+ {
+ fprintf (stderr, "%s\n", errstring);
+ val = 0;
+ }
+
+ restore_cleanups (saved_cleanup_chain);
+
+ bcopy (saved, to_top_level, sizeof (jmp_buf));
+ return val;
+}
+
+/* Handler for SIGHUP. */
+
+static void
+disconnect ()
+{
+ kill_inferior_fast ();
+ signal (SIGHUP, SIG_DFL);
+ kill (getpid (), SIGHUP);
+}
+
+/* Clean up on error during a "source" command (or execution of a
+ user-defined command).
+ Close the file opened by the command
+ and restore the previous input stream. */
+
+static void
+source_cleanup (stream)
+ FILE *stream;
+{
+ /* Instream may be 0; set to it when executing user-defined command. */
+ if (instream)
+ fclose (instream);
+ instream = stream;
+}
+
+
+int
+main (argc, argv, envp)
+ int argc;
+ char **argv;
+ char **envp;
+{
+ extern void request_quit ();
+ int count;
+ int inhibit_gdbinit = 0;
+ int quiet = 0;
+ int batch = 0;
+ register int i;
+
+ quit_flag = 0;
+ linesize = 100;
+ line = (char *) xmalloc (linesize);
+ instream = stdin;
+
+ getwd (dirbuf);
+ current_directory = dirbuf;
+
+#ifdef SET_STACK_LIMIT_HUGE
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca (particularly stringtab
+ * in dbxread.c) does not fail. */
+ getrlimit (RLIMIT_STACK, &rlim);
+ original_stack_limit = rlim.rlim_cur;
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+ /* Look for flag arguments. */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-q") || !strcmp (argv[i], "-quiet"))
+ quiet = 1;
+ else if (!strcmp (argv[i], "-nx"))
+ inhibit_gdbinit = 1;
+ else if (!strcmp (argv[i], "-nw"))
+ inhibit_windows = 1;
+ else if (!strcmp (argv[i], "-batch"))
+ batch = 1, quiet = 1;
+ else if (!strcmp (argv[i], "-fullname"))
+ frame_file_full_name = 1;
+ else if (argv[i][0] == '-')
+ i++;
+ }
+
+ /* Run the init function of each source file */
+
+ init_cmd_lists (); /* This needs to be done first */
+ init_all_files ();
+ init_main (); /* But that omits this file! Do it now */
+
+ signal (SIGINT, request_quit);
+ signal (SIGQUIT, SIG_IGN);
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, disconnect);
+
+ if (!quiet)
+ print_gdb_version ();
+
+ /* Process the command line arguments. */
+
+ count = 0;
+ for (i = 1; i < argc; i++)
+ {
+ register char *arg = argv[i];
+ /* Args starting with - say what to do with the following arg
+ as a filename. */
+ if (arg[0] == '-')
+ {
+ extern void exec_file_command (), symbol_file_command ();
+ extern void core_file_command (), directory_command ();
+ extern void tty_command ();
+
+ if (!strcmp (arg, "-q") || !strcmp (arg, "-nx")
+ || !strcmp (arg, "-quiet") || !strcmp (arg, "-batch")
+ || !strcmp (arg, "-fullname"))
+ /* Already processed above */
+ continue;
+
+ if (++i == argc)
+ fprintf (stderr, "No argument follows \"%s\".\n", arg);
+ if (!setjmp (to_top_level))
+ {
+ /* -s foo: get syms from foo. -e foo: execute foo.
+ -se foo: do both with foo. -c foo: use foo as core dump. */
+ if (!strcmp (arg, "-se"))
+ {
+ exec_file_command (argv[i], !batch);
+ symbol_file_command (argv[i], !batch);
+ }
+ else if (!strcmp (arg, "-s") || !strcmp (arg, "-symbols"))
+ symbol_file_command (argv[i], !batch);
+ else if (!strcmp (arg, "-e") || !strcmp (arg, "-exec"))
+ exec_file_command (argv[i], !batch);
+ else if (!strcmp (arg, "-c") || !strcmp (arg, "-core"))
+ core_file_command (argv[i], !batch);
+ /* -x foo: execute commands from foo. */
+ else if (!strcmp (arg, "-x") || !strcmp (arg, "-command")
+ || !strcmp (arg, "-commands"))
+ source_command (argv[i]);
+ /* -d foo: add directory `foo' to source-file directory
+ search-list */
+ else if (!strcmp (arg, "-d") || !strcmp (arg, "-dir")
+ || !strcmp (arg, "-directory"))
+ directory_command (argv[i], 0);
+ /* -cd FOO: specify current directory as FOO.
+ GDB remembers the precise string FOO as the dirname. */
+ else if (!strcmp (arg, "-cd"))
+ {
+ int len = strlen (argv[i]);
+ current_directory = argv[i];
+ if (len > 1 && current_directory[len - 1] == '/')
+ current_directory = savestring (current_directory, len-1);
+ chdir (current_directory);
+ init_source_path ();
+ }
+ /* -t /def/ttyp1: use /dev/ttyp1 for inferior I/O. */
+ else if (!strcmp (arg, "-t") || !strcmp (arg, "-tty"))
+ tty_command (argv[i], 0);
+ else
+ error ("Unknown command-line switch: \"%s\"\n", arg);
+ }
+ }
+ else
+ {
+ /* Args not thus accounted for
+ are treated as, first, the symbol/executable file
+ and, second, the core dump file. */
+ count++;
+ if (!setjmp (to_top_level))
+ switch (count)
+ {
+ case 1:
+ exec_file_command (arg, !batch);
+ symbol_file_command (arg, !batch);
+ break;
+
+ case 2:
+ core_file_command (arg, !batch);
+ break;
+
+ case 3:
+ fprintf (stderr, "Excess command line args ignored. (%s%s)\n",
+ arg, (i == argc - 1) ? "" : " ...");
+ }
+ }
+ }
+
+ /* Read init file, if it exists in home directory */
+ if (getenv ("HOME"))
+ {
+ char *s;
+ s = (char *) xmalloc (strlen (getenv ("HOME")) + 10);
+ strcpy (s, getenv ("HOME"));
+ strcat (s, "/.gdbinit");
+ if (!inhibit_gdbinit && access (s, R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (s);
+ }
+
+ /* Read init file, if it exists in current directory. */
+ if (!inhibit_gdbinit && access (".gdbinit", R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (".gdbinit");
+
+ if (batch)
+ fatal ("Attempt to read commands from stdin in batch mode.");
+
+ if (!quiet)
+ printf ("Type \"help\" for a list of commands.\n");
+
+ /* The command loop. */
+
+ while (1)
+ {
+ if (!setjmp (to_top_level))
+ command_loop ();
+ clearerr (stdin); /* Don't get hung if C-d is typed. */
+ }
+}
+
+/* Execute the line P as a command.
+ Pass FROM_TTY as second argument to the defining function. */
+
+void
+execute_command (p, from_tty)
+ char *p;
+ int from_tty;
+{
+ register struct cmd_list_element *c;
+ register struct command_line *cmdlines;
+
+ free_all_values ();
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p)
+ {
+ c = lookup_cmd (&p, cmdlist, "", 0);
+ if (c->function == 0)
+ error ("That is not a command, just a help topic.");
+ else if (c->class == (int) class_user)
+ {
+ struct cleanup *old_chain;
+
+ if (*p)
+ error ("User-defined commands cannot take arguments.");
+ cmdlines = (struct command_line *) c->function;
+ if (cmdlines == (struct command_line *) 0)
+ /* Null command */
+ return;
+
+ /* Set the instream to 0, indicating execution of a
+ user-defined function. */
+ old_chain = make_cleanup (source_cleanup, instream);
+ instream = (FILE *) 0;
+ while (cmdlines)
+ {
+ execute_command (cmdlines->line, 0);
+ cmdlines = cmdlines->next;
+ }
+ do_cleanups (old_chain);
+ }
+ else
+ /* Pass null arg rather than an empty one. */
+ (*c->function) (*p ? p : 0, from_tty);
+ }
+}
+
+static void
+do_nothing ()
+{
+}
+
+/* Read commands from `instream' and execute them
+ until end of file. */
+void
+command_loop ()
+{
+ struct cleanup *old_chain;
+ while (!feof (instream))
+ {
+ if (window_hook && instream == stdin)
+ (*window_hook) (instream, prompt);
+
+ quit_flag = 0;
+ old_chain = make_cleanup (do_nothing, 0);
+ execute_command (gdb_read_line (instream == stdin ? prompt : 0,
+ instream == stdin),
+ instream == stdin);
+ /* Do any commands attached to breakpoint we stopped at. */
+ do_breakpoint_commands ();
+ do_cleanups (old_chain);
+ }
+}
+
+#ifdef SIGTSTP
+static void
+stop_sig ()
+{
+ signal (SIGTSTP, SIG_DFL);
+ sigsetmask (0);
+ kill (getpid (), SIGTSTP);
+ signal (SIGTSTP, stop_sig);
+ printf ("%s", prompt);
+ fflush (stdout);
+
+ /* Forget about any previous command -- null line now will do nothing. */
+ *line = 0;
+}
+#endif /* SIGTSTP */
+
+/* Commands call this if they do not want to be repeated by null lines. */
+
+void
+dont_repeat ()
+{
+ *line = 0;
+}
+
+/* Read one line from the command input stream `instream'
+ into the buffer `line' (whose current length is `linesize').
+ The buffer is made bigger as necessary.
+ Returns the address of the start of the line. */
+
+char *
+gdb_read_line (prompt, repeat)
+ char *prompt;
+ int repeat;
+{
+ register char *p = line;
+ register char *p1;
+ register int c;
+ char *nline;
+
+ /* Control-C quits instantly if typed while in this loop
+ since it should not wait until the user types a newline. */
+ immediate_quit++;
+#ifdef SIGTSTP
+ signal (SIGTSTP, stop_sig);
+#endif
+
+ if (prompt)
+ {
+ printf (prompt);
+ fflush (stdout);
+ }
+
+ while (1)
+ {
+ c = fgetc (instream);
+ if (c == -1 || c == '\n')
+ break;
+ /* Ignore backslash-newline; keep adding to the same line. */
+ else if (c == '\\')
+ {
+ int c1 = fgetc (instream);
+ if (c1 == '\n')
+ continue;
+ else
+ ungetc (c1, instream);
+ }
+
+ if (p - line == linesize - 1)
+ {
+ linesize *= 2;
+ nline = (char *) xrealloc (line, linesize);
+ p += nline - line;
+ line = nline;
+ }
+ *p++ = c;
+ }
+
+#ifdef SIGTSTP
+ signal (SIGTSTP, SIG_DFL);
+#endif
+ immediate_quit--;
+
+ /* If we just got an empty line, and that is supposed
+ to repeat the previous command, leave the last input unchanged. */
+ if (p == line && repeat)
+ return line;
+
+ /* If line is a comment, clear it out. */
+ p1 = line;
+ while ((c = *p1) == ' ' || c == '\t') p1++;
+ if (c == '#')
+ p = line;
+
+ *p = 0;
+
+ return line;
+}
+
+/* Read lines from the input stream
+ and accumulate them in a chain of struct command_line's
+ which is then returned. */
+
+struct command_line *
+read_command_lines ()
+{
+ struct command_line *first = 0;
+ register struct command_line *next, *tail = 0;
+ register char *p, *p1;
+ struct cleanup *old_chain = 0;
+
+ while (1)
+ {
+ dont_repeat ();
+ p = gdb_read_line (0, 1);
+ /* Remove leading and trailing blanks. */
+ while (*p == ' ' || *p == '\t') p++;
+ p1 = p + strlen (p);
+ while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--;
+
+ /* Is this "end"? */
+ if (p1 - p == 3 && !strncmp (p, "end", 3))
+ break;
+
+ /* No => add this line to the chain of command lines. */
+ next = (struct command_line *) xmalloc (sizeof (struct command_line));
+ next->line = savestring (p, p1 - p);
+ next->next = 0;
+ if (tail)
+ {
+ tail->next = next;
+ }
+ else
+ {
+ /* We just read the first line.
+ From now on, arrange to throw away the lines we have
+ if we quit or get an error while inside this function. */
+ first = next;
+ old_chain = make_cleanup (free_command_lines, &first);
+ }
+ tail = next;
+ }
+
+ dont_repeat ();
+
+ /* Now we are about to return the chain to our caller,
+ so freeing it becomes his responsibility. */
+ if (first)
+ discard_cleanups (old_chain);
+ return first;
+}
+
+/* Free a chain of struct command_line's. */
+
+void
+free_command_lines (lptr)
+ struct command_line **lptr;
+{
+ register struct command_line *l = *lptr;
+ register struct command_line *next;
+
+ while (l)
+ {
+ next = l->next;
+ free (l->line);
+ free (l);
+ l = next;
+ }
+}
+
+/* Add an element to the list of info subcommands. */
+
+void
+add_info (name, fun, doc)
+ char *name;
+ void (*fun) ();
+ char *doc;
+{
+ add_cmd (name, no_class, fun, doc, &infolist);
+}
+
+/* Add an alias to the list of info subcommands. */
+
+void
+add_info_alias (name, oldname, abbrev_flag)
+ char *name;
+ char *oldname;
+ int abbrev_flag;
+{
+ add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
+}
+
+/* The "info" command is defined as a prefix, with allow_unknown = 0.
+ Therefore, its own definition is called only for "info" with no args. */
+
+static void
+info_command ()
+{
+ printf ("\"info\" must be followed by the name of an info command.\n");
+ help_list (infolist, "info ", -1, stdout);
+}
+
+/* Add an element to the list of commands. */
+
+void
+add_com (name, class, fun, doc)
+ char *name;
+ int class;
+ void (*fun) ();
+ char *doc;
+{
+ add_cmd (name, class, fun, doc, &cmdlist);
+}
+
+/* Add an alias or abbreviation command to the list of commands. */
+
+void
+add_com_alias (name, oldname, class, abbrev_flag)
+ char *name;
+ char *oldname;
+ int class;
+ int abbrev_flag;
+{
+ add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
+}
+
+void
+error_no_arg (why)
+ char *why;
+{
+ error ("Argument required (%s).", why);
+}
+
+static void
+help_command (command, from_tty)
+ char *command;
+ int from_tty; /* Ignored */
+{
+ help_cmd (command, stdout);
+}
+
+static void
+validate_comname (comname)
+ char *comname;
+{
+ register char *p;
+
+ if (comname == 0)
+ error_no_arg ("name of command to define");
+
+ p = comname;
+ while (*p)
+ {
+ if (!(*p >= 'A' && *p <= 'Z')
+ && !(*p >= 'a' && *p <= 'z')
+ && !(*p >= '0' && *p <= '9')
+ && *p != '-')
+ error ("Junk in argument list: \"%s\"", p);
+ p++;
+ }
+}
+
+static void
+define_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ register struct command_line *cmds;
+ register struct cmd_list_element *c;
+ char *tem = comname;
+
+ validate_comname (comname);
+
+ c = lookup_cmd (&tem, cmdlist, "", -1);
+ if (c)
+ {
+ if (c->class == (int) class_user || c->class == (int) class_alias)
+ tem = "Redefine command \"%s\"? ";
+ else
+ tem = "Really redefine built-in command \"%s\"? ";
+ if (!query (tem, comname))
+ error ("Command \"%s\" not redefined.", comname);
+ }
+
+ if (from_tty)
+ {
+ printf ("Type commands for definition of \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+ fflush (stdout);
+ }
+ comname = savestring (comname, strlen (comname));
+
+ cmds = read_command_lines ();
+
+ if (c && c->class == (int) class_user)
+ free_command_lines (&c->function);
+
+ add_com (comname, class_user, cmds,
+ (c && c->class == (int) class_user)
+ ? c->doc : savestring ("User-defined.", 13));
+}
+
+static void
+document_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ struct command_line *doclines;
+ register struct cmd_list_element *c;
+ char *tem = comname;
+
+ validate_comname (comname);
+
+ c = lookup_cmd (&tem, cmdlist, "", 0);
+
+ if (c->class != (int) class_user)
+ error ("Command \"%s\" is built-in.", comname);
+
+ if (from_tty)
+ printf ("Type documentation for \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+
+ doclines = read_command_lines ();
+
+ if (c->doc) free (c->doc);
+
+ {
+ register struct command_line *cl1;
+ register int len = 0;
+
+ for (cl1 = doclines; cl1; cl1 = cl1->next)
+ len += strlen (cl1->line) + 1;
+
+ c->doc = (char *) xmalloc (len + 1);
+ *c->doc = 0;
+
+ for (cl1 = doclines; cl1; cl1 = cl1->next)
+ {
+ strcat (c->doc, cl1->line);
+ if (cl1->next)
+ strcat (c->doc, "\n");
+ }
+ }
+
+ free_command_lines (&doclines);
+}
+
+static void
+copying_info ()
+{
+ immediate_quit++;
+ printf (" GDB GENERAL PUBLIC LICENSE\n\
+ (Clarified 11 Feb 1988)\n\
+\n\
+ Copyright (C) 1988 Richard M. Stallman\n\
+ Everyone is permitted to copy and distribute verbatim copies\n\
+ of this license, but changing it is not allowed.\n\
+ You can also use this wording to make the terms for other programs.\n\
+\n\
+ The license agreements of most software companies keep you at the\n\
+mercy of those companies. By contrast, our general public license is\n\
+intended to give everyone the right to share GDB. To make sure that\n\
+you get the rights we want you to have, we need to make restrictions\n\
+that forbid anyone to deny you these rights or to ask you to surrender\n\
+the rights. Hence this license agreement.\n\
+\n\
+ Specifically, we want to make sure that you have the right to give\n\
+away copies of GDB, that you receive source code or else can get it\n\
+if you want it, that you can change GDB or use pieces of it in new\n\
+free programs, and that you know you can do these things.\n\
+--Type Return to print more--");
+ fflush (stdout);
+ gdb_read_line (0, 0);
+
+ printf ("\
+ To make sure that everyone has such rights, we have to forbid you to\n\
+deprive anyone else of these rights. For example, if you distribute\n\
+copies of GDB, you must give the recipients all the rights that you\n\
+have. You must make sure that they, too, receive or can get the\n\
+source code. And you must tell them their rights.\n\
+\n\
+ Also, for our own protection, we must make certain that everyone\n\
+finds out that there is no warranty for GDB. If GDB is modified by\n\
+someone else and passed on, we want its recipients to know that what\n\
+they have is not what we distributed, so that any problems introduced\n\
+by others will not reflect on our reputation.\n\
+\n\
+ Therefore we (Richard Stallman and the Free Software Foundation,\n\
+Inc.) make the following terms which say what you must do to be\n\
+allowed to distribute or change GDB.\n\
+--Type Return to print more--");
+ fflush (stdout);
+ gdb_read_line (0, 0);
+
+ printf ("\
+ COPYING POLICIES\n\
+\n\
+ 1. You may copy and distribute verbatim copies of GDB source code as\n\
+you receive it, in any medium, provided that you conspicuously and\n\
+appropriately publish on each copy a valid copyright notice \"Copyright\n\
+\(C) 1988 Free Software Foundation, Inc.\" (or with whatever year is\n\
+appropriate); keep intact the notices on all files that refer\n\
+to this License Agreement and to the absence of any warranty; and give\n\
+any other recipients of the GDB program a copy of this License\n\
+Agreement along with the program. You may charge a distribution fee\n\
+for the physical act of transferring a copy.\n\
+\n\
+ 2. You may modify your copy or copies of GDB or any portion of it,\n\
+and copy and distribute such modifications under the terms of\n\
+Paragraph 1 above, provided that you also do the following:\n\
+\n\
+ a) cause the modified files to carry prominent notices stating\n\
+ that you changed the files and the date of any change; and\n\
+--Type Return to print more--");
+ fflush (stdout);
+ gdb_read_line (0, 0);
+
+ printf ("\
+ b) cause the whole of any work that you distribute or publish,\n\
+ that in whole or in part contains or is a derivative of GDB\n\
+ or any part thereof, to be licensed to all third parties on terms\n\
+ identical to those contained in this License Agreement (except that\n\
+ you may choose to grant more extensive warranty protection to some\n\
+ or all third parties, at your option).\n\
+\n");
+ printf ("\
+ c) if the modified program serves as a debugger, cause it\n\
+ when started running in the simplest and usual way, to print\n\
+ an announcement including a valid copyright notice\n\
+ \"Copyright (C) 1988 Free Software Foundation, Inc.\" (or with\n\
+ the year that is appropriate), saying that there is no warranty\n\
+ (or else, saying that you provide a warranty) and that users may\n\
+ redistribute the program under these conditions, and telling the user\n\
+ how to view a copy of this License Agreement.\n\
+\n\
+ d) You may charge a distribution fee for the physical act of\n\
+ transferring a copy, and you may at your option offer warranty\n\
+ protection in exchange for a fee.\n\
+\n\
+Mere aggregation of another unrelated program with this program (or its\n\
+derivative) on a volume of a storage or distribution medium does not bring\n\
+the other program under the scope of these terms.\n\
+--Type Return to print more--");
+ fflush (stdout);
+ gdb_read_line (0, 0);
+
+ printf ("\
+ 3. You may copy and distribute GDB (or a portion or derivative of it,\n\
+under Paragraph 2) in object code or executable form under the terms of\n\
+Paragraphs 1 and 2 above provided that you also do one of the following:\n\
+\n\
+ a) accompany it with the complete corresponding machine-readable\n\
+ source code, which must be distributed under the terms of\n\
+ Paragraphs 1 and 2 above; or,\n\
+\n\
+ b) accompany it with a written offer, valid for at least three\n\
+ years, to give any third party free (except for a nominal\n\
+ shipping charge) a complete machine-readable copy of the\n\
+ corresponding source code, to be distributed under the terms of\n\
+ Paragraphs 1 and 2 above; or,\n\n");
+
+ printf ("\
+ c) accompany it with the information you received as to where the\n\
+ corresponding source code may be obtained. (This alternative is\n\
+ allowed only for noncommercial distribution and only if you\n\
+ received the program in object code or executable form alone.)\n\
+\n\
+For an executable file, complete source code means all the source code for\n\
+all modules it contains; but, as a special exception, it need not include\n\
+source code for modules which are standard libraries that accompany the\n\
+operating system on which the executable file runs.\n\
+--Type Return to print more--");
+ fflush (stdout);
+ gdb_read_line (0, 0);
+
+ printf ("\
+ 4. You may not copy, sublicense, distribute or transfer GDB\n\
+except as expressly provided under this License Agreement. Any attempt\n\
+otherwise to copy, sublicense, distribute or transfer GDB is void and\n\
+your rights to use the program under this License agreement shall be\n\
+automatically terminated. However, parties who have received computer\n\
+software programs from you with this License Agreement will not have\n\
+their licenses terminated so long as such parties remain in full compliance.\n\
+\n\
+");
+ printf ("\
+ 5. If you wish to incorporate parts of GDB into other free\n\
+programs whose distribution conditions are different, write to the Free\n\
+Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet\n\
+worked out a simple rule that can be stated here, but we will often permit\n\
+this. We will be guided by the two goals of preserving the free status of\n\
+all derivatives of our free software and of promoting the sharing and reuse\n\
+of software.\n\
+\n\
+In other words, go ahead and share GDB, but don't try to stop\n\
+anyone else from sharing it farther. Help stamp out software hoarding!\n\
+");
+ immediate_quit--;
+}
+
+static void
+warranty_info ()
+{
+ immediate_quit++;
+ printf (" NO WARRANTY\n\
+\n\
+ BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY NO\n\
+WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT\n\
+WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,\n\
+RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB \"AS IS\" WITHOUT\n\
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT\n\
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\
+A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND\n\
+PERFORMANCE OF GDB IS WITH YOU. SHOULD GDB PROVE DEFECTIVE, YOU\n\
+ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n");
+
+ printf ("\
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.\n\
+STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY\n\
+WHO MAY MODIFY AND REDISTRIBUTE GDB, BE LIABLE TO\n\
+YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER\n\
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR\n\
+INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA\n\
+BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A\n\
+FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GDB, EVEN\n\
+IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR\n\
+ANY CLAIM BY ANY OTHER PARTY.\n");
+ immediate_quit--;
+}
+
+static void
+print_gdb_version ()
+{
+ printf ("GDB %s, Copyright (C) 1988 Free Software Foundation, Inc.\n\
+There is ABSOLUTELY NO WARRANTY for GDB; type \"info warranty\" for details.\n\
+GDB is free software and you are welcome to distribute copies of it\n\
+ under certain conditions; type \"info copying\" to see the conditions.\n",
+ version);
+}
+
+static void
+version_info ()
+{
+ immediate_quit++;
+ print_gdb_version ();
+ immediate_quit--;
+}
+
+/* xgdb calls this to reprint the usual GDB prompt. */
+
+void
+print_prompt ()
+{
+ printf ("%s", prompt);
+ fflush (stdout);
+}
+
+/* Command to specify a prompt string instead of "(gdb) ". */
+
+static void
+set_prompt_command (text)
+ char *text;
+{
+ char *p, *q;
+ register int c;
+ char *new;
+
+ if (text == 0)
+ error_no_arg ("string to which to set prompt");
+
+ new = (char *) xmalloc (strlen (text) + 2);
+ p = text; q = new;
+ while (c = *p++)
+ {
+ if (c == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ if (*p == 0)
+ break;
+ c = parse_escape (&p);
+ if (c == 0)
+ break; /* C loses */
+ else if (c > 0)
+ *q++ = c;
+ }
+ else
+ *q++ = c;
+ }
+ if (*(p - 1) != '\\')
+ *q++ = ' ';
+ *q++ = '\0';
+ new = (char *) xrealloc (new, q - new);
+ free (prompt);
+ prompt = new;
+}
+
+static void
+quit_command ()
+{
+ if (have_inferior_p ())
+ {
+ if (query ("The program is running. Quit anyway? "))
+ {
+ /* Prevent any warning message from reopen_exec_file, in case
+ we have a core file that's inconsistent with the exec file. */
+ exec_file_command (0, 0);
+ kill_inferior ();
+ }
+ else
+ error ("Not confirmed.");
+ }
+ exit (0);
+}
+
+int
+input_from_terminal_p ()
+{
+ return instream == stdin;
+}
+
+static void
+pwd_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg) error ("The \"pwd\" command does not take an argument: %s", arg);
+ getwd (dirbuf);
+
+ if (strcmp (dirbuf, current_directory))
+ printf ("Working directory %s\n (canonically %s).\n",
+ current_directory, dirbuf);
+ else
+ printf ("Working directory %s.\n", current_directory);
+}
+
+static void
+cd_command (dir, from_tty)
+ char *dir;
+ int from_tty;
+{
+ int len;
+ int change;
+
+ if (dir == 0)
+ error_no_arg ("new working directory");
+
+ len = strlen (dir);
+ dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
+ if (dir[0] == '/')
+ current_directory = dir;
+ else
+ {
+ current_directory = concat (current_directory, "/", dir);
+ free (dir);
+ }
+
+ /* Now simplify any occurrences of `.' and `..' in the pathname. */
+
+ change = 1;
+ while (change)
+ {
+ char *p;
+ change = 0;
+
+ for (p = current_directory; *p;)
+ {
+ if (!strncmp (p, "/./", 2)
+ && (p[2] == 0 || p[2] == '/'))
+ strcpy (p, p + 2);
+ else if (!strncmp (p, "/..", 3)
+ && (p[3] == 0 || p[3] == '/')
+ && p != current_directory)
+ {
+ char *q = p;
+ while (q != current_directory && q[-1] != '/') q--;
+ if (q != current_directory)
+ {
+ strcpy (q-1, p+3);
+ p = q-1;
+ }
+ }
+ else p++;
+ }
+ }
+
+ if (chdir (dir) < 0)
+ perror_with_name (dir);
+
+ if (from_tty)
+ pwd_command ((char *) 0, 1);
+}
+
+static void
+source_command (file)
+ char *file;
+{
+ FILE *stream;
+ struct cleanup *cleanups;
+
+ if (file == 0)
+ error_no_arg ("file to read commands from");
+
+ stream = fopen (file, "r");
+ if (stream == 0)
+ perror_with_name (file);
+
+ cleanups = make_cleanup (source_cleanup, instream);
+
+ instream = stream;
+
+ command_loop ();
+
+ do_cleanups (cleanups);
+}
+
+static void
+echo_command (text)
+ char *text;
+{
+ char *p = text;
+ register int c;
+
+ if (text)
+ while (c = *p++)
+ {
+ if (c == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ if (*p == 0)
+ return;
+
+ c = parse_escape (&p);
+ if (c >= 0)
+ fputc (c, stdout);
+ }
+ else
+ fputc (c, stdout);
+ }
+}
+
+static void
+dump_me_command ()
+{
+ if (query ("Should GDB dump core? "))
+ {
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ }
+}
+
+static void
+init_cmd_lists ()
+{
+ cmdlist = (struct cmd_list_element *) 0;
+ infolist = (struct cmd_list_element *) 0;
+ enablelist = (struct cmd_list_element *) 0;
+ disablelist = (struct cmd_list_element *) 0;
+ deletelist = (struct cmd_list_element *) 0;
+ enablebreaklist = (struct cmd_list_element *) 0;
+ setlist = (struct cmd_list_element *) 0;
+}
+
+static void
+init_main ()
+{
+ prompt = savestring ("(gdb) ", 6);
+
+ /* Define the classes of commands.
+ They will appear in the help list in the reverse of this order. */
+
+ add_cmd ("obscure", class_obscure, 0, "Obscure features.", &cmdlist);
+ add_cmd ("alias", class_alias, 0, "Aliases of other commands.", &cmdlist);
+ add_cmd ("user", class_user, 0, "User-defined commands.\n\
+The commands in this class are those defined by the user.\n\
+Use the \"define\" command to define a command.", &cmdlist);
+ add_cmd ("support", class_support, 0, "Support facilities.", &cmdlist);
+ add_cmd ("status", class_info, 0, "Status inquiries.", &cmdlist);
+ add_cmd ("files", class_files, 0, "Specifying and examining files.", &cmdlist);
+ add_cmd ("breakpoints", class_breakpoint, 0, "Making program stop at certain points.", &cmdlist);
+ add_cmd ("data", class_vars, 0, "Examining data.", &cmdlist);
+ add_cmd ("stack", class_stack, 0, "Examining the stack.\n\
+The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\
+counting from zero for the innermost (currently executing) frame.\n\n\
+At any time gdb identifies one frame as the \"selected\" frame.\n\
+Variable lookups are done with respect to the selected frame.\n\
+When the program being debugged stops, gdb selects the innermost frame.\n\
+The commands below can be used to select other frames by number or address.",
+ &cmdlist);
+ add_cmd ("running", class_run, 0, "Running the program.", &cmdlist);
+
+ add_com ("pwd", class_files, pwd_command,
+ "Print working directory. This is used for your program as well.");
+ add_com ("cd", class_files, cd_command,
+ "Set working directory to DIR for debugger and program being debugged.\n\
+The change does not take effect for the program being debugged\n\
+until the next time it is started.");
+
+ add_cmd ("prompt", class_support, set_prompt_command,
+ "Change gdb's prompt from the default of \"(gdb)\"",
+ &setlist);
+ add_com ("echo", class_support, echo_command,
+ "Print a constant string. Give string as argument.\n\
+C escape sequences may be used in the argument.\n\
+No newline is added at the end of the argument;\n\
+use \"\\n\" if you want a newline to be printed.\n\
+Since leading and trailing whitespace are ignored in command arguments,\n\
+if you want to print some you must use \"\\\" before leading whitespace\n\
+to be printed or after trailing whitespace.");
+ add_com ("document", class_support, document_command,
+ "Document a user-defined command.\n\
+Give command name as argument. Give documentation on following lines.\n\
+End with a line of just \"end\".");
+ add_com ("define", class_support, define_command,
+ "Define a new command name. Command name is argument.\n\
+Definition appears on following lines, one command per line.\n\
+End with a line of just \"end\".\n\
+Use the \"document\" command to give documentation for the new command.\n\
+Commands defined in this way do not take arguments.");
+
+ add_com ("source", class_support, source_command,
+ "Read commands from a file named FILE.\n\
+Note that the file \".gdbinit\" is read automatically in this way\n\
+when gdb is started.");
+ add_com ("quit", class_support, quit_command, "Exit gdb.");
+ add_com ("help", class_support, help_command, "Print list of commands.");
+ add_com_alias ("q", "quit", class_support, 1);
+ add_com_alias ("h", "help", class_support, 1);
+
+ add_com ("dump-me", class_obscure, dump_me_command,
+ "Get fatal error; make debugger dump its core.");
+
+ add_prefix_cmd ("info", class_info, info_command,
+ "Generic command for printing status.",
+ &infolist, "info ", 0, &cmdlist);
+ add_com_alias ("i", "info", class_info, 1);
+
+ add_info ("copying", copying_info, "Conditions for redistributing copies of GDB.");
+ add_info ("warranty", warranty_info, "Various kinds of warranty you do not have.");
+ add_info ("version", version_info, "Report what version of GDB this is.");
+}
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d103 2
+a104 2
+static void initialize_main ();
+static void initialize_cmd_lists ();
+d247 3
+a249 3
+ initialize_cmd_lists (); /* This needs to be done first */
+ initialize_all_files ();
+ initialize_main (); /* But that omits this file! Do it now */
+d1206 1
+a1206 1
+initialize_cmd_lists ()
+d1218 1
+a1218 1
+initialize_main ()
+@
diff --git a/gdb/RCS/munch,v b/gdb/RCS/munch,v
new file mode 100755
index 0000000..bac6946
--- /dev/null
+++ b/gdb/RCS/munch,v
@@ -0,0 +1,75 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @# @;
+
+
+1.3
+date 89.03.27.21.15.45; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.03.27.20.18.28; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.20.18.58.17; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@Fix up "munch" so it generates a name that doesn't match its own
+"grep" conventions. Change main so that it calls the new name,
+and also doesn't use the conventions for functions that should NOT
+be called by init.c.
+@
+text
+@#! /bin/sh
+
+# create an initialization procedure from a list of .o files
+# Look in object files, find symbols including the string _initialize_,
+# and call each one as a function.
+
+echo '/* Do not modify this file. It is created automatically by "munch". */'
+echo 'void init_all_files () {'
+
+nm $* | egrep '_initialize_' | \
+ sed -e 's/^.*\(initialize_[a-zA-Z_0-9]*\).*$/ _\1 ();/' | \
+ sort -u
+
+echo '}'
+@
+
+
+1.2
+log
+@Generic change: make it not care much about the output format of "nm".
+Now as long as _initialize_foo is not touching any other
+symbol or alphanumeric, we'll find it and use it.
+@
+text
+@d8 1
+a8 1
+echo 'void initialize_all_files () {'
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d4 2
+d10 3
+a12 1
+nm -p $* | egrep 'T *__?initialize_' | sed -e 's/^.*T *_*\(.*\)/ _\1 ();/'
+@
diff --git a/gdb/RCS/printcmd.c,v b/gdb/RCS/printcmd.c,v
new file mode 100644
index 0000000..2ab3acc
--- /dev/null
+++ b/gdb/RCS/printcmd.c,v
@@ -0,0 +1,1707 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.04.26.00.54.22; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.04.25.15.38.49; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@(1) Depend on XXX_BIG_ENDIAN rather than testing gdb's object code.
+(2) Print to the STREAM parameter, not to stdout.
+(3) Use is_nan with new arguments.
+(4) Use unpack_double with new args, and deal with invalid results.
+(5) Don't print history numbers in the "print" command for things
+that weren't recorded in history (because they were invalid values).
+@
+text
+@/* Print values for GNU debugger GDB.
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+
+struct format_data
+{
+ int count;
+ char format;
+ char size;
+};
+
+/* Last specified output format. */
+
+static char last_format = 'x';
+
+/* Last specified examination size. 'b', 'h', 'w' or `q'. */
+
+static char last_size = 'w';
+
+/* Default address to examine next. */
+
+static CORE_ADDR next_address;
+
+/* Last address examined. */
+
+static CORE_ADDR last_examine_address;
+
+/* Contents of last address examined.
+ This is not valid past the end of the `x' command! */
+
+static value last_examine_value;
+
+/* Number of auto-display expression currently being displayed.
+ So that we can deleted it if we get an error or a signal within it.
+ -1 when not doing one. */
+
+int current_display_number;
+
+static void do_one_display ();
+
+void do_displays ();
+void print_address ();
+void print_scalar_formatted ();
+
+
+/* Decode a format specification. *STRING_PTR should point to it.
+ OFORMAT and OSIZE are used as defaults for the format and size
+ if none are given in the format specification.
+ The structure returned describes all the data
+ found in the specification. In addition, *STRING_PTR is advanced
+ past the specification and past all whitespace following it. */
+
+struct format_data
+decode_format (string_ptr, oformat, osize)
+ char **string_ptr;
+ char oformat;
+ char osize;
+{
+ struct format_data val;
+ register char *p = *string_ptr;
+
+ val.format = oformat;
+ val.size = osize;
+ val.count = 1;
+
+ if (*p >= '0' && *p <= '9')
+ val.count = atoi (p);
+ while (*p >= '0' && *p <= '9') p++;
+
+ /* Now process size or format letters that follow. */
+
+ while (1)
+ {
+ if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g')
+ val.size = *p++;
+#ifdef LONG_LONG
+ else if (*p == 'l')
+ {
+ val.size = 'g';
+ p++;
+ }
+#endif
+ else if (*p >= 'a' && *p <= 'z')
+ val.format = *p++;
+ else
+ break;
+ }
+
+#ifndef LONG_LONG
+ /* Make sure 'g' size is not used on integer types.
+ Well, actually, we can handle hex. */
+ if (val.size == 'g' && val.format != 'f' && val.format != 'x')
+ val.size = 'w';
+#endif
+
+ while (*p == ' ' || *p == '\t') p++;
+ *string_ptr = p;
+
+ return val;
+}
+
+/* Print value VAL on stdout according to FORMAT, a letter or 0.
+ Do not end with a newline.
+ 0 means print VAL according to its own type.
+ SIZE is the letter for the size of datum being printed.
+ This is used to pad hex numbers so they line up. */
+
+static void
+print_formatted (val, format, size)
+ register value val;
+ register char format;
+ char size;
+{
+ int len = TYPE_LENGTH (VALUE_TYPE (val));
+
+ if (VALUE_LVAL (val) == lval_memory)
+ next_address = VALUE_ADDRESS (val) + len;
+
+ switch (format)
+ {
+ case 's':
+ next_address = VALUE_ADDRESS (val)
+ + value_print (value_addr (val), stdout, 0);
+ break;
+
+ case 'i':
+ next_address = VALUE_ADDRESS (val)
+ + print_insn (VALUE_ADDRESS (val), stdout);
+ break;
+
+ default:
+ if (format == 0
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_ARRAY
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_UNION
+ || VALUE_REPEATED (val))
+ value_print (val, stdout, format);
+ else
+ print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val),
+ format, size, stdout);
+ }
+}
+
+/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
+ according to letters FORMAT and SIZE on STREAM.
+ FORMAT may not be zero. Formats s and i are not supported at this level.
+
+ This is how the elements of an array or structure are printed
+ with a format. */
+
+void
+print_scalar_formatted (valaddr, type, format, size, stream)
+ char *valaddr;
+ struct type *type;
+ char format;
+ int size;
+ FILE *stream;
+{
+ LONGEST val_long;
+ int len = TYPE_LENGTH (type);
+
+ if (size == 'g' && sizeof (LONGEST) < 8
+ && format == 'x')
+ {
+ /* ok, we're going to have to get fancy here. Assumption: a
+ long is four bytes. */
+ unsigned long v1, v2, tmp;
+
+ v1 = unpack_long (builtin_type_long, valaddr);
+ v2 = unpack_long (builtin_type_long, valaddr + 4);
+
+#ifdef BYTES_BIG_ENDIAN
+#else
+ /* Little endian -- swap the two for printing */
+ tmp = v1;
+ v1 = v2;
+ v2 = tmp;
+#endif
+
+ switch (format)
+ {
+ case 'x':
+ fprintf (stream, "0x%08x%08x", v1, v2);
+ break;
+ default:
+ error ("Output size \"g\" unimplemented for format \"%c\".",
+ format);
+ }
+ return;
+ }
+
+ val_long = unpack_long (type, valaddr);
+
+ /* If value is unsigned, truncate it in case negative. */
+ if (format != 'd')
+ {
+ if (len == sizeof (char))
+ val_long &= (1 << 8 * sizeof(char)) - 1;
+ else if (len == sizeof (short))
+ val_long &= (1 << 8 * sizeof(short)) - 1;
+ else if (len == sizeof (long))
+ val_long &= (unsigned long) - 1;
+ }
+
+ switch (format)
+ {
+ case 'x':
+#ifdef LONG_LONG
+ if (!size)
+ size = (len < sizeof (long long) ? 'w' : 'g');
+ switch (size)
+ {
+ case 'b':
+ fprintf (stream, "0x%02llx", val_long);
+ break;
+ case 'h':
+ fprintf (stream, "0x%04llx", val_long);
+ break;
+ case 0: /* no size specified, like in print */
+ case 'w':
+ fprintf (stream, "0x%08llx", val_long);
+ break;
+ case 'g':
+ fprintf (stream, "0x%16llx", val_long);
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+#else
+ switch (size)
+ {
+ case 'b':
+ fprintf (stream, "0x%02x", val_long);
+ break;
+ case 'h':
+ fprintf (stream, "0x%04x", val_long);
+ break;
+ case 0: /* no size specified, like in print */
+ case 'w':
+ fprintf (stream, "0x%08x", val_long);
+ break;
+ case 'g':
+ fprintf (stream, "0x%16x", val_long);
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+#endif /* not LONG_LONG */
+ break;
+
+ case 'd':
+#ifdef LONG_LONG
+ fprintf (stream, "%lld", val_long);
+#else
+ fprintf (stream, "%d", val_long);
+#endif
+ break;
+
+ case 'u':
+#ifdef LONG_LONG
+ fprintf (stream, "%llu", val_long);
+#else
+ fprintf (stream, "%u", val_long);
+#endif
+ break;
+
+ case 'o':
+ if (val_long)
+#ifdef LONG_LONG
+ fprintf (stream, "0%llo", val_long);
+#else
+ fprintf (stream, "0%o", val_long);
+#endif
+ else
+ fprintf (stream, "0");
+ break;
+
+ case 'a':
+ print_address ((CORE_ADDR) val_long, stream);
+ break;
+
+ case 'c':
+ value_print (value_from_long (builtin_type_char, val_long), stream, 0);
+ break;
+
+ case 'f':
+ if (len == sizeof (float))
+ type = builtin_type_float;
+ else if (len == sizeof (double))
+ type = builtin_type_double;
+ else abort();
+
+#ifdef IEEE_FLOAT
+ if (is_nan (valaddr, len))
+ {
+ fprintf (stream, "NaN");
+ break;
+ }
+#endif
+ {
+ double doub;
+ int inv;
+
+ doub = unpack_double (type, valaddr, &inv);
+ if (inv)
+ fprintf (stream, "Invalid float value");
+ else
+ fprintf (stream, len > 4? "%.16g": "%.6g", doub);
+ }
+ break;
+
+ case 0:
+ abort ();
+
+ default:
+ error ("Undefined output format \"%c\".", format);
+ }
+}
+
+/* Specify default address for `x' command.
+ `info lines' uses this. */
+
+void
+set_next_address (addr)
+ CORE_ADDR addr;
+{
+ next_address = addr;
+
+ /* Make address available to the user as $_. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_long (builtin_type_int, (LONGEST) addr));
+}
+
+/* Print address ADDR symbolically on STREAM.
+ First print it as a number. Then perhaps print
+ <SYMBOL + OFFSET> after the number. */
+
+void
+print_address (addr, stream)
+ CORE_ADDR addr;
+ FILE *stream;
+{
+ register int i;
+ struct symbol *fs;
+ char *name;
+ int name_location;
+
+ fprintf (stream, "0x%x", addr);
+
+ fs = find_pc_function (addr);
+
+ if (!fs)
+ {
+ i = find_pc_misc_function (addr);
+
+ if (i < 0) return; /* If nothing comes through, don't
+ print anything symbolic */
+
+ name = misc_function_vector[i].name;
+ name_location = misc_function_vector[i].address;
+ }
+ else
+ {
+ name = fs->name;
+ name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (fs));
+ }
+
+ if (addr - name_location)
+ fprintf (stream, " <%s+%d>",
+ name,
+ addr - name_location);
+ else
+ fprintf (stream, " <%s>", name);
+}
+
+/* Examine data at address ADDR in format FMT.
+ Fetch it from memory and print on stdout. */
+
+static void
+do_examine (fmt, addr)
+ struct format_data fmt;
+ CORE_ADDR addr;
+{
+ register char format = 0;
+ register char size;
+ register int count = 1;
+ struct type *val_type;
+ register int i;
+ register int maxelts;
+
+ format = fmt.format;
+ size = fmt.size;
+ count = fmt.count;
+ next_address = addr;
+
+ /* String or instruction format implies fetch single bytes
+ regardless of the specified size. */
+ if (format == 's' || format == 'i')
+ size = 'b';
+
+ if (size == 'b')
+ val_type = builtin_type_char;
+ else if (size == 'h')
+ val_type = builtin_type_short;
+ else if (size == 'w')
+ val_type = builtin_type_long;
+ else if (size == 'g')
+#ifndef LONG_LONG
+ val_type = builtin_type_double;
+#else
+ val_type = builtin_type_long_long;
+#endif
+
+ maxelts = 8;
+ if (size == 'w')
+ maxelts = 4;
+ if (size == 'g')
+ maxelts = 2;
+ if (format == 's' || format == 'i')
+ maxelts = 1;
+
+ /* Print as many objects as specified in COUNT, at most maxelts per line,
+ with the address of the next one at the start of each line. */
+
+ while (count > 0)
+ {
+ print_address (next_address, stdout);
+ fputc (':', stdout);
+ for (i = maxelts;
+ i > 0 && count > 0;
+ i--, count--)
+ {
+ fputc ('\t', stdout);
+ /* Note that print_formatted sets next_address for the next
+ object. */
+ last_examine_address = next_address;
+ last_examine_value = value_at (val_type, next_address);
+ print_formatted (last_examine_value, format, size);
+ }
+ fputc ('\n', stdout);
+ fflush (stdout);
+ }
+}
+
+static void
+validate_format (fmt, cmdname)
+ struct format_data fmt;
+ char *cmdname;
+{
+ if (fmt.size != 0)
+ error ("Size letters are meaningless in \"%s\" command.", cmdname);
+ if (fmt.count != 1)
+ error ("Item count other than 1 is meaningless in \"%s\" command.",
+ cmdname);
+ if (fmt.format == 'i' || fmt.format == 's')
+ error ("Format letter \"%c\" is meaningless in \"%s\" command.",
+ fmt.format, cmdname);
+}
+
+static void
+print_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain = 0;
+ register char format = 0;
+ register value val;
+ struct format_data fmt;
+ int histindex;
+ int cleanup = 0;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, 0);
+ validate_format (fmt, "print");
+ last_format = format = fmt.format;
+ }
+
+ if (exp && *exp)
+ {
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ cleanup = 1;
+ val = evaluate_expression (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ histindex = record_latest_value (val);
+ if (histindex >= 0) printf ("$%d = ", histindex);
+
+ print_formatted (val, format, fmt.size);
+ printf ("\n");
+
+ if (cleanup)
+ do_cleanups (old_chain);
+}
+
+static void
+output_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain;
+ register char format = 0;
+ register value val;
+ struct format_data fmt;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ validate_format (fmt, "print");
+ format = fmt.format;
+ }
+
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+
+ print_formatted (val, format, fmt.size);
+
+ do_cleanups (old_chain);
+}
+
+static void
+set_command (exp)
+ char *exp;
+{
+ struct expression *expr = parse_c_expression (exp);
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+ evaluate_expression (expr);
+ do_cleanups (old_chain);
+}
+
+static void
+address_info (exp)
+ char *exp;
+{
+ register struct symbol *sym;
+ register CORE_ADDR val;
+ int is_a_field_of_this; /* C++: lookup_symbol sets this to nonzero
+ if exp is a field of `this'. */
+
+ if (exp == 0)
+ error ("Argument required.");
+
+ sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE,
+ &is_a_field_of_this);
+ if (sym == 0)
+ {
+ register int i;
+
+ if (is_a_field_of_this)
+ {
+ printf("Symbol \"%s\" is a field of the local class variable `this'\n", exp);
+ return;
+ }
+
+ for (i = 0; i < misc_function_count; i++)
+ if (!strcmp (misc_function_vector[i].name, exp))
+ break;
+
+ if (i < misc_function_count)
+ printf ("Symbol \"%s\" is at 0x%x in a file compiled without -g.\n",
+ exp, misc_function_vector[i].address);
+ else
+ error ("No symbol \"%s\" in current context.", exp);
+ return;
+ }
+
+ printf ("Symbol \"%s\" is ", SYMBOL_NAME (sym));
+ val = SYMBOL_VALUE (sym);
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ printf ("constant");
+ break;
+
+ case LOC_LABEL:
+ printf ("a label at address 0x%x", val);
+ break;
+
+ case LOC_REGISTER:
+ printf ("a variable in register %s", reg_names[val]);
+ break;
+
+ case LOC_STATIC:
+ printf ("static at address 0x%x", val);
+ break;
+
+ case LOC_REGPARM:
+ printf ("an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_ARG:
+ printf ("an argument at offset %d", val);
+ break;
+
+ case LOC_LOCAL:
+ printf ("a local variable at frame offset %d", val);
+ break;
+
+ case LOC_TYPEDEF:
+ printf ("a typedef");
+ break;
+
+ case LOC_BLOCK:
+ printf ("a function at address 0x%x",
+ BLOCK_START (SYMBOL_BLOCK_VALUE (sym)));
+ break;
+ }
+ printf (".\n");
+}
+
+static void
+x_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct expression *expr;
+ struct format_data fmt;
+ struct cleanup *old_chain;
+
+ fmt.format = last_format;
+ fmt.size = last_size;
+ fmt.count = 1;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, last_size);
+ last_size = fmt.size;
+ last_format = fmt.format;
+ }
+
+ /* If we have an expression, evaluate it and use it as the address. */
+
+ if (exp != 0 && *exp != 0)
+ {
+ expr = parse_c_expression (exp);
+ /* Cause expression not to be there any more
+ if this command is repeated with Newline.
+ But don't clobber a user-defined command's definition. */
+ if (from_tty)
+ *exp = 0;
+ old_chain = make_cleanup (free_current_contents, &expr);
+ next_address = (CORE_ADDR) value_as_long (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ }
+
+ do_examine (fmt, next_address);
+
+ /* Set a couple of internal variables if appropriate. */
+ if (last_examine_value)
+ {
+ /* Make last address examined available to the user as $_. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_long (builtin_type_int,
+ (LONGEST) last_examine_address));
+
+ /* Make contents of last address examined available to the user as $__.*/
+ set_internalvar (lookup_internalvar ("__"), last_examine_value);
+ }
+}
+
+/* Commands for printing types of things. */
+
+static void
+whatis_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register value val;
+ register struct cleanup *old_chain;
+
+ if (exp)
+ {
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ val = evaluate_type (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ printf ("type = ");
+ type_print (VALUE_TYPE (val), "", stdout, 1);
+ printf ("\n");
+
+ if (exp)
+ do_cleanups (old_chain);
+}
+
+static void
+ptype_command (typename)
+ char *typename;
+{
+ register char *p = typename;
+ register int len;
+ extern struct block *get_current_block ();
+ register struct block *b
+ = (have_inferior_p () || have_core_file_p ()) ? get_current_block () : 0;
+ register struct type *type;
+
+ if (typename == 0)
+ error_no_arg ("type name");
+
+ while (*p && *p != ' ' && *p != '\t') p++;
+ len = p - typename;
+ while (*p == ' ' || *p == '\t') p++;
+
+ if (len == 6 && !strncmp (typename, "struct", 6))
+ type = lookup_struct (p, b);
+ else if (len == 5 && !strncmp (typename, "union", 5))
+ type = lookup_union (p, b);
+ else if (len == 4 && !strncmp (typename, "enum", 4))
+ type = lookup_enum (p, b);
+ else
+ {
+ type = lookup_typename (typename, b, 1);
+ if (type == 0)
+ {
+ register struct symbol *sym
+ = lookup_symbol (typename, b, STRUCT_NAMESPACE, 0);
+ if (sym == 0)
+ error ("No type named %s.", typename);
+ printf ("No type named %s, but there is a ",
+ typename);
+ switch (TYPE_CODE (SYMBOL_TYPE (sym)))
+ {
+ case TYPE_CODE_STRUCT:
+ printf ("struct");
+ break;
+
+ case TYPE_CODE_UNION:
+ printf ("union");
+ break;
+
+ case TYPE_CODE_ENUM:
+ printf ("enum");
+ }
+ printf (" %s. Type \"help ptype\".\n", typename);
+ type = SYMBOL_TYPE (sym);
+ }
+ }
+
+ type_print (type, "", stdout, 1);
+ printf ("\n");
+}
+
+enum display_status {disabled, enabled};
+
+struct display
+{
+ /* Chain link to next auto-display item. */
+ struct display *next;
+ /* Expression to be evaluated and displayed. */
+ struct expression *exp;
+ /* Item number of this auto-display item. */
+ int number;
+ /* Display format specified. */
+ struct format_data format;
+ /* Innermost block required by this expression when evaluated */
+ struct block *block;
+ /* Status of this display (enabled or disabled) */
+ enum display_status status;
+};
+
+/* Chain of expressions whose values should be displayed
+ automatically each time the program stops. */
+
+static struct display *display_chain;
+
+static int display_number;
+
+/* Add an expression to the auto-display chain.
+ Specify the expression. */
+
+static void
+display_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct format_data fmt;
+ register struct expression *expr;
+ register struct display *new;
+ extern struct block *innermost_block;
+
+ if (exp == 0)
+ {
+ do_displays ();
+ return;
+ }
+
+ if (*exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ if (fmt.size && fmt.format == 0)
+ fmt.format = 'x';
+ if (fmt.format == 'i' || fmt.format == 's')
+ fmt.size = 'b';
+ }
+ else
+ {
+ fmt.format = 0;
+ fmt.size = 0;
+ fmt.count = 0;
+ }
+
+ innermost_block = 0;
+ expr = parse_c_expression (exp);
+
+ new = (struct display *) xmalloc (sizeof (struct display));
+
+ new->exp = expr;
+ new->block = innermost_block;
+ new->next = display_chain;
+ new->number = ++display_number;
+ new->format = fmt;
+ new->status = enabled;
+ display_chain = new;
+
+ if (from_tty && have_inferior_p ())
+ do_one_display (new);
+
+ dont_repeat ();
+}
+
+static void
+free_display (d)
+ struct display *d;
+{
+ free (d->exp);
+ free (d);
+}
+
+/* Clear out the display_chain.
+ Done when new symtabs are loaded, since this invalidates
+ the types stored in many expressions. */
+
+void
+clear_displays ()
+{
+ register struct display *d;
+
+ while (d = display_chain)
+ {
+ free (d->exp);
+ display_chain = d->next;
+ free (d);
+ }
+}
+
+/* Delete the auto-display number NUM. */
+
+void
+delete_display (num)
+ int num;
+{
+ register struct display *d1, *d;
+
+ if (!display_chain)
+ error ("No display number %d.", num);
+
+ if (display_chain->number == num)
+ {
+ d1 = display_chain;
+ display_chain = d1->next;
+ free_display (d1);
+ }
+ else
+ for (d = display_chain; ; d = d->next)
+ {
+ if (d->next == 0)
+ error ("No display number %d.", num);
+ if (d->next->number == num)
+ {
+ d1 = d->next;
+ d->next = d1->next;
+ free_display (d1);
+ break;
+ }
+ }
+}
+
+/* Delete some values from the auto-display chain.
+ Specify the element numbers. */
+
+static void
+undisplay_command (args)
+ char *args;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d, *d1;
+
+ if (args == 0)
+ {
+ if (query ("Delete all auto-display expressions? "))
+ clear_displays ();
+ dont_repeat ();
+ return;
+ }
+
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9') p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ delete_display (num);
+
+ p = p1;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+ dont_repeat ();
+}
+
+/* Display a single auto-display.
+ Do nothing if the display cannot be printed in the current context,
+ or if the display is disabled. */
+
+static void
+do_one_display (d)
+ struct display *d;
+{
+ int within_current_scope;
+
+ if (d->status == disabled)
+ return;
+
+ if (d->block)
+ within_current_scope = contained_in (get_selected_block (), d->block);
+ else
+ within_current_scope = 1;
+ if (!within_current_scope)
+ return;
+
+ current_display_number = d->number;
+
+ printf ("%d: ", d->number);
+ if (d->format.size)
+ {
+ printf ("x/");
+ if (d->format.count != 1)
+ printf ("%d", d->format.count);
+ printf ("%c", d->format.format);
+ if (d->format.format != 'i' && d->format.format != 's')
+ printf ("%c", d->format.size);
+ printf (" ");
+ print_expression (d->exp, stdout);
+ if (d->format.count != 1)
+ printf ("\n");
+ else
+ printf (" ");
+ do_examine (d->format,
+ (CORE_ADDR) value_as_long (evaluate_expression (d->exp)));
+
+ }
+ else
+ {
+ if (d->format.format)
+ printf ("/%c ", d->format.format);
+ print_expression (d->exp, stdout);
+ printf (" = ");
+ print_formatted (evaluate_expression (d->exp),
+ d->format.format, d->format.size);
+ printf ("\n");
+ }
+
+ fflush (stdout);
+ current_display_number = -1;
+}
+
+/* Display all of the values on the auto-display chain which can be
+ evaluated in the current scope. */
+
+void
+do_displays ()
+{
+ register struct display *d;
+
+ for (d = display_chain; d; d = d->next)
+ do_one_display (d);
+}
+
+/* Delete the auto-display which we were in the process of displaying.
+ This is done when there is an error or a signal. */
+
+void
+delete_current_display ()
+{
+ if (current_display_number >= 0)
+ {
+ delete_display (current_display_number);
+ fprintf (stderr, "Deleting display %d to avoid infinite recursion.\n",
+ current_display_number);
+ }
+ current_display_number = -1;
+}
+
+static void
+display_info ()
+{
+ register struct display *d;
+
+ if (!display_chain)
+ printf ("There are no auto-display expressions now.\n");
+ else
+ printf ("Auto-display expressions now in effect:\n\
+Num Enb Expression\n");
+
+ for (d = display_chain; d; d = d->next)
+ {
+ printf ("%d: %c ", d->number, "ny"[(int)d->status]);
+ if (d->format.size)
+ printf ("/%d%c%c ", d->format.count, d->format.size,
+ d->format.format);
+ else if (d->format.format)
+ printf ("/%c ", d->format.format);
+ print_expression (d->exp, stdout);
+ if (d->block && !contained_in (get_selected_block (), d->block))
+ printf (" (cannot be evaluated in the current context)");
+ printf ("\n");
+ fflush (stdout);
+ }
+}
+
+void
+enable_display (args)
+ char *args;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d->next)
+ d->status = enabled;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->status = enabled;
+ goto win;
+ }
+ printf ("No display number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+void
+disable_display (args)
+ char *args;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d->next)
+ d->status = disabled;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->status = disabled;
+ goto win;
+ }
+ printf ("No display number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+
+/* Print the value in stack frame FRAME of a variable
+ specified by a struct symbol. */
+
+void
+print_variable_value (var, frame, stream)
+ struct symbol *var;
+ CORE_ADDR frame;
+ FILE *stream;
+{
+ value val = read_var_value (var, frame);
+ value_print (val, stream, 0);
+}
+
+/* Print the arguments of a stack frame, given the function FUNC
+ running in that frame (as a symbol), the info on the frame,
+ and the number of args according to the stack frame (or -1 if unknown). */
+
+static void print_frame_nameless_args ();
+
+void
+print_frame_args (func, fi, num, stream)
+ struct symbol *func;
+ struct frame_info *fi;
+ int num;
+ FILE *stream;
+{
+ struct block *b;
+ int nsyms = 0;
+ int first = 1;
+ register int i;
+ register int last_offset = FRAME_ARGS_SKIP;
+ register int last_regparm = 0;
+ register struct symbol *lastsym, *sym, *nextsym;
+ register value val;
+ register CORE_ADDR addr = FRAME_ARGS_ADDRESS (fi);
+
+ if (func)
+ {
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+ }
+
+ lastsym = 0;
+ while (1)
+ {
+ /* Find first arg that is not before LAST_OFFSET. */
+ nextsym = 0;
+ for (i = 0; i < nsyms; i++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (sym) == LOC_ARG)
+ {
+ if (SYMBOL_VALUE (sym) >= last_offset
+ && (nextsym == 0
+ || SYMBOL_VALUE (sym) < SYMBOL_VALUE (nextsym)))
+ nextsym = sym;
+ }
+ else if (SYMBOL_CLASS (sym) == LOC_REGPARM)
+ {
+ /* This shouldn't be sorted by number. Since we can't
+ find nameless args with register parameters, print
+ this out in order by .stabs. */
+ if (sym > lastsym && nextsym == 0)
+ nextsym = sym;
+ }
+ }
+ if (nextsym == 0)
+ break;
+ sym = nextsym;
+ /* Print any nameless args between the last arg printed
+ and the next arg. */
+ if (SYMBOL_CLASS (sym) == LOC_ARG
+ && last_offset != (SYMBOL_VALUE (sym) / sizeof (int)) * sizeof (int))
+ {
+ print_frame_nameless_args (addr, last_offset, SYMBOL_VALUE (sym),
+ stream);
+ first = 0;
+ }
+ /* Print the next arg. */
+ if (SYMBOL_CLASS (sym) == LOC_REGPARM)
+ val = value_from_register (SYMBOL_TYPE (sym),
+ SYMBOL_VALUE (sym),
+ FRAME_INFO_ID (fi));
+ else
+ val = value_at (SYMBOL_TYPE (sym), addr + SYMBOL_VALUE (sym));
+
+ if (! first)
+ fprintf (stream, ", ");
+ fprintf (stream, "%s=", SYMBOL_NAME (sym));
+ value_print (val, stream, 0);
+ first = 0;
+ if (SYMBOL_CLASS (sym) == LOC_ARG)
+ last_offset = SYMBOL_VALUE (sym) + TYPE_LENGTH (SYMBOL_TYPE (sym));
+ else
+ {
+ last_regparm = SYMBOL_VALUE (sym) + 1;
+ last_offset += TYPE_LENGTH (SYMBOL_TYPE (sym));
+ }
+
+ /* Round up address of next arg to multiple of size of int. */
+ last_offset
+ = ((last_offset + sizeof (int) - 1) / sizeof (int)) * sizeof (int);
+ lastsym = sym;
+ }
+ if (num >= 0 && num * sizeof (int) + FRAME_ARGS_SKIP > last_offset)
+ print_frame_nameless_args (addr, last_offset,
+ num * sizeof (int) + FRAME_ARGS_SKIP, stream);
+}
+
+static void
+print_frame_nameless_args (argsaddr, start, end, stream)
+ CORE_ADDR argsaddr;
+ int start;
+ int end;
+ FILE *stream;
+{
+ while (start < end)
+ {
+ QUIT;
+ if (start != FRAME_ARGS_SKIP)
+ fprintf (stream, ", ");
+ fprintf (stream, "%d",
+ read_memory_integer (argsaddr + start, sizeof (int)));
+ start += sizeof (int);
+ }
+}
+
+static void
+printf_command (arg)
+ char *arg;
+{
+ register char *f;
+ register char *s = arg;
+ char *string;
+ value *val_args;
+ int nargs = 0;
+ int allocated_args = 20;
+ char *arg_bytes;
+ char *argclass;
+ int i;
+ int argindex;
+ int nargs_wanted;
+
+ val_args = (value *) xmalloc (allocated_args * sizeof (value));
+
+ if (s == 0)
+ error_no_arg ("format-control string and values to print");
+
+ /* Skip white space before format string */
+ while (*s == ' ' || *s == '\t') s++;
+
+ /* A format string should follow, enveloped in double quotes */
+ if (*s++ != '"')
+ error ("Bad format string, missing '\"'.");
+
+ /* Parse the format-control string and copy it into the string STRING,
+ processing some kinds of escape sequence. */
+
+ f = string = (char *) alloca (strlen (s) + 1);
+ while (*s != '"')
+ {
+ int c = *s++;
+ switch (c)
+ {
+ case '\0':
+ error ("Bad format string, non-terminated '\"'.");
+ /* doesn't return */
+
+ case '\\':
+ switch (c = *s++)
+ {
+ case '\\':
+ *f++ = '\\';
+ break;
+ case 'n':
+ *f++ = '\n';
+ break;
+ case 't':
+ *f++ = '\t';
+ break;
+ case 'r':
+ *f++ = '\r';
+ break;
+ case '"':
+ *f++ = '"';
+ break;
+ default:
+ /* ??? TODO: handle other escape sequences */
+ error ("Unrecognized \\ escape character in format string.");
+ }
+ break;
+
+ default:
+ *f++ = c;
+ }
+ }
+
+ /* Skip over " and following space and comma. */
+ s++;
+ *f++ = '\0';
+ while (*s == ' ' || *s == '\t') s++;
+
+ if (*s != ',' && *s != 0)
+ error ("Invalid argument syntax");
+
+ if (*s == ',') s++;
+ while (*s == ' ' || *s == '\t') s++;
+
+ /* Now scan the string for %-specs and see what kinds of args they want.
+ argclass[I] is set to 1 if the Ith arg should be a string.
+ It's set to 2 if the Ith arg should be floating point. */
+
+ argclass = (char *) alloca (strlen (s));
+ nargs_wanted = 0;
+ f = string;
+ while (*f)
+ if (*f++ == '%')
+ {
+ while (index ("0123456789.hlL-+ #", *f)) f++;
+ if (*f == 's')
+ argclass[nargs_wanted++] = 1;
+ else if (*f == 'e' || *f == 'f' || *f == 'g')
+ argclass[nargs_wanted++] = 2;
+ else if (*f != '%')
+ argclass[nargs_wanted++] = 0;
+ f++;
+ }
+
+ /* Now, parse all arguments and evaluate them.
+ Store the VALUEs in VAL_ARGS. */
+
+ while (*s != '\0')
+ {
+ char *s1;
+ if (nargs == allocated_args)
+ val_args = (value *) xrealloc (val_args,
+ (allocated_args *= 2)
+ * sizeof (value));
+ s1 = s;
+ val_args[nargs] = parse_to_comma_and_eval (&s1);
+
+ /* If format string wants a float, unchecked-convert the value to
+ floating point of the same size */
+
+ if (argclass[nargs] == 2)
+ {
+ argclass[nargs] = 0;
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (float))
+ VALUE_TYPE (val_args[nargs]) = builtin_type_float;
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (double))
+ VALUE_TYPE (val_args[nargs]) = builtin_type_double;
+ }
+ nargs++;
+ s = s1;
+ if (*s == ',')
+ s++;
+ }
+
+ if (nargs != nargs_wanted)
+ error ("Wrong number of arguments for specified format-string");
+
+ /* Now lay out an argument-list containing the arguments
+ as doubles, integers and C pointers. */
+
+ arg_bytes = (char *) alloca (sizeof (double) * nargs);
+ argindex = 0;
+ for (i = 0; i < nargs; i++)
+ {
+ if (argclass[i])
+ {
+ char *str;
+ int tem, j;
+ tem = value_as_long (val_args[i]);
+
+ /* This is a %s argument. Find the length of the string. */
+ for (j = 0; ; j++)
+ {
+ char c;
+ QUIT;
+ read_memory (tem + j, &c, 1);
+ if (c == 0)
+ break;
+ }
+
+ /* Copy the string contents into a string inside GDB. */
+ str = (char *) alloca (j + 1);
+ read_memory (tem, str, j);
+ str[j] = 0;
+
+ /* Pass address of internal copy as the arg to vprintf. */
+ *((int *) &arg_bytes[argindex]) = (int) str;
+ argindex += sizeof (int);
+ }
+ else if (VALUE_TYPE (val_args[i])->code == TYPE_CODE_FLT)
+ {
+ *((double *) &arg_bytes[argindex]) = value_as_double (val_args[i]);
+ argindex += sizeof (double);
+ }
+ else
+#ifdef LONG_LONG
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[i])) == sizeof (long long))
+ {
+ *(long long *) &arg_bytes[argindex] = value_as_long (val_args[i]);
+ argindex += sizeof (long long);
+ }
+ else
+#endif
+ {
+ *((int *) &arg_bytes[argindex]) = value_as_long (val_args[i]);
+ argindex += sizeof (int);
+ }
+ }
+
+ vprintf (string, arg_bytes);
+}
+
+extern struct cmd_list_element *enablelist, *disablelist, *deletelist;
+extern struct cmd_list_element *cmdlist, *setlist;
+
+void
+_initialize_printcmd ()
+{
+ current_display_number = -1;
+
+ add_info ("address", address_info,
+ "Describe where variable VAR is stored.");
+
+ add_com ("x", class_vars, x_command,
+ "Examine memory: x/FMT ADDRESS.\n\
+ADDRESS is an expression for the memory address to examine.\n\
+FMT is a repeat count followed by a format letter and a size letter.\n\
+Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
+ f(float), a(address), i(instruction), c(char) and s(string).\n\
+Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
+ g is meaningful only with f, for type double.\n\
+The specified number of objects of the specified size are printed\n\
+according to the format.\n\n\
+Defaults for format and size letters are those previously used.\n\
+Default count is 1. Default address is following last thing printed\n\
+with this command or \"print\".");
+
+ add_com ("ptype", class_vars, ptype_command,
+ "Print definition of type TYPE.\n\
+Argument may be a type name defined by typedef, or \"struct STRUCTNAME\"\n\
+or \"union UNIONNAME\" or \"enum ENUMNAME\".\n\
+The selected stack frame's lexical context is used to look up the name.");
+
+ add_com ("whatis", class_vars, whatis_command,
+ "Print data type of expression EXP.");
+
+ add_info ("display", display_info,
+ "Expressions to display when program stops, with code numbers.");
+
+ add_abbrev_cmd ("undisplay", class_vars, undisplay_command,
+ "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+\"delete display\" has the same effect as this command.\n\
+Do \"info display\" to see current list of code numbers.",
+ &cmdlist);
+
+ add_com ("display", class_vars, display_command,
+ "Print value of expression EXP each time the program stops.\n\
+/FMT may be used before EXP as in the \"print\" command.\n\
+/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\
+as in the \"x\" command, and then EXP is used to get the address to examine\n\
+and examining is done as in the \"x\" command.\n\n\
+With no argument, display all currently requested auto-display expressions.\n\
+Use \"undisplay\" to cancel display requests previously made.");
+
+ add_cmd ("display", class_vars, enable_display,
+ "Enable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to resume displaying.\n\
+No argument means enable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &enablelist);
+
+ add_cmd ("display", class_vars, disable_display,
+ "Disable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means disable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &disablelist);
+
+ add_cmd ("display", class_vars, undisplay_command,
+ "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &deletelist);
+
+ add_com ("printf", class_vars, printf_command,
+ "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
+This is useful for formatted output in user-defined commands.");
+ add_com ("output", class_vars, output_command,
+ "Like \"print\" but don't put in value history and don't print newline.\n\
+This is useful in user-defined commands.");
+
+ add_prefix_cmd ("set", class_vars, set_command,
+"Perform an assignment VAR = EXP.\n\
+You must type the \"=\". VAR may be a debugger \"convenience\" variable\n\
+(names starting with $), a register (a few standard names starting with $),\n\
+or an actual variable in the program being debugged. EXP is any expression.\n\
+Use \"set variable\" for variables with names identical to set subcommands.\n\
+\nWith a subcommand, this command modifies parts of the gdb environment",
+ &setlist, "set ", 1, &cmdlist);
+
+ add_cmd ("variable", class_vars, set_command,
+ "Perform an assignment VAR = EXP.\n\
+You must type the \"=\". VAR may be a debugger \"convenience\" variable\n\
+(names starting with $), a register (a few standard names starting with $),\n\
+or an actual variable in the program being debugged. EXP is any expression.\n\
+This may usually be abbreviated to simply \"set\".",
+ &setlist);
+
+ add_com ("print", class_vars, print_command,
+ concat ("Print value of expression EXP.\n\
+Variables accessible are those of the lexical environment of the selected\n\
+stack frame, plus all those whose scope is global or an entire file.\n\
+\n\
+$NUM gets previous value number NUM. $ and $$ are the last two values.\n\
+$$NUM refers to NUM'th value back from the last one.\n\
+Names starting with $ refer to registers (with the values they would have\n\
+if the program were to return to the stack frame now selected, restoring\n\
+all registers saved by frames farther in) or else to debugger\n\
+\"convenience\" variables (any such name not a known register).\n\
+Use assignment expressions to give values to convenience variables.\n",
+ "\n\
+\{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\
+@@ is a binary operator for treating consecutive data objects\n\
+anywhere in memory as an array. FOO@@NUM gives an array whose first\n\
+element is FOO, whose second element is stored in the space following\n\
+where FOO is stored, etc. FOO must be an expression whose value\n\
+resides in memory.\n",
+ "\n\
+EXP may be preceded with /FMT, where FMT is a format letter\n\
+but no count or size letter (see \"x\" command)."));
+ add_com_alias ("p", "print", class_vars, 1);
+}
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@a191 1
+ int bigendian = 0;
+d196 7
+a202 5
+ {
+ union {
+ char a, b, c, d;
+ long i;
+ } x;
+a203 10
+ x.i = 1;
+ if (x.a)
+ {
+ /* Little endian */
+ tmp = v1;
+ v1 = v2;
+ v2 = tmp;
+ }
+ }
+
+d207 1
+a207 1
+ printf ("0x%08x%08x", v1, v2);
+d238 1
+a238 1
+ printf ("0x%02llx", val_long);
+d241 1
+a241 1
+ printf ("0x%04llx", val_long);
+d245 1
+a245 1
+ printf ("0x%08llx", val_long);
+d248 1
+a248 1
+ printf ("0x%16llx", val_long);
+d257 1
+a257 1
+ printf ("0x%02x", val_long);
+d260 1
+a260 1
+ printf ("0x%04x", val_long);
+d264 1
+a264 1
+ printf ("0x%08x", val_long);
+d267 1
+a267 1
+ printf ("0x%16x", val_long);
+d277 1
+a277 1
+ printf ("%lld", val_long);
+d279 1
+a279 1
+ printf ("%d", val_long);
+d285 1
+a285 1
+ printf ("%llu", val_long);
+d287 1
+a287 1
+ printf ("%u", val_long);
+d294 1
+a294 1
+ printf ("0%llo", val_long);
+d296 1
+a296 1
+ printf ("0%o", val_long);
+d299 1
+a299 1
+ printf ("0");
+d313 1
+a313 1
+ if (len == sizeof (double))
+d315 2
+d318 1
+a318 1
+ if (is_nan (unpack_double (type, valaddr)))
+d320 1
+a320 1
+ printf ("Nan");
+d324 10
+a333 4
+ if (len > 4)
+ printf ("%.16g", unpack_double (type, valaddr));
+ else
+ printf ("%.6g", unpack_double (type, valaddr));
+d515 1
+a515 1
+ printf ("$%d = ", histindex);
+@
diff --git a/gdb/RCS/remote.c,v b/gdb/RCS/remote.c,v
new file mode 100644
index 0000000..213113d
--- /dev/null
+++ b/gdb/RCS/remote.c,v
@@ -0,0 +1,662 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.03.27.20.21.22; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.20.18.45.46; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Avoid <sys/fcntl.h>.
+@
+text
+@/* Memory-access and commands for inferior process, for GDB.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+/* Remote communication protocol.
+ All values are encoded in ascii hex digits.
+
+ Request Packet
+
+ read registers g
+ reply XX....X Each byte of register data
+ is described by two hex digits.
+ Registers are in the internal order
+ for GDB, and the bytes in a register
+ are in the same order the machine uses.
+ or ENN for an error.
+
+ write regs GXX..XX Each byte of register data
+ is described by two hex digits.
+ reply OK for success
+ ENN for an error
+
+ read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
+ reply XX..XX XX..XX is mem contents
+ or ENN NN is errno
+
+ write mem MAA..AA,LLLL:XX..XX
+ AA..AA is address,
+ LLLL is number of bytes,
+ XX..XX is data
+ reply OK for success
+ ENN for an error
+
+ cont cAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ step sAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ There is no immediate reply to step or cont.
+ The reply comes when the machine stops.
+ It is SAA AA is the "signal number"
+
+ kill req k
+*/
+
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+
+#include "wait.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#ifdef HAVE_TERMIO
+#include <termio.h>
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+#else
+#include <sgtty.h>
+#define TERMINAL struct sgttyb
+#endif
+
+int kiodebug;
+
+int icache;
+
+/* Descriptor for I/O to remote machine. */
+int remote_desc;
+
+#define PBUFSIZ 400
+
+static void remote_send ();
+static void putpkt ();
+static void getpkt ();
+static void dcache_flush ();
+
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+void
+remote_open (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ TERMINAL sg;
+
+ remote_debugging = 0;
+ dcache_init ();
+
+ remote_desc = open (name, O_RDWR);
+ if (remote_desc < 0)
+ perror_with_name (name);
+
+ ioctl (remote_desc, TIOCGETP, &sg);
+#ifdef HAVE_TERMIO
+ sg.c_lflag &= ~ICANON;
+#else
+ sg.sg_flags = RAW;
+#endif
+ ioctl (remote_desc, TIOCSETP, &sg);
+
+ if (from_tty)
+ printf ("Remote debugging using %s\n", name);
+ remote_debugging = 1;
+}
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (a)
+ int a;
+{
+ if (a >= '0' && a <= '9')
+ return a - '0';
+ else if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ else
+ error ("Reply contains invalid hex digit");
+}
+
+/* Convert number NIB to a hex digit. */
+
+static int
+tohex (nib)
+ int nib;
+{
+ if (nib < 10)
+ return '0'+nib;
+ else
+ return 'a'+nib-10;
+}
+
+/* Tell the remote machine to resume. */
+
+int
+remote_resume (step, signal)
+ int step, signal;
+{
+ char buf[PBUFSIZ];
+
+ dcache_flush ();
+
+ strcpy (buf, step ? "s": "c");
+
+ putpkt (buf);
+}
+
+/* Wait until the remote machine stops, then return,
+ storing status in STATUS just as `wait' would. */
+
+int
+remote_wait (status)
+ WAITTYPE *status;
+{
+ char buf[PBUFSIZ];
+
+ WSETEXIT ((*status), 0);
+ getpkt (buf);
+ if (buf[0] == 'E')
+ error ("Remote failure reply: %s", buf);
+ if (buf[0] != 'S')
+ error ("Invalid remote reply: %s", buf);
+ WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))));
+}
+
+/* Read the remote registers into the block REGS. */
+
+void
+remote_fetch_registers (regs)
+ char *regs;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ sprintf (buf, "g");
+ remote_send (buf);
+
+ /* Reply describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf;
+ for (i = 0; i < REGISTER_BYTES; i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ error ("Remote reply is too short: %s", buf);
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+}
+
+/* Store the remote registers from the contents of the block REGS. */
+
+void
+remote_store_registers (regs)
+ char *regs;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ buf[0] = 'G';
+
+ /* Command describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf + 1;
+ for (i = 0; i < REGISTER_BYTES; i++)
+ {
+ *p++ = tohex ((regs[i] >> 4) & 0xf);
+ *p++ = tohex (regs[i] & 0xf);
+ }
+
+ remote_send (buf);
+}
+
+/* Read a word from remote address ADDR and return it.
+ This goes through the data cache. */
+
+int
+remote_fetch_word (addr)
+ CORE_ADDR addr;
+{
+ if (icache)
+ {
+ extern CORE_ADDR text_start, text_end;
+
+ if (addr >= text_start && addr < text_end)
+ {
+ int buffer;
+ xfer_core_file (addr, &buffer, sizeof (int));
+ return buffer;
+ }
+ }
+ return dcache_fetch (addr);
+}
+
+/* Write a word WORD into remote address ADDR.
+ This goes through the data cache. */
+
+void
+remote_store_word (addr, word)
+ CORE_ADDR addr;
+ int word;
+{
+ dcache_poke (addr, word);
+}
+
+/* Write memory data directly to the remote machine.
+ This does not inform the data cache; the data cache uses this.
+ MEMADDR is the address in the remote memory space.
+ MYADDR is the address of the buffer in our space.
+ LEN is the number of bytes. */
+
+void
+remote_write_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ if (len > PBUFSIZ / 2 - 20)
+ abort ();
+
+ sprintf (buf, "M%x,%x:", memaddr, len);
+
+ /* Command describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf + strlen (buf);
+ for (i = 0; i < len; i++)
+ {
+ *p++ = tohex ((myaddr[i] >> 4) & 0xf);
+ *p++ = tohex (myaddr[i] & 0xf);
+ }
+
+ remote_send (buf);
+}
+
+/* Read memory data directly from the remote machine.
+ This does not use the data cache; the data cache uses this.
+ MEMADDR is the address in the remote memory space.
+ MYADDR is the address of the buffer in our space.
+ LEN is the number of bytes. */
+
+void
+remote_read_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ if (len > PBUFSIZ / 2 - 1)
+ abort ();
+
+ sprintf (buf, "m%x,%x", memaddr, len);
+ remote_send (buf);
+
+ /* Reply describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf;
+ for (i = 0; i < len; i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ error ("Remote reply is too short: %s", buf);
+ myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+}
+
+/*
+
+A debug packet whose contents are <data>
+is encapsulated for transmission in the form:
+
+ $ <data> # CSUM1 CSUM2
+
+ <data> must be ASCII alphanumeric and cannot include characters
+ '$' or '#'
+
+ CSUM1 and CSUM2 are ascii hex representation of an 8-bit
+ checksum of <data>, the most significant nibble is sent first.
+ the hex digits 0-9,a-f are used.
+
+Receiver responds with:
+
+ + - if CSUM is correct and ready for next packet
+ - - if CSUM is incorrect
+
+*/
+
+/* Send the command in BUF to the remote machine,
+ and read the reply into BUF.
+ Report an error if we get an error reply. */
+
+static void
+remote_send (buf)
+ char *buf;
+{
+ int i;
+ putpkt (buf);
+ getpkt (buf);
+
+ if (buf[0] == 'E')
+ error ("Remote failure reply: %s", buf);
+}
+
+/* Send a packet to the remote machine, with error checking.
+ The data of the packet is in BUF. */
+
+static void
+putpkt (buf)
+ char *buf;
+{
+ int i;
+ char csum = 0;
+ char buf2[500];
+ char buf3[1];
+ int cnt = strlen (buf);
+ char *p;
+
+ if (kiodebug)
+ fprintf (stderr, "Sending packet: %s\n", buf);
+
+ /* Copy the packet into buffer BUF2, encapsulating it
+ and giving it a checksum. */
+
+ p = buf2;
+ *p++ = '$';
+
+ for (i = 0; i < cnt; i++)
+ {
+ csum += buf[i];
+ *p++ = buf[i];
+ }
+ *p++ = '#';
+ *p++ = tohex ((csum >> 4) & 0xf);
+ *p++ = tohex (csum & 0xf);
+
+ /* Send it over and over until we get a positive ack. */
+
+ do {
+ write (remote_desc, buf2, p - buf2);
+ read (remote_desc, buf3, 1);
+ } while (buf3[0] != '+');
+}
+
+static int
+readchar ()
+{
+ char buf[1];
+ while (read (remote_desc, buf, 1) != 1) ;
+ return buf[0] & 0x7f;
+}
+
+/* Read a packet from the remote machine, with error checking,
+ and store it in BUF. */
+
+static void
+getpkt (buf)
+ char *buf;
+{
+ char *bp;
+ unsigned char csum;
+ unsigned int c, c1, c2;
+ extern kiodebug;
+
+ while (1)
+ {
+ /* Force csum to be zero here because of possible error retry. */
+ csum = 0;
+
+ while ((c = readchar()) != '$');
+
+ bp = buf;
+ while (1)
+ {
+ c = readchar ();
+ if (c == '#')
+ break;
+ *bp++ = c;
+ csum += c;
+ }
+ *bp = 0;
+
+ c1 = fromhex (readchar ());
+ c2 = fromhex (readchar ());
+ if (csum == (c1 << 4) + c2)
+ break;
+ printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
+ (c1 << 4) + c2, csum, buf);
+ write (remote_desc, "-", 1);
+ }
+
+ write (remote_desc, "+", 1);
+
+ if (kiodebug)
+ fprintf (stderr,"Packet received :%s\n", buf);
+}
+
+/* The data cache records all the data read from the remote machine
+ since the last time it stopped.
+
+ Each cache block holds 16 bytes of data
+ starting at a multiple-of-16 address. */
+
+#define DCACHE_SIZE 64 /* Number of cache blocks */
+
+struct dcache_block {
+ struct dcache_block *next, *last;
+ unsigned int addr; /* Address for which data is recorded. */
+ int data[4];
+};
+
+struct dcache_block dcache_free, dcache_valid;
+
+/* Free all the data cache blocks, thus discarding all cached data. */
+
+static void
+dcache_flush ()
+{
+ register struct dcache_block *db;
+
+ while ((db = dcache_valid.next) != &dcache_valid)
+ {
+ remque (db);
+ insque (db, &dcache_free);
+ }
+}
+
+/*
+ * If addr is present in the dcache, return the address of the block
+ * containing it.
+ */
+
+struct dcache_block *
+dcache_hit (addr)
+{
+ register struct dcache_block *db;
+
+ if (addr & 3)
+ abort ();
+
+ /* Search all cache blocks for one that is at this address. */
+ db = dcache_valid.next;
+ while (db != &dcache_valid)
+ {
+ if ((addr & 0xfffffff0) == db->addr)
+ return db;
+ db = db->next;
+ }
+ return NULL;
+}
+
+/* Return the int data at address ADDR in dcache block DC. */
+
+int
+dcache_value (db, addr)
+ struct dcache_block *db;
+ unsigned int addr;
+{
+ if (addr & 3)
+ abort ();
+ return (db->data[(addr>>2)&3]);
+}
+
+/* Get a free cache block, put it on the valid list,
+ and return its address. The caller should store into the block
+ the address and data that it describes. */
+
+struct dcache_block *
+dcache_alloc ()
+{
+ register struct dcache_block *db;
+
+ if ((db = dcache_free.next) == &dcache_free)
+ /* If we can't get one from the free list, take last valid */
+ db = dcache_valid.last;
+
+ remque (db);
+ insque (db, &dcache_valid);
+ return (db);
+}
+
+/* Return the contents of the word at address ADDR in the remote machine,
+ using the data cache. */
+
+int
+dcache_fetch (addr)
+ CORE_ADDR addr;
+{
+ register struct dcache_block *db;
+
+ db = dcache_hit (addr);
+ if (db == 0)
+ {
+ db = dcache_alloc ();
+ remote_read_bytes (addr & ~0xf, db->data, 16);
+ db->addr = addr & ~0xf;
+ }
+ return (dcache_value (db, addr));
+}
+
+/* Write the word at ADDR both in the data cache and in the remote machine. */
+
+dcache_poke (addr, data)
+ CORE_ADDR addr;
+ int data;
+{
+ register struct dcache_block *db;
+
+ /* First make sure the word is IN the cache. DB is its cache block. */
+ db = dcache_hit (addr);
+ if (db == 0)
+ {
+ db = dcache_alloc ();
+ remote_read_bytes (addr & ~0xf, db->data, 16);
+ db->addr = addr & ~0xf;
+ }
+
+ /* Modify the word in the cache. */
+ db->data[(addr>>2)&3] = data;
+
+ /* Send the changed word. */
+ remote_write_bytes (addr, &data, 4);
+}
+
+/* Initialize the data cache. */
+
+dcache_init ()
+{
+ register i;
+ register struct dcache_block *db;
+
+ db = (struct dcache_block *) xmalloc (sizeof (struct dcache_block) *
+ DCACHE_SIZE);
+ dcache_free.next = dcache_free.last = &dcache_free;
+ dcache_valid.next = dcache_valid.last = &dcache_valid;
+ for (i=0;i<DCACHE_SIZE;i++,db++)
+ insque (db, &dcache_free);
+}
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d74 1
+a74 1
+#include <sys/fcntl.h>
+@
diff --git a/gdb/RCS/source.c,v b/gdb/RCS/source.c,v
new file mode 100644
index 0000000..f19ff1d
--- /dev/null
+++ b/gdb/RCS/source.c,v
@@ -0,0 +1,990 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.03.27.20.21.45; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.20.18.45.48; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Avoid <sys/fcntl.h>.
+@
+text
+@/* List lines of source files for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "symtab.h"
+#include "param.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+/* Path of directories to search for source files.
+ Same format as the PATH environment variable's value. */
+
+static char *source_path;
+
+/* Symtab of default file for listing lines of. */
+
+struct symtab *current_source_symtab;
+
+/* Default next line to list. */
+
+int current_source_line;
+
+/* Line number of last line printed. Default for various commands.
+ current_source_line is usually, but not always, the same as this. */
+
+static int last_line_listed;
+
+/* First line number listed by last listing command. */
+
+static int first_line_listed;
+
+
+struct symtab *psymtab_to_symtab ();
+
+/* Set the source file default for the "list" command,
+ specifying a symtab. */
+
+void
+select_source_symtab (s)
+ register struct symtab *s;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct partial_symtab *ps, *cs_pst;
+
+ /* Make the default place to list be the function `main'
+ if one exists. */
+ if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0))
+ {
+ sals = decode_line_spec ("main", 1);
+ sal = sals.sals[0];
+ free (sals.sals);
+ current_source_symtab = sal.symtab;
+ current_source_line = sal.line - 9;
+ return;
+ }
+
+ /* If there is no `main', use the last symtab in the list,
+ which is actually the first found in the file's symbol table.
+ But ignore .h files. */
+ if (s)
+ {
+ do
+ {
+ char *name = s->filename;
+ int len = strlen (name);
+ if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
+ current_source_symtab = s;
+ s = s->next;
+ }
+ while (s);
+ current_source_line = 1;
+ }
+ else
+ {
+ ps = partial_symtab_list;
+ while (ps)
+ {
+ char *name = ps->filename;
+ int len = strlen (name);
+ if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
+ cs_pst = ps;
+ ps = ps->next;
+ }
+ if (cs_pst)
+ current_source_symtab = psymtab_to_symtab (cs_pst);
+ else
+ current_source_symtab = 0;
+ current_source_line = 1;
+ }
+}
+
+static void
+directories_info ()
+{
+ printf ("Source directories searched: %s\n", source_path);
+}
+
+void
+init_source_path ()
+{
+ register struct symtab *s;
+
+ source_path = savestring (current_directory, strlen (current_directory));
+
+ /* Forget what we learned about line positions in source files;
+ must check again now since files may be found in
+ a different directory now. */
+ for (s = symtab_list; s; s = s->next)
+ if (s->line_charpos != 0)
+ {
+ free (s->line_charpos);
+ s->line_charpos = 0;
+ }
+}
+
+void
+directory_command (dirname, from_tty)
+ char *dirname;
+ int from_tty;
+{
+ char *old = source_path;
+
+ if (dirname == 0)
+ {
+ if (query ("Reinitialize source path to %s? ", current_directory))
+ {
+ init_source_path ();
+ free (old);
+ }
+ }
+ else
+ {
+ struct stat st;
+ register int len = strlen (dirname);
+ register char *tem;
+ extern char *index ();
+
+ if (index (dirname, ':'))
+ error ("Please add one directory at a time to the source path.");
+ if (dirname[len - 1] == '/')
+ /* Sigh. "foo/" => "foo" */
+ dirname[--len] == '\0';
+
+ while (dirname[len - 1] == '.')
+ {
+ if (len == 1)
+ {
+ /* "." => getwd () */
+ dirname = current_directory;
+ goto append;
+ }
+ else if (dirname[len - 2] == '/')
+ {
+ if (len == 2)
+ {
+ /* "/." => "/" */
+ dirname[--len] = '\0';
+ goto append;
+ }
+ else
+ {
+ /* "...foo/." => "...foo" */
+ dirname[len -= 2] = '\0';
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (dirname[0] != '/')
+ dirname = concat (current_directory, "/", dirname);
+ else
+ dirname = savestring (dirname, len);
+ make_cleanup (free, dirname);
+
+ if (stat (dirname, &st) < 0)
+ perror_with_name (dirname);
+ if ((st.st_mode & S_IFMT) != S_IFDIR)
+ error ("%s is not a directory.", dirname);
+
+ append:
+ len = strlen (dirname);
+ tem = source_path;
+ while (1)
+ {
+ if (!strncmp (tem, dirname, len)
+ && (tem[len] == '\0' || tem[len] == ':'))
+ {
+ printf ("\"%s\" is already in the source path.\n",
+ dirname);
+ break;
+ }
+ tem = index (tem, ':');
+ if (tem)
+ tem++;
+ else
+ {
+ source_path = concat (old, ":", dirname);
+ free (old);
+ break;
+ }
+ }
+ if (from_tty)
+ directories_info ();
+ }
+}
+
+/* Open a file named STRING, searching path PATH (dir names sep by colons)
+ using mode MODE and protection bits PROT in the calls to open.
+ If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
+ (ie pretend the first element of PATH is ".")
+ If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
+ the actual file opened (this string will always start with a "/"
+
+ If a file is found, return the descriptor.
+ Otherwise, return -1, with errno set for the last name we tried to open. */
+
+/* >>>> This should only allow files of certain types,
+ >>>> eg executable, non-directory */
+int
+openp (path, try_cwd_first, string, mode, prot, filename_opened)
+ char *path;
+ int try_cwd_first;
+ char *string;
+ int mode;
+ int prot;
+ char **filename_opened;
+{
+ register int fd;
+ register char *filename;
+ register char *p, *p1;
+ register int len;
+
+ /* ./foo => foo */
+ while (string[0] == '.' && string[1] == '/')
+ string += 2;
+
+ if (try_cwd_first || string[0] == '/')
+ {
+ filename = string;
+ fd = open (filename, mode, prot);
+ if (fd >= 0 || string[0] == '/')
+ goto done;
+ }
+
+ filename = (char *) alloca (strlen (path) + strlen (string) + 2);
+ fd = -1;
+ for (p = path; p; p = p1 ? p1 + 1 : 0)
+ {
+ p1 = (char *) index (p, ':');
+ if (p1)
+ len = p1 - p;
+ else
+ len = strlen (p);
+
+ strncpy (filename, p, len);
+ filename[len] = 0;
+ strcat (filename, "/");
+ strcat (filename, string);
+
+ fd = open (filename, mode, prot);
+ if (fd >= 0) break;
+ }
+
+ done:
+ if (filename_opened)
+ if (fd < 0)
+ *filename_opened = (char *) 0;
+ else if (filename[0] == '/')
+ *filename_opened = savestring (filename, strlen (filename));
+ else
+ {
+ *filename_opened = concat (current_directory, "/", filename);
+ }
+
+ return fd;
+}
+
+/* Create and initialize the table S->line_charpos that records
+ the positions of the lines in the source file, which is assumed
+ to be open on descriptor DESC.
+ All set S->nlines to the number of such lines. */
+
+static void
+find_source_lines (s, desc)
+ struct symtab *s;
+ int desc;
+{
+ struct stat st;
+ register char *data, *p, *end;
+ int nlines = 0;
+ int lines_allocated = 1000;
+ int *line_charpos = (int *) xmalloc (lines_allocated * sizeof (int));
+ extern int exec_mtime;
+
+ fstat (desc, &st);
+ if (get_exec_file (0) != 0 && exec_mtime < st.st_mtime)
+ printf ("Source file is more recent than executable.\n");
+
+ data = (char *) alloca (st.st_size);
+ myread (desc, data, st.st_size);
+ end = data + st.st_size;
+ p = data;
+ line_charpos[0] = 0;
+ nlines = 1;
+ while (p != end)
+ {
+ if (*p++ == '\n'
+ /* A newline at the end does not start a new line. */
+ && p != end)
+ {
+ if (nlines == lines_allocated)
+ {
+ lines_allocated *= 2;
+ line_charpos = (int *) xrealloc (line_charpos,
+ sizeof (int) * lines_allocated);
+ }
+ line_charpos[nlines++] = p - data;
+ }
+ }
+ s->nlines = nlines;
+ s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int));
+}
+
+/* Return the character position of a line LINE in symtab S.
+ Return 0 if anything is invalid. */
+
+int
+source_line_charpos (s, line)
+ struct symtab *s;
+ int line;
+{
+ if (!s) return 0;
+ if (!s->line_charpos || line <= 0) return 0;
+ if (line > s->nlines)
+ line = s->nlines;
+ return s->line_charpos[line - 1];
+}
+
+/* Return the line number of character position POS in symtab S. */
+
+int
+source_charpos_line (s, chr)
+ register struct symtab *s;
+ register int chr;
+{
+ register int line = 0;
+ register int *lnp;
+
+ if (s == 0 || s->line_charpos == 0) return 0;
+ lnp = s->line_charpos;
+ /* Files are usually short, so sequential search is Ok */
+ while (line < s->nlines && *lnp <= chr)
+ {
+ line++;
+ lnp++;
+ }
+ if (line >= s->nlines)
+ line = s->nlines;
+ return line;
+}
+
+/* Get full pathname and line number positions for a symtab.
+ Return nonzero if line numbers may have changed.
+ Set *FULLNAME to actual name of the file as found by `openp',
+ or to 0 if the file is not found. */
+
+int
+get_filename_and_charpos (s, line, fullname)
+ struct symtab *s;
+ int line;
+ char **fullname;
+{
+ register int desc, linenums_changed = 0;
+
+ desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
+ if (desc < 0)
+ {
+ if (fullname)
+ *fullname = NULL;
+ return 0;
+ }
+ if (fullname)
+ *fullname = s->fullname;
+ if (s->line_charpos == 0) linenums_changed = 1;
+ if (linenums_changed) find_source_lines (s, desc);
+ close (desc);
+ return linenums_changed;
+}
+
+/* Print text describing the full name of the source file S
+ and the line number LINE and its corresponding character position.
+ The text starts with two Ctrl-z so that the Emacs-GDB interface
+ can easily find it.
+
+ MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
+
+ Return 1 if successful, 0 if could not find the file. */
+
+int
+identify_source_line (s, line, mid_statement)
+ struct symtab *s;
+ int line;
+ int mid_statement;
+{
+ if (s->line_charpos == 0)
+ get_filename_and_charpos (s, line, 0);
+ if (s->fullname == 0)
+ return 0;
+ printf ("\032\032%s:%d:%d:%s\n", s->fullname,
+ line, s->line_charpos[line - 1],
+ mid_statement ? "middle" : "beg");
+ current_source_line = line;
+ first_line_listed = line;
+ last_line_listed = line;
+ current_source_symtab = s;
+ return 1;
+}
+
+/* Print source lines from the file of symtab S,
+ starting with line number LINE and stopping before line number STOPLINE. */
+
+void
+print_source_lines (s, line, stopline, noerror)
+ struct symtab *s;
+ int line, stopline;
+ int noerror;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int nlines = stopline - line;
+
+ desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
+ if (desc < 0)
+ {
+ extern int errno;
+ if (! noerror)
+ perror_with_name (s->filename);
+ print_sys_errmsg (s->filename, errno);
+ return;
+ }
+
+ if (s->line_charpos == 0)
+ find_source_lines (s, desc);
+
+ if (line < 1 || line > s->nlines)
+ {
+ close (desc);
+ error ("Line number out of range; %s has %d lines.",
+ s->filename, s->nlines);
+ }
+
+ if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (s->filename);
+ }
+
+ current_source_symtab = s;
+ current_source_line = line;
+ first_line_listed = line;
+
+ stream = fdopen (desc, "r");
+ clearerr (stream);
+
+ while (nlines-- > 0)
+ {
+ c = fgetc (stream);
+ if (c == EOF) break;
+ last_line_listed = current_source_line;
+ printf ("%d\t", current_source_line++);
+ do
+ {
+ if (c < 040 && c != '\t' && c != '\n')
+ {
+ fputc ('^', stdout);
+ fputc (c + 0100, stdout);
+ }
+ else if (c == 0177)
+ printf ("^?");
+ else
+ fputc (c, stdout);
+ } while (c != '\n' && (c = fgetc (stream)) >= 0);
+ }
+
+ fclose (stream);
+}
+
+
+
+/*
+ C++
+ Print a list of files and line numbers which a user may choose from
+ in order to list a function which was specified ambiguously
+ (as with `list classname::overloadedfuncname', for example).
+ The vector in SALS provides the filenames and line numbers.
+ */
+static void
+ambiguous_line_spec (sals)
+ struct symtabs_and_lines *sals;
+{
+ int i;
+
+ for (i = 0; i < sals->nelts; ++i)
+ printf("file: \"%s\", line number: %d\n",
+ sals->sals[i].symtab->filename, sals->sals[i].line);
+}
+
+
+static void
+list_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals, sals_end;
+ struct symtab_and_line sal, sal_end;
+ struct symbol *sym;
+ char *arg1;
+ int no_end = 1;
+ int dummy_end = 0;
+ int dummy_beg = 0;
+ int linenum_beg = 0;
+ char *p;
+
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ error ("Listing source lines requires symbols.");
+
+ /* Pull in a current source symtab if necessary */
+ if (current_source_symtab == 0 &&
+ (arg == 0 || arg[0] == '+' || arg[0] == '-'))
+ select_source_symtab (symtab_list);
+
+ /* "l" or "l +" lists next ten lines. */
+
+ if (arg == 0 || !strcmp (arg, "+"))
+ {
+ if (current_source_symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ print_source_lines (current_source_symtab, current_source_line,
+ current_source_line + 10, 0);
+ return;
+ }
+
+ /* "l -" lists previous ten lines, the ones before the ten just listed. */
+ if (!strcmp (arg, "-"))
+ {
+ if (current_source_symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ print_source_lines (current_source_symtab,
+ max (first_line_listed - 10, 1),
+ first_line_listed, 0);
+ return;
+ }
+
+ /* Now if there is only one argument, decode it in SAL
+ and set NO_END.
+ If there are two arguments, decode them in SAL and SAL_END
+ and clear NO_END; however, if one of the arguments is blank,
+ set DUMMY_BEG or DUMMY_END to record that fact. */
+
+ arg1 = arg;
+ if (*arg1 == ',')
+ dummy_beg = 1;
+ else
+ {
+ sals = decode_line_1 (&arg1, 0, 0, 0);
+
+ if (! sals.nelts) return; /* C++ */
+ if (sals.nelts > 1)
+ {
+ ambiguous_line_spec (&sals);
+ free (sals.sals);
+ return;
+ }
+
+ sal = sals.sals[0];
+ free (sals.sals);
+ }
+
+ /* Record whether the BEG arg is all digits. */
+
+ for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
+ linenum_beg = (p == arg1);
+
+ while (*arg1 == ' ' || *arg1 == '\t')
+ arg1++;
+ if (*arg1 == ',')
+ {
+ no_end = 0;
+ arg1++;
+ while (*arg1 == ' ' || *arg1 == '\t')
+ arg1++;
+ if (*arg1 == 0)
+ dummy_end = 1;
+ else
+ {
+ if (dummy_beg)
+ sals_end = decode_line_1 (&arg1, 0, 0, 0);
+ else
+ sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
+ if (sals_end.nelts == 0)
+ return;
+ if (sals_end.nelts > 1)
+ {
+ ambiguous_line_spec (&sals_end);
+ free (sals_end.sals);
+ return;
+ }
+ sal_end = sals_end.sals[0];
+ free (sals_end.sals);
+ }
+ }
+
+ if (*arg1)
+ error ("Junk at end of line specification.");
+
+ if (!no_end && !dummy_beg && !dummy_end
+ && sal.symtab != sal_end.symtab)
+ error ("Specified start and end are in different files.");
+ if (dummy_beg && dummy_end)
+ error ("Two empty args do not say what lines to list.");
+
+ /* if line was specified by address,
+ first print exactly which line, and which file.
+ In this case, sal.symtab == 0 means address is outside
+ of all known source files, not that user failed to give a filename. */
+ if (*arg == '*')
+ {
+ if (sal.symtab == 0)
+ error ("No source file for address 0x%x.", sal.pc);
+ sym = find_pc_function (sal.pc);
+ if (sym)
+ printf ("0x%x is in %s (%s, line %d).\n",
+ sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
+ else
+ printf ("0x%x is in %s, line %d.\n",
+ sal.pc, sal.symtab->filename, sal.line);
+ }
+
+ /* If line was not specified by just a line number,
+ and it does not imply a symtab, it must be an undebuggable symbol
+ which means no source code. */
+
+ if (! linenum_beg && sal.symtab == 0)
+ error ("No line number known for %s.", arg);
+
+ /* If this command is repeated with RET,
+ turn it into the no-arg variant. */
+
+ if (from_tty)
+ *arg = 0;
+
+ if (dummy_beg && sal_end.symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ if (dummy_beg)
+ print_source_lines (sal_end.symtab, max (sal_end.line - 9, 1),
+ sal_end.line + 1, 0);
+ else if (sal.symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+ else if (no_end)
+ print_source_lines (sal.symtab, max (sal.line - 5, 1), sal.line + 5, 0);
+ else
+ print_source_lines (sal.symtab, sal.line,
+ dummy_end ? sal.line + 10 : sal_end.line + 1,
+ 0);
+}
+
+/* Print info on range of pc's in a specified line. */
+
+static void
+line_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ int start_pc, end_pc;
+ int i;
+
+ if (arg == 0)
+ {
+ sal.symtab = current_source_symtab;
+ sal.line = last_line_listed;
+ sals.nelts = 1;
+ sals.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ sals.sals[0] = sal;
+ }
+ else
+ {
+ sals = decode_line_spec_1 (arg, 0);
+
+ /* If this command is repeated with RET,
+ turn it into the no-arg variant. */
+ if (from_tty)
+ *arg = 0;
+ }
+
+ /* C++ More than one line may have been specified, as when the user
+ specifies an overloaded function name. Print info on them all. */
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ if (sal.symtab == 0)
+ error ("No source file specified.");
+
+ if (sal.line > 0
+ && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
+ {
+ if (start_pc == end_pc)
+ printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
+ sal.line, sal.symtab->filename, start_pc);
+ else
+ printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
+ sal.line, sal.symtab->filename, start_pc, end_pc);
+ /* x/i should display this line's code. */
+ set_next_address (start_pc);
+ /* Repeating "info line" should do the following line. */
+ last_line_listed = sal.line + 1;
+ }
+ else
+ printf ("Line number %d is out of range for \"%s\".\n",
+ sal.line, sal.symtab->filename);
+ }
+}
+
+/* Commands to search the source file for a regexp. */
+
+static void
+forward_search_command (regex, from_tty)
+ char *regex;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int line = last_line_listed + 1;
+ char *msg;
+
+ msg = (char *) re_comp (regex);
+ if (msg)
+ error (msg);
+
+ if (current_source_symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+
+ /* Search from last_line_listed+1 in current_source_symtab */
+
+ desc = openp (source_path, 0, current_source_symtab->filename,
+ O_RDONLY, 0, &current_source_symtab->fullname);
+ if (desc < 0)
+ perror_with_name (current_source_symtab->filename);
+
+ if (current_source_symtab->line_charpos == 0)
+ find_source_lines (current_source_symtab, desc);
+
+ if (line < 1 || line > current_source_symtab->nlines)
+ {
+ close (desc);
+ error ("Expression not found");
+ }
+
+ if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (current_source_symtab->filename);
+ }
+
+ stream = fdopen (desc, "r");
+ clearerr (stream);
+ while (1) {
+ char buf[4096]; /* Should be reasonable??? */
+ register char *p = buf;
+
+ c = fgetc (stream);
+ if (c == EOF)
+ break;
+ do {
+ *p++ = c;
+ } while (c != '\n' && (c = fgetc (stream)) >= 0);
+
+ /* we now have a source line in buf, null terminate and match */
+ *p = 0;
+ if (re_exec (buf) > 0)
+ {
+ /* Match! */
+ fclose (stream);
+ print_source_lines (current_source_symtab,
+ line, line+1, 0);
+ current_source_line = max (line - 5, 1);
+ return;
+ }
+ line++;
+ }
+
+ printf ("Expression not found\n");
+ fclose (stream);
+}
+
+static void
+reverse_search_command (regex, from_tty)
+ char *regex;
+{
+ register int c;
+ register int desc;
+ register FILE *stream;
+ int line = last_line_listed - 1;
+ char *msg;
+
+ msg = (char *) re_comp (regex);
+ if (msg)
+ error (msg);
+
+ if (current_source_symtab == 0)
+ error ("No default source file yet. Do \"help list\".");
+
+ /* Search from last_line_listed-1 in current_source_symtab */
+
+ desc = openp (source_path, 0, current_source_symtab->filename,
+ O_RDONLY, 0, &current_source_symtab->fullname);
+ if (desc < 0)
+ perror_with_name (current_source_symtab->filename);
+
+ if (current_source_symtab->line_charpos == 0)
+ find_source_lines (current_source_symtab, desc);
+
+ if (line < 1 || line > current_source_symtab->nlines)
+ {
+ close (desc);
+ error ("Expression not found");
+ }
+
+ if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ close (desc);
+ perror_with_name (current_source_symtab->filename);
+ }
+
+ stream = fdopen (desc, "r");
+ clearerr (stream);
+ while (1)
+ {
+ char buf[4096]; /* Should be reasonable??? */
+ register char *p = buf;
+
+ c = fgetc (stream);
+ if (c == EOF)
+ break;
+ do {
+ *p++ = c;
+ } while (c != '\n' && (c = fgetc (stream)) >= 0);
+
+ /* We now have a source line in buf; null terminate and match. */
+ *p = 0;
+ if (re_exec (buf) > 0)
+ {
+ /* Match! */
+ fclose (stream);
+ print_source_lines (current_source_symtab,
+ line, line+1, 0);
+ current_source_line = max (line - 5, 1);
+ return;
+ }
+ line--;
+ if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ fclose (stream);
+ perror_with_name (current_source_symtab->filename);
+ }
+ }
+
+ printf ("Expression not found\n");
+ fclose (stream);
+ return;
+}
+
+void
+_initialize_source ()
+{
+ current_source_symtab = 0;
+ init_source_path ();
+
+ add_com ("directory", class_files, directory_command,
+ "Add directory DIR to end of search path for source files.\n\
+With no argument, reset the search path to just the working directory\n\
+and forget cached info on line positions in source files.");
+
+ add_info ("directories", directories_info,
+ "Current search path for finding source files.");
+
+ add_info ("line", line_info,
+ "Core addresses of the code for a source line.\n\
+Line can be specified as\n\
+ LINENUM, to list around that line in current file,\n\
+ FILE:LINENUM, to list around that line in that file,\n\
+ FUNCTION, to list around beginning of that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+Default is to describe the last source line that was listed.\n\n\
+This sets the default address for \"x\" to the line's first instruction\n\
+so that \"x/i\" suffices to start examining the machine code.\n\
+The address is also stored as the value of \"$_\".");
+
+ add_com ("forward-search", class_files, forward_search_command,
+ "Search for regular expression (see regex(3)) from last line listed.");
+ add_com_alias ("search", "forward-search", class_files, 0);
+
+ add_com ("reverse-search", class_files, reverse_search_command,
+ "Search backward for regular expression (see regex(3)) from last line listed.");
+
+ add_com ("list", class_files, list_command,
+ "List specified function or line.\n\
+With no argument, lists ten more lines after or around previous listing.\n\
+\"list -\" lists the ten lines before a previous ten-line listing.\n\
+One argument specifies a line, and ten lines are listed around that line.\n\
+Two arguments with comma between specify starting and ending lines to list.\n\
+Lines can be specified in these ways:\n\
+ LINENUM, to list around that line in current file,\n\
+ FILE:LINENUM, to list around that line in that file,\n\
+ FUNCTION, to list around beginning of that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+ *ADDRESS, to list around the line containing that address.\n\
+With two args if one is empty it stands for ten lines away from the other arg.");
+}
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d27 1
+a27 1
+#include <sys/fcntl.h>
+@
diff --git a/gdb/RCS/sparc-dep.c,v b/gdb/RCS/sparc-dep.c,v
new file mode 100644
index 0000000..8178e00
--- /dev/null
+++ b/gdb/RCS/sparc-dep.c,v
@@ -0,0 +1,1091 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.3
+date 89.04.04.21.31.02; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.02.10.01.47.27; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.10.01.46.36; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@Fix handling of annulled branches in single step. "b foo; bcc,a bar"
+annuls the instruction at foo, not just after the bcc,a. Also,
+handle CBcc (coprocessor) annulled branch, and improve doc.
+@
+text
+@/* Machine-dependent code which would otherwise be in inflow.c and core.c,
+ for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+ This code is for the sparc cpu.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "obstack.h"
+#include "sparc-opcode.h"
+#include "gdbcore.h"
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+#include <a.out.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/core.h>
+
+extern int errno;
+extern int attach_flag;
+
+/* This function simply calls ptrace with the given arguments.
+ It exists so that all calls to ptrace are isolated in this
+ machine-dependent file. */
+int
+call_ptrace (request, pid, arg3, arg4)
+ int request, pid, arg3, arg4;
+{
+ return ptrace (request, pid, arg3, arg4);
+}
+
+void
+kill_inferior ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+ inferior_died ();
+}
+
+/* This is used when GDB is exiting. It gives less chance of error.*/
+
+void
+kill_inferior_fast ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+}
+
+/* Simulate single-step ptrace call for sun4. Code written by Gary
+ Beihl (beihl@@mcc.com). */
+
+/*
+ * Duplicated from breakpoint.c because (at least for now) this is a
+ * machine dependent routine.
+ */
+static char break_insn[] = BREAKPOINT;
+
+/* From infrun.c */
+extern int stop_after_trap, stop_after_attach;
+
+static CORE_ADDR next_pc, npc4, target;
+static int brknpc4, brktrg;
+typedef char binsn_quantum[sizeof break_insn];
+static binsn_quantum break_mem[3];
+
+/* Non-zero if we just simulated a single-step ptrace call. This is
+ needed because we cannot remove the breakpoints in the inferior
+ process until after the `wait' in `wait_for_inferior'. Used for
+ sun4. */
+
+int one_stepped;
+
+void
+single_step (signal)
+ int signal;
+{
+ branch_type br, isannulled();
+ CORE_ADDR pc;
+
+ next_pc = read_register (NPC_REGNUM);
+ npc4 = next_pc + 4; /* branch not taken */
+
+ if (!one_stepped)
+ {
+ /* Always set breakpoint for NPC. */
+ read_memory (next_pc, break_mem[0], sizeof break_insn);
+ write_memory (next_pc, break_insn, sizeof break_insn);
+ /* printf ("set break at %x\n",next_pc); */
+
+ pc = read_register (PC_REGNUM);
+ br = isannulled (pc, &target);
+ brknpc4 = brktrg = 0;
+
+ if (br == bicca)
+ {
+ /* Conditional annulled branch will either end up at
+ npc (if taken) or at npc+4 (if not taken). Trap npc+4. */
+ brknpc4 = 1;
+ read_memory (npc4, break_mem[1], sizeof break_insn);
+ write_memory (npc4, break_insn, sizeof break_insn);
+ }
+ else if (br == baa && target != next_pc)
+ {
+ /* Unconditional annulled branch will always end up at
+ the target. */
+ brktrg = 1;
+ read_memory (target, break_mem[2], sizeof break_insn);
+ write_memory (target, break_insn, sizeof break_insn);
+ }
+
+ /* Let it go */
+ ptrace (7, inferior_pid, 1, signal);
+ one_stepped = 1;
+ return;
+ }
+ else
+ {
+ /* Remove breakpoints */
+ write_memory (next_pc, break_mem[0], sizeof break_insn);
+
+ if (brknpc4)
+ {
+ write_memory (npc4, break_mem[1], sizeof break_insn);
+ }
+ if (brktrg)
+ {
+ write_memory (target, break_mem[2], sizeof break_insn);
+ }
+ one_stepped = 0;
+ }
+}
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+resume (step, signal)
+ int step;
+ int signal;
+{
+ errno = 0;
+ if (remote_debugging)
+ remote_resume (step, signal);
+ else
+ {
+ /* Sparc doesn't have single step on ptrace */
+ if (step)
+ single_step (signal);
+ else
+ ptrace (7, inferior_pid, 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+ }
+}
+
+#ifdef ATTACH_DETACH
+
+/* Start debugging the process whose number is PID. */
+
+int
+attach (pid)
+ int pid;
+{
+ errno = 0;
+ ptrace (PTRACE_ATTACH, pid, 0, 0);
+ if (errno)
+ perror_with_name ("ptrace");
+ attach_flag = 1;
+ return pid;
+}
+
+/* Stop debugging the process whose number is PID
+ and continue it with signal number SIGNAL.
+ SIGNAL = 0 means just continue it. */
+
+void
+detach (signal)
+ int signal;
+{
+ errno = 0;
+ ptrace (PTRACE_DETACH, inferior_pid, 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+ attach_flag = 0;
+}
+#endif /* ATTACH_DETACH */
+
+void
+fetch_inferior_registers ()
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+ extern char registers[];
+ int cwp;
+ struct rwindow local_and_ins;
+
+ if (remote_debugging)
+ remote_fetch_registers (registers);
+ else
+ {
+ ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers);
+ ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers);
+
+ registers[REGISTER_BYTE (0)] = 0;
+ bcopy (&inferior_registers.r_g1, &registers[REGISTER_BYTE (1)], 15 * 4);
+ bcopy (&inferior_fp_registers, &registers[REGISTER_BYTE (FP0_REGNUM)],
+ sizeof inferior_fp_registers.fpu_fr);
+ *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
+ *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
+ *(int *)&registers[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc;
+ *(int *)&registers[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y;
+/* *(int *)&registers[REGISTER_BYTE (RP_REGNUM)] =
+ inferior_registers.r_o7 + 8;
+ bcopy (&inferior_fp_registers.Fpu_fsr,
+ &registers[REGISTER_BYTE (FPS_REGNUM)],
+ sizeof (FPU_FSR_TYPE)); */
+
+ read_inferior_memory (inferior_registers.r_sp,
+ &registers[REGISTER_BYTE (16)],
+ 16*4);
+ }
+}
+
+/* Store our register values back into the inferior.
+ If REGNO is -1, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+
+void
+store_inferior_registers (regno)
+ int regno;
+{
+ struct regs inferior_registers;
+ struct fp_status inferior_fp_registers;
+ extern char registers[];
+
+ if (remote_debugging)
+ remote_store_registers (registers);
+ else
+ {
+ int in_regs = 1, in_fpregs = 1, in_fparegs, in_cpregs = 1;
+
+ if (regno >= 0)
+ if (FP0_REGNUM <= regno && regno <= FP0_REGNUM + 32)
+ in_regs = 0;
+ else
+ in_fpregs = 0;
+
+ if (in_regs)
+ {
+ bcopy (&registers[REGISTER_BYTE (1)],
+ &inferior_registers.r_g1, 15 * 4);
+
+ inferior_registers.r_ps =
+ *(int *)&registers[REGISTER_BYTE (PS_REGNUM)];
+ inferior_registers.r_pc =
+ *(int *)&registers[REGISTER_BYTE (PC_REGNUM)];
+ inferior_registers.r_npc =
+ *(int *)&registers[REGISTER_BYTE (NPC_REGNUM)];
+ inferior_registers.r_y =
+ *(int *)&registers[REGISTER_BYTE (Y_REGNUM)];
+
+ write_inferior_memory (*(int *)&registers[REGISTER_BYTE (SP_REGNUM)],
+ &registers[REGISTER_BYTE (16)],
+ 16*4);
+ }
+ if (in_fpregs)
+ {
+ bcopy (&registers[REGISTER_BYTE (FP0_REGNUM)],
+ &inferior_fp_registers,
+ sizeof inferior_fp_registers.fpu_fr);
+
+ /* bcopy (&registers[REGISTER_BYTE (FPS_REGNUM)],
+ &inferior_fp_registers.Fpu_fsr,
+ sizeof (FPU_FSR_TYPE));
+ ****/
+ }
+
+ if (in_regs)
+ ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers);
+ if (in_fpregs)
+ ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers);
+ }
+}
+
+/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
+ in the NEW_SUN_PTRACE case.
+ It ought to be straightforward. But it appears that writing did
+ not write the data that I specified. I cannot understand where
+ it got the data that it actually did write. */
+
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+ to debugger memory starting at MYADDR.
+ On failure (cannot read from inferior, usually because address is out
+ of bounds) returns the value of errno. */
+
+int
+read_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca (count * sizeof (int));
+ extern int errno;
+
+ /* Read all the longwords */
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ if (remote_debugging)
+ buffer[i] = remote_fetch_word (addr);
+ else
+ buffer[i] = ptrace (1, inferior_pid, addr, 0);
+ if (errno)
+ return errno;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+ return 0;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+ to inferior's memory at MEMADDR.
+ On failure (cannot write the inferior)
+ returns the value of errno. */
+
+int
+write_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca (count * sizeof (int));
+ extern int errno;
+
+ /* Fill start and end extra bytes of buffer with existing memory data. */
+
+ if (remote_debugging)
+ buffer[0] = remote_fetch_word (addr);
+ else
+ buffer[0] = ptrace (1, inferior_pid, addr, 0);
+
+ if (count > 1)
+ {
+ if (remote_debugging)
+ buffer[count - 1]
+ = remote_fetch_word (addr + (count - 1) * sizeof (int));
+ else
+ buffer[count - 1]
+ = ptrace (1, inferior_pid,
+ addr + (count - 1) * sizeof (int), 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ if (remote_debugging)
+ remote_store_word (addr, buffer[i]);
+ else
+ ptrace (4, inferior_pid, addr, buffer[i]);
+ if (errno)
+ return errno;
+ }
+
+ return 0;
+}
+
+
+/* Machine-dependent code which would otherwise be in core.c */
+/* Work with core dump and executable files, for GDB. */
+
+/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
+#ifdef AOUTHDR
+#define COFF_FORMAT
+#endif
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(hdr) 0
+#endif /* no N_TXTADDR */
+
+#ifndef N_DATADDR
+#define N_DATADDR(hdr) hdr.a_text
+#endif /* no N_DATADDR */
+
+/* Make COFF and non-COFF names for things a little more compatible
+ to reduce conditionals later. */
+
+#ifdef COFF_FORMAT
+#define a_magic magic
+#endif
+
+#ifndef COFF_FORMAT
+#define AOUTHDR struct exec
+#endif
+
+extern char *sys_siglist[];
+
+/* Hook for `exec_file_command' command to call. */
+
+extern void (*exec_file_display_hook) ();
+
+#ifdef COFF_FORMAT
+/* various coff data structures */
+
+extern FILHDR file_hdr;
+extern SCNHDR text_hdr;
+extern SCNHDR data_hdr;
+
+#endif /* not COFF_FORMAT */
+
+/* a.out header saved in core file. */
+
+extern AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+extern AOUTHDR exec_aouthdr;
+
+extern void validate_files ();
+
+void
+core_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+ extern char registers[];
+
+ /* Discard all vestiges of any previous core file
+ and mark data and stack spaces as empty. */
+
+ if (corefile)
+ free (corefile);
+ corefile = 0;
+
+ if (corechan >= 0)
+ close (corechan);
+ corechan = -1;
+
+ data_start = 0;
+ data_end = 0;
+ stack_start = STACK_END_ADDR;
+ stack_end = STACK_END_ADDR;
+
+ /* Now, if a new core file was specified, open it and digest it. */
+
+ if (filename)
+ {
+ if (have_inferior_p ())
+ error ("To look at a core file, you must kill the inferior with \"kill\".");
+ corechan = open (filename, O_RDONLY, 0);
+ if (corechan < 0)
+ perror_with_name (filename);
+
+ {
+ struct core corestr;
+
+ val = myread (corechan, &corestr, sizeof corestr);
+ if (val < 0)
+ perror_with_name (filename);
+ if (corestr.c_magic != CORE_MAGIC)
+ error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)",
+ filename, corestr.c_magic, (int) CORE_MAGIC);
+ else if (sizeof (struct core) != corestr.c_len)
+ error ("\"%s\" has an invalid struct core length (%d, expected %d)",
+ filename, corestr.c_len, (int) sizeof (struct core));
+
+ /* Note that data_start and data_end don't depend on the exec file */
+ data_start = N_DATADDR (corestr.c_aouthdr);
+ data_end = data_start + corestr.c_dsize;
+ stack_start = stack_end - corestr.c_ssize;
+ data_offset = sizeof corestr;
+ stack_offset = sizeof corestr + corestr.c_dsize;
+
+ /* G0 *always* holds 0. */
+ *(int *)&registers[REGISTER_BYTE (0)] = 0;
+ /* The globals and output registers. */
+
+ bcopy (&corestr.c_regs.r_g1, ((int *) registers) + 1, 15 * 4);
+ *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps;
+ *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc;
+ *(int *)&registers[REGISTER_BYTE (NPC_REGNUM)] = corestr.c_regs.r_npc;
+ *(int *)&registers[REGISTER_BYTE (Y_REGNUM)] = corestr.c_regs.r_y;
+
+ /* My best guess at where to get the locals and input
+ registers is exactly where they usually are, right above
+ the stack pointer. If the core dump was caused by a bus
+ writing off the stack pointer (as is possible) then this
+ won't work, but it's worth the try. */
+ {
+ int sp;
+
+ sp = *(int *)&registers[REGISTER_BYTE (SP_REGNUM)];
+ lseek (corechan, sp - stack_start + stack_offset, L_SET);
+ if (16 * 4 != myread (corechan,
+ &registers[REGISTER_BYTE (16)],
+ 16 * 4))
+ /* fprintf so user can still use gdb */
+ fprintf (stderr, "Couldn't read input and local registers from core file\n");
+ }
+
+ bcopy (corestr.c_fpu.fpu_regs,
+ &registers[REGISTER_BYTE (FP0_REGNUM)],
+ sizeof corestr.c_fpu.fpu_regs);
+#ifdef FPU
+ bcopy (&corestr.c_fpu.fpu_fsr,
+ &registers[REGISTER_BYTE (FPS_REGNUM)],
+ sizeof (FPU_FSR_TYPE));
+#endif
+
+ bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec));
+
+ printf ("Core file is from \"%s\".\n", corestr.c_cmdname);
+ if (corestr.c_signo > 0)
+ printf ("Program terminated with signal %d, %s.\n",
+ corestr.c_signo,
+ corestr.c_signo < NSIG
+ ? sys_siglist[corestr.c_signo]
+ : "(undocumented)");
+ }
+ if (filename[0] == '/')
+ corefile = savestring (filename, strlen (filename));
+ else
+ {
+ corefile = concat (current_directory, "/", filename);
+ }
+
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+ select_frame (get_current_frame (), 0);
+ validate_files ();
+ }
+ else if (from_tty)
+ printf ("No core file now.\n");
+}
+
+void
+exec_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+
+ /* Eliminate all traces of old exec file.
+ Mark text segment as empty. */
+
+ if (execfile)
+ free (execfile);
+ execfile = 0;
+ text_start = 0;
+ text_end = 0;
+ exec_data_start = 0;
+ exec_data_end = 0;
+ if (execchan >= 0)
+ close (execchan);
+ execchan = -1;
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (filename)
+ {
+ execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
+ &execfile);
+ if (execchan < 0)
+ perror_with_name (filename);
+
+#ifdef COFF_FORMAT
+ {
+ int aout_hdrsize;
+ int num_sections;
+
+ if (read_file_hdr (execchan, &file_hdr) < 0)
+ error ("\"%s\": not in executable format.", execfile);
+
+ aout_hdrsize = file_hdr.f_opthdr;
+ num_sections = file_hdr.f_nscns;
+
+ if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
+ error ("\"%s\": can't read optional aouthdr", execfile);
+
+ if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
+ error ("\"%s\": can't read text section header", execfile);
+
+ if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
+ error ("\"%s\": can't read data section header", execfile);
+
+ text_start = exec_aouthdr.text_start;
+ text_end = text_start + exec_aouthdr.tsize;
+ text_offset = text_hdr.s_scnptr;
+ exec_data_start = exec_aouthdr.data_start;
+ exec_data_end = exec_data_start + exec_aouthdr.dsize;
+ exec_data_offset = data_hdr.s_scnptr;
+ exec_mtime = file_hdr.f_timdat;
+ }
+#else /* not COFF_FORMAT */
+ {
+ struct stat st_exec;
+ val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
+
+ if (val < 0)
+ perror_with_name (filename);
+
+ text_start = N_TXTADDR (exec_aouthdr);
+ exec_data_start = N_DATADDR (exec_aouthdr);
+ text_offset = N_TXTOFF (exec_aouthdr);
+ exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
+
+ text_end = text_start + exec_aouthdr.a_text;
+ exec_data_end = exec_data_start + exec_aouthdr.a_data;
+
+ fstat (execchan, &st_exec);
+ exec_mtime = st_exec.st_mtime;
+ }
+#endif /* not COFF_FORMAT */
+
+ validate_files ();
+ }
+ else if (from_tty)
+ printf ("No exec file now.\n");
+
+ /* Tell display code (if any) about the changed file name. */
+ if (exec_file_display_hook)
+ (*exec_file_display_hook) (filename);
+}
+
+/*
+ * Find the pc saved in frame FRAME.
+ */
+CORE_ADDR
+frame_saved_pc (frame)
+ FRAME frame;
+{
+ CORE_ADDR prev_pc;
+
+ /* If it's at the bottom, the return value's stored in i7/rp */
+ if (get_current_frame () == frame)
+ prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]);
+ else
+ /* Wouldn't this always work? This would allow this routine to
+ be completely a macro. */
+ prev_pc = GET_RWINDOW_REG (frame->bottom, rw_in[7]);
+
+ return PC_ADJUST (prev_pc);
+}
+
+/*
+ * Since an individual frame in the frame cache is defined by two
+ * arguments (a frame pointer and a stack pointer), we need two
+ * arguments to get info for an arbitrary stack frame. This routine
+ * takes two arguments and makes the cached frames look as if these
+ * two arguments defined a frame on the cache. This allows the rest
+ * of info frame to extract the important arguments without
+ * difficulty.
+ */
+FRAME
+setup_arbitrary_frame (frame, stack)
+ FRAME_ADDR frame, stack;
+{
+ struct frame_info *fci;
+ FRAME fid = create_new_frame (frame, 0);
+
+ if (!fid)
+ fatal ("internal: create_new_frame returned invalid frame id");
+
+ fid->bottom = stack;
+
+ return fid;
+}
+
+/* This code was written by Gary Beihl (beihl@@mcc.com).
+ It was modified by Michael Tiemann (tiemann@@corto.inria.fr). */
+
+struct command_line *get_breakpoint_commands ();
+
+/*
+ * This routine appears to be passed a size by which to increase the
+ * stack. It then executes a save instruction in the inferior to
+ * increase the stack by this amount. Only the register window system
+ * should be affected by this; the program counter & etc. will not be.
+ *
+ * This instructions used for this purpose are:
+ *
+ * sethi %hi(0x0),g1 *
+ * add g1,0x1ee0,g1 *
+ * save sp,g1,sp
+ * sethi %hi(0x0),g1 *
+ * add g1,0x1ee0,g1 *
+ * t g0,0x1,o0
+ * sethi %hi(0x0),g0 (nop)
+ *
+ * I presume that these set g1 to be the negative of the size, do a
+ * save (putting the stack pointer at sp - size) and restore the
+ * original contents of g1. A * indicates that the actual value of
+ * the instruction is modified below.
+ */
+static int save_insn_opcodes[] = {
+ 0x03000000, 0x82007ee0, 0x9de38001, 0x03000000,
+ 0x82007ee0, 0x91d02001, 0x01000000 };
+
+/* Neither do_save_insn or do_restore_insn save stack configuration
+ (since the stack is in an indeterminate state through the call to
+ each of them); that responsibility of the routine which calls them. */
+
+void
+do_save_insn (size)
+ int size;
+{
+ int g1 = read_register (1);
+ CORE_ADDR sp = read_register (SP_REGNUM);
+ CORE_ADDR pc = read_register (PC_REGNUM);
+ CORE_ADDR npc = read_register (NPC_REGNUM);
+ CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes);
+ struct inferior_status inf_status;
+
+ save_inferior_status (&inf_status, 0); /* Don't restore stack info */
+ /*
+ * See above.
+ */
+ save_insn_opcodes[0] = 0x03000000 | ((-size >> 10) & 0x3fffff);
+ save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff);
+ save_insn_opcodes[3] = 0x03000000 | ((g1 >> 10) & 0x3fffff);
+ save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff);
+ write_memory (fake_pc, save_insn_opcodes, sizeof (save_insn_opcodes));
+
+ clear_proceed_status ();
+ stop_after_trap = 1;
+ proceed (fake_pc, 0, 0);
+
+ write_register (PC_REGNUM, pc);
+ write_register (NPC_REGNUM, npc);
+ restore_inferior_status (&inf_status);
+}
+
+/*
+ * This routine takes a program counter value. It restores the
+ * register window system to the frame above the current one, and sets
+ * the pc and npc to the correct values.
+ */
+
+/* The following insns translate to:
+
+ restore
+ t g0,0x1,o0
+ sethi %hi(0x0), g0 */
+
+static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 };
+
+void
+do_restore_insn (pc)
+ CORE_ADDR pc;
+{
+ CORE_ADDR sp = read_register (SP_REGNUM);
+ CORE_ADDR npc = pc + 4;
+ CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes);
+ struct inferior_status inf_status;
+
+ save_inferior_status (&inf_status, 0); /* Don't restore stack info */
+
+ if (!pc)
+ abort();
+
+ write_memory (fake_pc, restore_insn_opcodes, sizeof (restore_insn_opcodes));
+
+ clear_proceed_status ();
+ stop_after_trap = 1;
+ proceed (fake_pc, 0, 0);
+
+ write_register (PC_REGNUM, pc);
+ write_register (NPC_REGNUM, npc);
+ restore_inferior_status (&inf_status);
+}
+
+/*
+ * This routine should be more specific in it's actions; making sure
+ * that it uses the same register in the initial prologue section.
+ */
+CORE_ADDR
+skip_prologue (pc)
+ CORE_ADDR pc;
+{
+ union
+ {
+ union insn_fmt insn;
+ int i;
+ } x;
+ int dest = -1;
+
+ x.i = read_memory_integer (pc, 4);
+
+ /* Recognize sethi insn. Record destination. */
+ if (x.insn.sethi.op == 0
+ && x.insn.sethi.op2 == 4)
+ {
+ dest = x.insn.sethi.rd;
+ pc += 4;
+ x.i = read_memory_integer (pc, 4);
+ }
+
+ /* Recognizes an add immediate value to register to either %g1 or
+ the destination register recorded above. Actually, this might
+ well recognize several different arithmetic operations.*/
+ if (x.insn.arith_imm.op == 2
+ && x.insn.arith_imm.i == 1
+ && (x.insn.arith_imm.rd == 1
+ || x.insn.arith_imm.rd == dest))
+ {
+ pc += 4;
+ x.i = read_memory_integer (pc, 4);
+ }
+
+ /* This recognizes any SAVE insn. But why do the XOR and then
+ the compare? That's identical to comparing against 60 (as long
+ as there isn't any sign extension). */
+ if (x.insn.arith.op == 2
+ && (x.insn.arith.op3 ^ 32) == 28)
+ {
+ pc += 4;
+ x.i = read_memory_integer (pc, 4);
+ }
+
+ /* Now we need to recognize stores into the frame from the input
+ registers. This recognizes all non alternate stores of input
+ register, into a location offset from the frame pointer. */
+ while (x.insn.arith_imm.op == 3
+ && (x.insn.arith_imm.op3 & 0x3c) == 4 /* Store, non-alt */
+ && (x.insn.arith_imm.rd & 0x18) == 0x18 /* Input register */
+ && x.insn.arith_imm.i == 1 /* Immediate mode */
+ && x.insn.arith_imm.rs1 == 30 /* Off of frame pointer */
+ && x.insn.arith_imm.simm >= 0x44 /* Into reserved */
+ && x.insn.arith_imm.simm < 0x5b) /* stack space. */
+ {
+ pc += 4;
+ x.i = read_memory_integer (pc, 4);
+ }
+ return pc;
+}
+
+/*
+ * Check instruction at "addr" to see if it is an annulled branch.
+ * All other instructions will go to NPC or will trap.
+ *
+ * Set *target if we find a candidate branch; set to zero if not.
+ */
+
+branch_type
+isannulled (addr, target)
+ CORE_ADDR addr, *target;
+{
+ union insn_fmt instr;
+ branch_type val = not_branch;
+ long offset; /* Must be signed for sign-extend */
+
+ *target = 0;
+ instr.intval = read_memory_integer (addr, 4);
+ /* printf("intval = %x\n",instr.intval); */
+ switch (instr.op1.op1)
+ {
+ case 0: /* Format 2 */
+ switch(instr.op2.op2)
+ {
+ case 2: case 6: case 7: /* Bcc, FBcc, CBcc */
+ if (instr.branch.cond == 8)
+ val = instr.branch.a ? baa : ba;
+ else
+ val = instr.branch.a ? bicca : bicc;
+ /* 22 bits, sign extended */
+ offset = 4 * ((int) (instr.branch.disp << 10) >> 10);
+ *target = addr + offset;
+ break;
+ }
+ break;
+ }
+ /*printf("isannulled ret: %d\n",val); */
+ return val;
+}
+@
+
+
+1.2
+log
+@ * Use gdbcore.h rather than a bunch of externs.
+ * Avoid dependency on "exec file" when figuring out data_start and data_end
+of core file.
+@
+text
+@d97 2
+a98 2
+static CORE_ADDR next_pc, pc8, target;
+static int brkpc8, brktrg;
+d113 2
+a114 1
+ branch_type br, isabranch();
+d117 1
+a117 1
+ pc8 = read_register (PC_REGNUM) + 8; /* branch not taken */
+d124 1
+d126 3
+a128 3
+ /* printf ("set break at %x\n",next_pc); */
+ br = isabranch (pc8 - 8, &target);
+ brkpc8 = brktrg = 0;
+d130 7
+a136 6
+ if (br == bicca && pc8 != next_pc)
+ {
+ /* Handle branches with care */
+ brkpc8 = 1;
+ read_memory (pc8, break_mem[1], sizeof break_insn);
+ write_memory (pc8, break_insn, sizeof break_insn);
+d140 2
+d157 1
+a157 1
+ if (brkpc8)
+d159 1
+a159 1
+ write_memory (pc8, break_mem[1], sizeof break_insn);
+d895 6
+a900 1
+/* Set *target if we find a branch. */
+d903 1
+a903 1
+isabranch (addr, target)
+d918 1
+a918 1
+ case 2: case 6: /* BICC & FBCC */
+d930 1
+a930 1
+ /*printf("isabranch ret: %d\n",val); */
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d29 1
+a453 49
+/* File names of core file and executable file. */
+
+extern char *corefile;
+extern char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+extern int corechan;
+extern int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+extern int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+extern CORE_ADDR data_start;
+extern CORE_ADDR data_end;
+extern CORE_ADDR stack_start;
+extern CORE_ADDR stack_end;
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+extern CORE_ADDR text_start;
+extern CORE_ADDR text_end;
+
+extern CORE_ADDR exec_data_start;
+extern CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+extern int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+extern int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+extern int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+extern int stack_offset;
+
+d520 2
+a521 1
+ data_start = exec_data_start;
+a601 2
+ data_start = 0;
+ data_end -= exec_data_start;
+a644 2
+ data_start = exec_data_start;
+ data_end += exec_data_start;
+a661 2
+ data_start = exec_data_start;
+ data_end += exec_data_start;
+@
diff --git a/gdb/RCS/stack.c,v b/gdb/RCS/stack.c,v
new file mode 100644
index 0000000..fc755c2
--- /dev/null
+++ b/gdb/RCS/stack.c,v
@@ -0,0 +1,882 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.02.09.23.53.05; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.09.15.03.51; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Avoid coredumps if stack commands are used when there is no stack.
+@
+text
+@/* Print and select stack frames for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include <stdio.h>
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+
+
+/* Thie "selected" stack frame is used by default for local and arg access.
+ May be zero, for no selected frame. */
+
+FRAME selected_frame;
+
+/* Level of the selected frame:
+ 0 for innermost, 1 for its caller, ...
+ or -1 for frame specified by address with no defined level. */
+
+int selected_frame_level;
+
+/* Error message when selected_frame is zero when it's needed */
+char no_sel_frame[] = "There is no current stack frame.";
+
+/* Nonzero means print the full filename and linenumber
+ when a frame is printed, and do so in a format programs can parse. */
+
+int frame_file_full_name = 0;
+
+static void select_calling_frame ();
+
+void print_frame_info ();
+
+/* Print a stack frame briefly. FRAME should be the frame address
+ and LEVEL should be its level in the stack (or -1 for level not defined).
+ This prints the level, the function executing, the arguments,
+ and the file name and line number.
+ If the pc is not at the beginning of the source line,
+ the actual pc is printed at the beginning.
+
+ If SOURCE is 1, print the source line as well.
+ If SOURCE is -1, print ONLY the source line. */
+
+/* FIXME, the argument "frame" is always "selected_frame". This is why
+ we can say "No selected frame" if it == 0. Probably shouldn't be an
+ argument anymore... */
+
+static void
+print_stack_frame (frame, level, source)
+ FRAME frame;
+ int level;
+ int source;
+{
+ struct frame_info *fi;
+
+ if (frame == 0)
+ error (no_sel_frame);
+ fi = get_frame_info (frame);
+
+ print_frame_info (fi, level, source, 1);
+}
+
+void
+print_frame_info (fi, level, source, args)
+ struct frame_info *fi;
+ register int level;
+ int source;
+ int args;
+{
+ struct symtab_and_line sal;
+ struct symbol *func;
+ register char *funname = 0;
+ int numargs;
+
+ sal = find_pc_line (fi->pc, fi->next_frame);
+ func = find_pc_function (fi->pc);
+ if (func)
+ funname = SYMBOL_NAME (func);
+ else
+ {
+ register int misc_index = find_pc_misc_function (fi->pc);
+ if (misc_index >= 0)
+ funname = misc_function_vector[misc_index].name;
+ }
+
+ if (source >= 0 || !sal.symtab)
+ {
+ if (level >= 0)
+ printf ("#%-2d ", level);
+ if (fi->pc != sal.pc || !sal.symtab)
+ printf ("0x%x in ", fi->pc);
+ printf ("%s (", funname ? funname : "??");
+ if (args)
+ {
+ FRAME_NUM_ARGS (numargs, fi);
+ print_frame_args (func, fi, numargs, stdout);
+ }
+ printf (")");
+ if (sal.symtab)
+ printf (" (%s line %d)", sal.symtab->filename, sal.line);
+ printf ("\n");
+ }
+
+ if (source != 0 && sal.symtab)
+ {
+ int done = 0;
+ int mid_statement = source < 0 && fi->pc != sal.pc;
+ if (frame_file_full_name)
+ done = identify_source_line (sal.symtab, sal.line, mid_statement);
+ if (!done)
+ {
+ if (mid_statement)
+ printf ("0x%x\t", fi->pc);
+ print_source_lines (sal.symtab, sal.line, sal.line + 1, 1);
+ }
+ current_source_line = max (sal.line - 5, 1);
+ }
+ if (source != 0)
+ set_default_breakpoint (1, fi->pc, sal.symtab, sal.line);
+
+ fflush (stdout);
+}
+
+/* Call here to print info on selected frame, after a trap. */
+
+void
+print_sel_frame (just_source)
+ int just_source;
+{
+ print_stack_frame (selected_frame, -1, just_source ? -1 : 1);
+}
+
+/* Print info on the selected frame, including level number
+ but not source. */
+
+void
+print_selected_frame ()
+{
+ print_stack_frame (selected_frame, selected_frame_level, 0);
+}
+
+void flush_cached_frames (); /* FIXME, never called! */
+
+#ifdef FRAME_SPECIFICATION_DYADIC
+extern FRAME setup_arbitrary_frame ();
+#endif
+
+/*
+ * Read a frame specification in whatever the appropriate format is.
+ */
+static FRAME
+parse_frame_specification (frame_exp)
+ char *frame_exp;
+{
+ int numargs = 0;
+ int arg1, arg2;
+
+ if (frame_exp)
+ {
+ char *addr_string, *p;
+ struct cleanup *tmp_cleanup;
+ struct frame_info *fci;
+
+ while (*frame_exp == ' ') frame_exp++;
+ for (p = frame_exp; *p && *p != ' '; p++)
+ ;
+
+ if (*frame_exp)
+ {
+ numargs = 1;
+ addr_string = savestring(frame_exp, p - frame_exp);
+
+ {
+ tmp_cleanup = make_cleanup (free, addr_string);
+ arg1 = parse_and_eval_address (addr_string);
+ do_cleanups (tmp_cleanup);
+ }
+
+ while (*p == ' ') p++;
+
+ if (*p)
+ {
+ numargs = 2;
+ arg2 = parse_and_eval_address (p);
+ }
+ }
+ }
+
+ switch (numargs)
+ {
+ case 0:
+ if (selected_frame == 0)
+ error (no_sel_frame);
+ return selected_frame;
+ /* NOTREACHED */
+ case 1:
+ {
+ int level = arg1;
+ FRAME fid = find_relative_frame (get_current_frame (), &level);
+ FRAME tfid;
+
+ if (level == 0)
+ /* find_relative_frame was successful */
+ return fid;
+
+ /* If (s)he specifies the frame with an address, he deserves what
+ (s)he gets. Still, give the highest one that matches. */
+
+ for (fid = get_current_frame ();
+ fid && FRAME_FP (fid) != arg1;
+ fid = get_prev_frame (fid))
+ ;
+
+ if (fid)
+ while ((tfid = get_prev_frame (fid)) &&
+ (FRAME_FP (tfid) == arg1))
+ fid = tfid;
+
+#ifdef FRAME_SPECIFICATION_DYADIC
+ if (!fid)
+ error ("Incorrect number of args in frame specification");
+
+ return fid;
+#else
+ return create_new_frame (arg1, 0);
+#endif
+ }
+ /* NOTREACHED */
+ case 2:
+ /* Must be addresses */
+#ifndef FRAME_SPECIFICATION_DYADIC
+ error ("Incorrect number of args in frame specification");
+#else
+ return setup_arbitrary_frame (arg1, arg2);
+#endif
+ /* NOTREACHED */
+ }
+ fatal ("Internal: Error in parsing in parse_frame_specification");
+ /* NOTREACHED */
+}
+
+/* Print verbosely the selected frame or the frame at address ADDR.
+ This means absolutely all information in the frame is printed. */
+
+static void
+frame_info (addr_exp)
+ char *addr_exp;
+{
+ FRAME frame;
+ struct frame_info *fi;
+ struct frame_saved_regs fsr;
+ struct symtab_and_line sal;
+ struct symbol *func;
+ FRAME calling_frame;
+ int i, count;
+ char *funname = 0;
+ int numargs;
+
+ frame = parse_frame_specification (addr_exp);
+
+ fi = get_frame_info (frame);
+ get_frame_saved_regs (fi, &fsr);
+ sal = find_pc_line (fi->pc, fi->next_frame);
+ func = get_frame_function (frame);
+ if (func)
+ funname = SYMBOL_NAME (func);
+ else
+ {
+ register int misc_index = find_pc_misc_function (fi->pc);
+ if (misc_index >= 0)
+ funname = misc_function_vector[misc_index].name;
+ }
+ calling_frame = get_prev_frame (frame);
+
+ if (!addr_exp && selected_frame_level >= 0)
+ printf ("Stack level %d, frame at 0x%x:\n pc = 0x%x",
+ selected_frame_level, FRAME_FP(frame), fi->pc);
+ else
+ printf ("Stack frame at 0x%x:\n pc = 0x%x",
+ FRAME_FP(frame), fi->pc);
+
+ if (funname)
+ printf (" in %s", funname);
+ if (sal.symtab)
+ printf (" (%s line %d)", sal.symtab->filename, sal.line);
+ printf ("; saved pc 0x%x\n", FRAME_SAVED_PC (frame));
+ if (calling_frame)
+ printf (" called by frame at 0x%x", FRAME_FP (calling_frame));
+ if (fi->next_frame && calling_frame)
+ printf (",");
+ if (fi->next_frame)
+ printf (" caller of frame at 0x%x", fi->next_frame);
+ if (fi->next_frame || calling_frame)
+ printf ("\n");
+ printf (" Arglist at 0x%x,", FRAME_ARGS_ADDRESS (fi));
+ FRAME_NUM_ARGS (i, fi);
+ if (i < 0)
+ printf (" args: ");
+ else if (i == 0)
+ printf (" no args.");
+ else if (i == 1)
+ printf (" 1 arg: ");
+ else
+ printf (" %d args: ", i);
+
+ FRAME_NUM_ARGS (numargs, fi);
+ print_frame_args (func, fi, numargs, stdout);
+ printf ("\n");
+ count = 0;
+ for (i = 0; i < NUM_REGS; i++)
+ if (fsr.regs[i])
+ {
+ if (count % 4 != 0)
+ printf (", ");
+ else
+ {
+ if (count == 0)
+ printf (" Saved registers:");
+ printf ("\n ");
+ }
+ printf ("%s at 0x%x", reg_names[i], fsr.regs[i]);
+ count++;
+ }
+ if (count)
+ printf ("\n");
+}
+
+#if 0
+/* Set a limit on the number of frames printed by default in a
+ backtrace. */
+
+static int backtrace_limit;
+
+static void
+set_backtrace_limit_command (count_exp, from_tty)
+ char *count_exp;
+ int from_tty;
+{
+ int count = parse_and_eval_address (count_exp);
+
+ if (count < 0)
+ error ("Negative argument not meaningful as backtrace limit.");
+
+ backtrace_limit = count;
+}
+
+static void
+backtrace_limit_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"Info backtrace-limit\" takes no arguments.");
+
+ printf ("Backtrace limit: %d.\n", backtrace_limit);
+}
+#endif
+
+/* Print briefly all stack frames or just the innermost COUNT frames. */
+
+static void
+backtrace_command (count_exp)
+ char *count_exp;
+{
+ struct frame_info *fi;
+ register int count;
+ register FRAME frame;
+ register int i;
+ register FRAME trailing;
+ register int trailing_level;
+
+ if (have_inferior_p () == 0 && corefile == 0)
+ error ("There is no running program or core file.");
+
+ /* The following code must do two things. First, it must
+ set the variable TRAILING to the frame from which we should start
+ printing. Second, it must set the variable count to the number
+ of frames which we should print, or -1 if all of them. */
+ trailing = get_current_frame ();
+ trailing_level = 0;
+ if (count_exp)
+ {
+ count = parse_and_eval_address (count_exp);
+ if (count < 0)
+ {
+ FRAME current;
+
+ count = -count;
+
+ current = trailing;
+ while (current && count--)
+ current = get_prev_frame (current);
+
+ /* Will stop when CURRENT reaches the top of the stack. TRAILING
+ will be COUNT below it. */
+ while (current)
+ {
+ trailing = get_prev_frame (trailing);
+ current = get_prev_frame (current);
+ trailing_level++;
+ }
+
+ count = -1;
+ }
+ }
+ else
+#if 0
+ count = backtrace_limit;
+#else
+ count = -1;
+#endif
+
+ for (i = 0, frame = trailing;
+ frame && count--;
+ i++, frame = get_prev_frame (frame))
+ {
+ QUIT;
+ fi = get_frame_info (frame);
+ print_frame_info (fi, trailing_level + i, 0, 1);
+ }
+
+ /* If we've stopped before the end, mention that. */
+ if (frame)
+ printf ("(More stack frames follow...)\n");
+}
+
+/* Print the local variables of a block B active in FRAME. */
+
+static void
+print_block_frame_locals (b, frame, stream)
+ struct block *b;
+ register FRAME frame;
+ register FILE *stream;
+{
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (sym) == LOC_LOCAL
+ || SYMBOL_CLASS (sym) == LOC_REGISTER
+ || SYMBOL_CLASS (sym) == LOC_STATIC)
+ {
+ fprintf (stream, "%s = ", SYMBOL_NAME (sym));
+ print_variable_value (sym, frame, stream);
+ fprintf (stream, "\n");
+ fflush (stream);
+ }
+ }
+}
+
+/* Print on STREAM all the local variables in frame FRAME,
+ including all the blocks active in that frame
+ at its current pc.
+
+ Returns 1 if the job was done,
+ or 0 if nothing was printed because we have no info
+ on the function running in FRAME. */
+
+static int
+print_frame_local_vars (frame, stream)
+ register FRAME frame;
+ register FILE *stream;
+{
+ register struct block *block;
+
+ block = get_frame_block (frame);
+ if (block == 0)
+ return 0;
+ while (block != 0)
+ {
+ print_block_frame_locals (block, frame, stream);
+ /* After handling the function's top-level block, stop.
+ Don't continue to its superblock, the block of
+ per-file symbols. */
+ if (BLOCK_FUNCTION (block))
+ break;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+ return 1;
+}
+
+static void
+locals_info ()
+{
+ if (selected_frame == 0)
+ error(no_sel_frame);
+ print_frame_local_vars (selected_frame, stdout);
+}
+
+static int
+print_frame_arg_vars (frame, stream)
+ register FRAME frame;
+ register FILE *stream;
+{
+ struct symbol *func;
+ register struct block *b;
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+
+ func = get_frame_function (frame);
+ if (func == 0)
+ return 0;
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (sym) == LOC_ARG || SYMBOL_CLASS (sym) == LOC_REGPARM)
+ {
+ fprintf (stream, "%s = ", SYMBOL_NAME (sym));
+ print_variable_value (sym, frame, stream);
+ fprintf (stream, "\n");
+ fflush (stream);
+ }
+ }
+
+ return 1;
+}
+
+static void
+args_info ()
+{
+ if (selected_frame == 0)
+ error(no_sel_frame);
+ print_frame_arg_vars (selected_frame, stdout);
+}
+
+/* Select frame FRAME, and note that its stack level is LEVEL.
+ LEVEL may be -1 if an actual level number is not known. */
+
+void
+select_frame (frame, level)
+ FRAME frame;
+ int level;
+{
+ selected_frame = frame;
+ selected_frame_level = level;
+}
+
+/* Store the selected frame and its level into *FRAMEP and *LEVELP. */
+
+void
+record_selected_frame (frameaddrp, levelp)
+ FRAME_ADDR *frameaddrp;
+ int *levelp;
+{
+ *frameaddrp = FRAME_FP (selected_frame);
+ *levelp = selected_frame_level;
+}
+
+/* Return the symbol-block in which the selected frame is executing.
+ Can return zero under various legitimate circumstances. */
+
+struct block *
+get_selected_block ()
+{
+ if (!have_inferior_p () && !have_core_file_p ())
+ return 0;
+
+ if (!selected_frame)
+ return get_current_block ();
+ return get_frame_block (selected_frame);
+}
+
+/* Find a frame a certain number of levels away from FRAME.
+ LEVEL_OFFSET_PTR points to an int containing the number of levels.
+ Positive means go to earlier frames (up); negative, the reverse.
+ The int that contains the number of levels is counted toward
+ zero as the frames for those levels are found.
+ If the top or bottom frame is reached, that frame is returned,
+ but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates
+ how much farther the original request asked to go. */
+
+FRAME
+find_relative_frame (frame, level_offset_ptr)
+ register FRAME frame;
+ register int* level_offset_ptr;
+{
+ register FRAME prev;
+ register FRAME frame1, frame2;
+
+ if (frame == 0)
+ error (no_sel_frame);
+ /* Going up is simple: just do get_prev_frame enough times
+ or until initial frame is reached. */
+ while (*level_offset_ptr > 0)
+ {
+ prev = get_prev_frame (frame);
+ if (prev == 0)
+ break;
+ (*level_offset_ptr)--;
+ frame = prev;
+ }
+ /* Going down could be done by iterating get_frame_info to
+ find the next frame, but that would be quadratic
+ since get_frame_info must scan all the way from the current frame.
+ The following algorithm is linear. */
+ if (*level_offset_ptr < 0)
+ {
+ /* First put frame1 at innermost frame
+ and frame2 N levels up from there. */
+ frame1 = get_current_frame ();
+ frame2 = frame1;
+ while (*level_offset_ptr < 0 && frame2 != frame)
+ {
+ frame2 = get_prev_frame (frame2);
+ (*level_offset_ptr) ++;
+ }
+ /* Then slide frame1 and frame2 up in synchrony
+ and when frame2 reaches our starting point
+ frame1 must be N levels down from there. */
+ while (frame2 != frame)
+ {
+ frame1 = get_prev_frame (frame1);
+ frame2 = get_prev_frame (frame2);
+ }
+ return frame1;
+ }
+ return frame;
+}
+
+/* The "frame" command. With no arg, print selected frame briefly.
+ With arg LEVEL_EXP, select the frame at level LEVEL if it is a
+ valid level. Otherwise, treat level_exp as an address expression
+ and print it. See parse_frame_specification for more info on proper
+ frame expressions. */
+
+static void
+frame_command (level_exp, from_tty)
+ char *level_exp;
+ int from_tty;
+{
+ register FRAME frame, frame1;
+ unsigned int level = 0;
+
+ frame = parse_frame_specification (level_exp);
+
+ for (frame1 = get_prev_frame (0);
+ frame1 && frame1 != frame;
+ frame1 = get_prev_frame (frame1))
+ level++;
+
+ if (!frame1)
+ level = 0;
+
+ select_frame (frame, level);
+
+ if (!from_tty)
+ return;
+
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+/* Select the frame up one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+static void
+up_command (count_exp)
+ char *count_exp;
+{
+ register FRAME frame;
+ int count = 1, count1;
+ if (count_exp)
+ count = parse_and_eval_address (count_exp);
+ count1 = count;
+
+ frame = find_relative_frame (selected_frame, &count1);
+ if (count1 != 0 && count_exp == 0)
+ error ("Initial frame selected; you cannot go up.");
+ select_frame (frame, selected_frame_level + count - count1);
+
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+/* Select the frame down one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+static void
+down_command (count_exp)
+ char *count_exp;
+{
+ register FRAME frame;
+ int count = -1, count1;
+ if (count_exp)
+ count = - parse_and_eval_address (count_exp);
+ count1 = count;
+
+ frame = find_relative_frame (selected_frame, &count1);
+ if (count1 != 0 && count_exp == 0)
+ error ("Bottom (i.e., innermost) frame selected; you cannot go down.");
+ select_frame (frame, selected_frame_level + count - count1);
+
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+static void
+return_command (retval_exp, from_tty)
+ char *retval_exp;
+ int from_tty;
+{
+ struct symbol *thisfun = get_frame_function (selected_frame);
+
+ /* If interactive, require confirmation. */
+
+ if (from_tty)
+ {
+ if (thisfun != 0)
+ {
+ if (!query ("Make %s return now? ", SYMBOL_NAME (thisfun)))
+ error ("Not confirmed.");
+ }
+ else
+ if (!query ("Make selected stack frame return now? "))
+ error ("Not confirmed.");
+ }
+
+ /* Do the real work. Pop until the specified frame is current. */
+
+ while (selected_frame != get_current_frame ())
+ POP_FRAME;
+
+ /* Then pop that frame. */
+
+ POP_FRAME;
+
+ /* Compute the return value (if any) and store in the place
+ for return values. */
+
+ if (retval_exp)
+ set_return_value (parse_and_eval (retval_exp));
+
+ /* If interactive, print the frame that is now current. */
+
+ if (from_tty)
+ frame_command ("0", 1);
+}
+
+extern struct cmd_list_element *setlist;
+
+void
+_initialize_stack ()
+{
+#if 0
+ backtrace_limit = 30;
+#endif
+
+ add_com ("return", class_stack, return_command,
+ "Make selected stack frame return to its caller.\n\
+Control remains in the debugger, but when you continue\n\
+execution will resume in the frame above the one now selected.\n\
+If an argument is given, it is an expression for the value to return.");
+
+ add_com ("up", class_stack, up_command,
+ "Select and print stack frame that called this one.\n\
+An argument says how many frames up to go.");
+
+ add_com ("down", class_stack, down_command,
+ "Select and print stack frame called by this one.\n\
+An argument says how many frames down to go.");
+ add_com_alias ("do", "down", class_stack, 1);
+
+ add_com ("frame", class_stack, frame_command,
+ "Select and print a stack frame.\n\
+With no argument, print the selected stack frame. (See also \"info frame\").\n\
+An argument specifies the frame to select.\n\
+It can be a stack frame number or the address of the frame.\n\
+With argument, nothing is printed if input is coming from\n\
+a command file or a user-defined command.");
+
+ add_com_alias ("f", "frame", class_stack, 1);
+
+ add_com ("backtrace", class_stack, backtrace_command,
+ "Print backtrace of all stack frames, or innermost COUNT frames.\n\
+With a negative argument, print outermost -COUNT frames.");
+ add_com_alias ("bt", "backtrace", class_stack, 0);
+ add_com_alias ("where", "backtrace", class_alias, 0);
+ add_info ("stack", backtrace_command,
+ "Backtrace of the stack, or innermost COUNT frames.");
+ add_info_alias ("s", "stack", 1);
+ add_info ("frame", frame_info,
+ "All about selected stack frame, or frame at ADDR.");
+ add_info_alias ("f", "frame", 1);
+ add_info ("locals", locals_info,
+ "Local variables of current stack frame.");
+ add_info ("args", args_info,
+ "Argument variables of current stack frame.");
+
+#if 0
+ add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command,
+ "Specify maximum number of frames for \"backtrace\" to print by default.",
+ &setlist);
+ add_info ("backtrace-limit", backtrace_limit_info,
+ "The maximum number of frames for \"backtrace\" to print by default.");
+#endif
+}
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d2 1
+a2 1
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+d27 2
+d42 3
+d64 4
+d76 2
+d162 1
+a162 1
+void flush_cached_frames ();
+d212 2
+d392 3
+d489 3
+a491 1
+ register struct block *block = get_frame_block (frame);
+d510 2
+d520 1
+a520 1
+ struct symbol *func = get_frame_function (frame);
+d526 1
+d551 2
+d610 2
+@
diff --git a/gdb/RCS/utils.c,v b/gdb/RCS/utils.c,v
new file mode 100644
index 0000000..1d8000d
--- /dev/null
+++ b/gdb/RCS/utils.c,v
@@ -0,0 +1,726 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.03.27.20.22.34; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.03.23.14.27.48; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@Portability changes. If USG, we need to re-enable the SIGINT
+signal handler when it is called. Also, build the sys_siglist
+table at runtime, based on the actual values of the signal
+#define's. Too many USG systems added Berkeley signal names
+as various numbers.
+@
+text
+@/* General utility routines for GDB, the GNU debugger.
+ Copyright (C) 1986 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include "defs.h"
+#include "param.h"
+#ifdef HAVE_TERMIO
+#include <termio.h>
+#endif
+
+void error ();
+void fatal ();
+
+/* Chain of cleanup actions established with make_cleanup,
+ to be executed if an error happens. */
+
+static struct cleanup *cleanup_chain;
+
+/* Nonzero means a quit has been requested. */
+
+int quit_flag;
+
+/* Nonzero means quit immediately if Control-C is typed now,
+ rather than waiting until QUIT is executed. */
+
+int immediate_quit;
+
+/* Add a new cleanup to the cleanup_chain,
+ and return the previous chain pointer
+ to be passed later to do_cleanups or discard_cleanups.
+ Args are FUNCTION to clean up with, and ARG to pass to it. */
+
+struct cleanup *
+make_cleanup (function, arg)
+ void (*function) ();
+ int arg;
+{
+ register struct cleanup *new
+ = (struct cleanup *) xmalloc (sizeof (struct cleanup));
+ register struct cleanup *old_chain = cleanup_chain;
+
+ new->next = cleanup_chain;
+ new->function = function;
+ new->arg = arg;
+ cleanup_chain = new;
+
+ return old_chain;
+}
+
+/* Discard cleanups and do the actions they describe
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+do_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ register struct cleanup *ptr;
+ while ((ptr = cleanup_chain) != old_chain)
+ {
+ (*ptr->function) (ptr->arg);
+ cleanup_chain = ptr->next;
+ free (ptr);
+ }
+}
+
+/* Discard cleanups, not doing the actions they describe,
+ until we get back to the point OLD_CHAIN in the cleanup_chain. */
+
+void
+discard_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ register struct cleanup *ptr;
+ while ((ptr = cleanup_chain) != old_chain)
+ {
+ cleanup_chain = ptr->next;
+ free (ptr);
+ }
+}
+
+/* Set the cleanup_chain to 0, and return the old cleanup chain. */
+struct cleanup *
+save_cleanups ()
+{
+ struct cleanup *old_chain = cleanup_chain;
+
+ cleanup_chain = 0;
+ return old_chain;
+}
+
+/* Restore the cleanup chain from a previously saved chain. */
+void
+restore_cleanups (chain)
+ struct cleanup *chain;
+{
+ cleanup_chain = chain;
+}
+
+/* This function is useful for cleanups.
+ Do
+
+ foo = xmalloc (...);
+ old_chain = make_cleanup (free_current_contents, &foo);
+
+ to arrange to free the object thus allocated. */
+
+void
+free_current_contents (location)
+ char **location;
+{
+ free (*location);
+}
+
+/* Generally useful subroutines used throughout the program. */
+
+/* Like malloc but get error if no storage available. */
+
+char *
+xmalloc (size)
+ long size;
+{
+ register char *val = (char *) malloc (size);
+ if (!val)
+ fatal ("virtual memory exhausted.", 0);
+ return val;
+}
+
+/* Like realloc but get error if no storage available. */
+
+char *
+xrealloc (ptr, size)
+ char *ptr;
+ long size;
+{
+ register char *val = (char *) realloc (ptr, size);
+ if (!val)
+ fatal ("virtual memory exhausted.", 0);
+ return val;
+}
+
+/* Print the system error message for errno, and also mention STRING
+ as the file name for which the error was encountered.
+ Then return to command level. */
+
+void
+perror_with_name (string)
+ char *string;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int errno;
+ char *err;
+ char *combined;
+
+ if (errno < sys_nerr)
+ err = sys_errlist[errno];
+ else
+ err = "unknown error";
+
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ error ("%s.", combined);
+}
+
+/* Print the system error message for ERRCODE, and also mention STRING
+ as the file name for which the error was encountered. */
+
+void
+print_sys_errmsg (string, errcode)
+ char *string;
+ int errcode;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ char *err;
+ char *combined;
+
+ if (errcode < sys_nerr)
+ err = sys_errlist[errcode];
+ else
+ err = "unknown error";
+
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ printf ("%s.\n", combined);
+}
+
+void
+quit ()
+{
+ fflush (stdout);
+#ifdef HAVE_TERMIO
+ ioctl (fileno (stdout), TCFLSH, 1);
+#else /* not HAVE_TERMIO */
+ ioctl (fileno (stdout), TIOCFLUSH, 0);
+#endif /* not HAVE_TERMIO */
+
+#ifdef TIOCGPGRP
+ error ("Quit");
+#else
+ error ("Quit (expect signal %d when inferior is resumed)", SIGINT);
+#endif /* TIOCGPGRP */
+}
+
+/* Control C comes here */
+
+void
+request_quit ()
+{
+ quit_flag = 1;
+
+#ifdef USG
+ /* Restore the signal handler */
+ signal(SIGINT, request_quit);
+#endif
+
+ if (immediate_quit)
+ quit ();
+}
+
+/* Print an error message and return to command level.
+ STRING is the error message, used as a fprintf string,
+ and ARG is passed as an argument to it. */
+
+void
+error (string, arg1, arg2, arg3)
+ char *string;
+ int arg1, arg2, arg3;
+{
+ fflush (stdout);
+ fprintf (stderr, string, arg1, arg2, arg3);
+ fprintf (stderr, "\n");
+ return_to_top_level ();
+}
+
+/* Print an error message and exit reporting failure.
+ This is for a error that we cannot continue from.
+ STRING and ARG are passed to fprintf. */
+
+void
+fatal (string, arg)
+ char *string;
+ int arg;
+{
+ fprintf (stderr, "gdb: ");
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Make a copy of the string at PTR with SIZE characters
+ (and add a null character at the end in the copy).
+ Uses malloc to get the space. Returns the address of the copy. */
+
+char *
+savestring (ptr, size)
+ char *ptr;
+ int size;
+{
+ register char *p = (char *) xmalloc (size + 1);
+ bcopy (ptr, p, size);
+ p[size] = 0;
+ return p;
+}
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ register char *val = (char *) xmalloc (len);
+ strcpy (val, s1);
+ strcat (val, s2);
+ strcat (val, s3);
+ return val;
+}
+
+void
+print_spaces (n, file)
+ register int n;
+ register FILE *file;
+{
+ while (n-- > 0)
+ fputc (' ', file);
+}
+
+/* Ask user a y-or-n question and return 1 iff answer is yes.
+ Takes three args which are given to printf to print the question.
+ The first, a control string, should end in "? ".
+ It should not say how to answer, because we do that. */
+
+int
+query (ctlstr, arg1, arg2)
+ char *ctlstr;
+{
+ register int answer;
+
+ /* Automatically answer "yes" if input is not from a terminal. */
+ if (!input_from_terminal_p ())
+ return 1;
+
+ while (1)
+ {
+ printf (ctlstr, arg1, arg2);
+ printf ("(y or n) ");
+ fflush (stdout);
+ answer = fgetc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer != '\n')
+ while (fgetc (stdin) != '\n') clearerr (stdin);
+ if (answer >= 'a')
+ answer -= 040;
+ if (answer == 'Y')
+ return 1;
+ if (answer == 'N')
+ return 0;
+ printf ("Please answer y or n.\n");
+ }
+}
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+int
+parse_escape (string_ptr)
+ char **string_ptr;
+{
+ register int c = *(*string_ptr)++;
+ switch (c)
+ {
+ case 'a':
+ return '\a';
+ case 'b':
+ return '\b';
+ case 'e':
+ return 033;
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case 'v':
+ return '\v';
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+ case '^':
+ c = *(*string_ptr)++;
+ if (c == '\\')
+ c = parse_escape (string_ptr);
+ if (c == '?')
+ return 0177;
+ return (c & 0200) | (c & 037);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ register int i = c - '0';
+ register int count = 0;
+ while (++count < 3)
+ {
+ if ((c = *(*string_ptr)++) >= '0' && c <= '7')
+ {
+ i *= 8;
+ i += c - '0';
+ }
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ return i;
+ }
+ default:
+ return c;
+ }
+}
+
+/* Print the character CH on STREAM as part of the contents
+ of a literal string whose delimiter is QUOTER. */
+
+void
+printchar (ch, stream, quoter)
+ unsigned char ch;
+ FILE *stream;
+ int quoter;
+{
+ register int c = ch;
+ if (c < 040 || c >= 0177)
+ {
+ if (c == '\n')
+ fprintf (stream, "\\n");
+ else if (c == '\b')
+ fprintf (stream, "\\b");
+ else if (c == '\t')
+ fprintf (stream, "\\t");
+ else if (c == '\f')
+ fprintf (stream, "\\f");
+ else if (c == '\r')
+ fprintf (stream, "\\r");
+ else if (c == 033)
+ fprintf (stream, "\\e");
+ else if (c == '\a')
+ fprintf (stream, "\\a");
+ else
+ fprintf (stream, "\\%03o", c);
+ }
+ else
+ {
+ if (c == '\\' || c == quoter)
+ fputc ('\\', stream);
+ fputc (c, stream);
+ }
+}
+
+
+#ifdef USG
+bcopy (from, to, count)
+char *from, *to;
+{
+ memcpy (to, from, count);
+}
+
+bcmp (from, to, count)
+{
+ return (memcmp (to, from, count));
+}
+
+bzero (to, count)
+char *to;
+{
+ while (count--)
+ *to++ = 0;
+}
+
+getwd (buf)
+char *buf;
+{
+ getcwd (buf, MAXPATHLEN);
+}
+
+char *
+index (s, c)
+ char *s;
+{
+ char *strchr ();
+ return strchr (s, c);
+}
+
+char *
+rindex (s, c)
+ char *s;
+{
+ char *strrchr ();
+ return strrchr (s, c);
+}
+
+/* Queue routines */
+
+struct queue {
+ struct queue *forw;
+ struct queue *back;
+};
+
+insque (item, after)
+struct queue *item;
+struct queue *after;
+{
+ item->forw = after->forw;
+ after->forw->back = item;
+
+ item->back = after;
+ after->forw = item;
+}
+
+remque (item)
+struct queue *item;
+{
+ item->forw->back = item->back;
+ item->back->forw = item->forw;
+}
+
+
+/*
+ * There is too much variation in Sys V signal numbers and names, so
+ * we must initialize them at runtime. If C provided a way to initialize
+ * an array based on subscript and value, this would not be necessary.
+ */
+static char undoc[] = "(undocumented)";
+
+char *sys_siglist[NSIG];
+
+_initialize_utils()
+{
+ int i;
+
+ for (i = 0; i < NSIG; i++)
+ sys_siglist[i] = undoc;
+
+#ifdef SIGHUP
+ sys_siglist[SIGHUP ] = "SIGHUP";
+#endif
+#ifdef SIGINT
+ sys_siglist[SIGINT ] = "SIGINT";
+#endif
+#ifdef SIGQUIT
+ sys_siglist[SIGQUIT ] = "SIGQUIT";
+#endif
+#ifdef SIGILL
+ sys_siglist[SIGILL ] = "SIGILL";
+#endif
+#ifdef SIGTRAP
+ sys_siglist[SIGTRAP ] = "SIGTRAP";
+#endif
+#ifdef SIGIOT
+ sys_siglist[SIGIOT ] = "SIGIOT";
+#endif
+#ifdef SIGEMT
+ sys_siglist[SIGEMT ] = "SIGEMT";
+#endif
+#ifdef SIGFPE
+ sys_siglist[SIGFPE ] = "SIGFPE";
+#endif
+#ifdef SIGKILL
+ sys_siglist[SIGKILL ] = "SIGKILL";
+#endif
+#ifdef SIGBUS
+ sys_siglist[SIGBUS ] = "SIGBUS";
+#endif
+#ifdef SIGSEGV
+ sys_siglist[SIGSEGV ] = "SIGSEGV";
+#endif
+#ifdef SIGSYS
+ sys_siglist[SIGSYS ] = "SIGSYS";
+#endif
+#ifdef SIGPIPE
+ sys_siglist[SIGPIPE ] = "SIGPIPE";
+#endif
+#ifdef SIGALRM
+ sys_siglist[SIGALRM ] = "SIGALRM";
+#endif
+#ifdef SIGTERM
+ sys_siglist[SIGTERM ] = "SIGTERM";
+#endif
+#ifdef SIGUSR1
+ sys_siglist[SIGUSR1 ] = "SIGUSR1";
+#endif
+#ifdef SIGUSR2
+ sys_siglist[SIGUSR2 ] = "SIGUSR2";
+#endif
+#ifdef SIGCLD
+ sys_siglist[SIGCLD ] = "SIGCLD";
+#endif
+#ifdef SIGCHLD
+ sys_siglist[SIGCHLD ] = "SIGCHLD";
+#endif
+#ifdef SIGPWR
+ sys_siglist[SIGPWR ] = "SIGPWR";
+#endif
+#ifdef SIGTSTP
+ sys_siglist[SIGTSTP ] = "SIGTSTP";
+#endif
+#ifdef SIGTTIN
+ sys_siglist[SIGTTIN ] = "SIGTTIN";
+#endif
+#ifdef SIGTTOU
+ sys_siglist[SIGTTOU ] = "SIGTTOU";
+#endif
+#ifdef SIGSTOP
+ sys_siglist[SIGSTOP ] = "SIGSTOP";
+#endif
+#ifdef SIGXCPU
+ sys_siglist[SIGXCPU ] = "SIGXCPU";
+#endif
+#ifdef SIGXFSZ
+ sys_siglist[SIGXFSZ ] = "SIGXFSZ";
+#endif
+#ifdef SIGVTALRM
+ sys_siglist[SIGVTALRM ] = "SIGVTALRM";
+#endif
+#ifdef SIGPROF
+ sys_siglist[SIGPROF ] = "SIGPROF";
+#endif
+#ifdef SIGWINCH
+ sys_siglist[SIGWINCH ] = "SIGWINCH";
+#endif
+#ifdef SIGCONT
+ sys_siglist[SIGCONT ] = "SIGCONT";
+#endif
+#ifdef SIGURG
+ sys_siglist[SIGURG ] = "SIGURG";
+#endif
+#ifdef SIGIO
+ sys_siglist[SIGIO ] = "SIGIO";
+#endif
+#ifdef SIGWIND
+ sys_siglist[SIGWIND ] = "SIGWIND";
+#endif
+#ifdef SIGPHONE
+ sys_siglist[SIGPHONE ] = "SIGPHONE";
+#endif
+#ifdef SIGPOLL
+ sys_siglist[SIGPOLL ] = "SIGPOLL";
+#endif
+}
+#endif /* USG */
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d223 1
+d237 6
+a506 26
+char *sys_siglist[32] = {
+ "SIG0",
+ "SIGHUP",
+ "SIGINT",
+ "SIGQUIT",
+ "SIGILL",
+ "SIGTRAP",
+ "SIGIOT",
+ "SIGEMT",
+ "SIGFPE",
+ "SIGKILL",
+ "SIGBUS",
+ "SIGSEGV",
+ "SIGSYS",
+ "SIGPIPE",
+ "SIGALRM",
+ "SIGTERM",
+ "SIGUSR1",
+ "SIGUSR2",
+ "SIGCLD",
+ "SIGPWR",
+ "SIGWIND",
+ "SIGPHONE",
+ "SIGPOLL",
+};
+
+d530 124
+@
diff --git a/gdb/RCS/valprint.c,v b/gdb/RCS/valprint.c,v
new file mode 100644
index 0000000..52d89b0
--- /dev/null
+++ b/gdb/RCS/valprint.c,v
@@ -0,0 +1,1117 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.3
+date 89.04.26.01.49.11; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.04.26.00.57.15; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.04.25.15.16.40; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@Fix spelling Nan => NaN
+@
+text
+@/* Print values for GNU debugger gdb.
+ Copyright (C) 1986, 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+
+/* Maximum number of chars to print for a string pointer value
+ or vector contents. */
+
+static int print_max;
+
+static void type_print_varspec_suffix ();
+static void type_print_varspec_prefix ();
+static void type_print_base ();
+static void type_print_method_args ();
+
+
+char **unsigned_type_table;
+char **signed_type_table;
+char **float_type_table;
+
+/* Print the value VAL in C-ish syntax on stream STREAM.
+ FORMAT is a format-letter, or 0 for print in natural format of data type.
+ If the object printed is a string pointer, returns
+ the number of string bytes printed. */
+
+int
+value_print (val, stream, format)
+ value val;
+ FILE *stream;
+ char format;
+{
+ register int i, n, typelen;
+
+ /* A "repeated" value really contains several values in a row.
+ They are made by the @@ operator.
+ Print such values as if they were arrays. */
+
+ if (VALUE_REPEATED (val))
+ {
+ n = VALUE_REPETITIONS (val);
+ typelen = TYPE_LENGTH (VALUE_TYPE (val));
+ fputc ('{', stream);
+ /* Print arrays of characters using string syntax. */
+ if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT
+ && format == 0)
+ {
+ fputc ('"', stream);
+ for (i = 0; i < n && i < print_max; i++)
+ {
+ QUIT;
+ printchar (VALUE_CONTENTS (val)[i], stream, '"');
+ }
+ if (i < n)
+ fprintf (stream, "...");
+ fputc ('"', stream);
+ }
+ else
+ {
+ for (i = 0; i < n && i < print_max; i++)
+ {
+ if (i)
+ fprintf (stream, ", ");
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i,
+ VALUE_ADDRESS (val) + typelen * i,
+ stream, format, 1);
+ }
+ if (i < n)
+ fprintf (stream, "...");
+ }
+ fputc ('}', stream);
+ return n * typelen;
+ }
+ else
+ {
+ /* If it is a pointer, indicate what it points to.
+
+ Print type also if it is a reference.
+
+ C++: if it is a member pointer, we will take care
+ of that when we print it. */
+ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_PTR
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF)
+ {
+ fprintf (stream, "(");
+ type_print (VALUE_TYPE (val), "", stream, -1);
+ fprintf (stream, ") ");
+ }
+ return val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+ VALUE_ADDRESS (val), stream, format, 1);
+ }
+}
+
+/* Print data of type TYPE located at VALADDR (within GDB),
+ which came from the inferior at address ADDRESS,
+ onto stdio stream STREAM according to FORMAT
+ (a letter or 0 for natural format).
+
+ If the data are a string pointer, returns the number of
+ sting characters printed.
+
+ if DEREF_REF is nonzero, then dereference references,
+ otherwise just print them like pointers. */
+
+int
+val_print (type, valaddr, address, stream, format, deref_ref)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ FILE *stream;
+ char format;
+ int deref_ref;
+{
+ register int i;
+ int len, n_baseclasses;
+ struct type *elttype;
+ int eltlen;
+ LONGEST val;
+ unsigned char c;
+
+ QUIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (TYPE_LENGTH (type) >= 0)
+ {
+ elttype = TYPE_TARGET_TYPE (type);
+ eltlen = TYPE_LENGTH (elttype);
+ len = TYPE_LENGTH (type) / eltlen;
+ fprintf (stream, "{");
+ /* For an array of chars, print with string syntax. */
+ if (eltlen == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT
+ && format == 0)
+ {
+ fputc ('"', stream);
+ for (i = 0; i < len && i < print_max; i++)
+ {
+ QUIT;
+ printchar (valaddr[i], stream, '"');
+ }
+ if (i < len)
+ fprintf (stream, "...");
+ fputc ('"', stream);
+ }
+ else
+ {
+ for (i = 0; i < len && i < print_max; i++)
+ {
+ if (i) fprintf (stream, ", ");
+ val_print (elttype, valaddr + i * eltlen,
+ 0, stream, format, deref_ref);
+ }
+ if (i < len)
+ fprintf (stream, "...");
+ }
+ fprintf (stream, "}");
+ break;
+ }
+ /* Array of unspecified length: treat like pointer. */
+
+ case TYPE_CODE_PTR:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
+ {
+ struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
+ struct type *target = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type));
+ struct fn_field *f;
+ int j, len2;
+ char *kind = "";
+
+ val = unpack_long (builtin_type_int, valaddr);
+ if (TYPE_CODE (target) == TYPE_CODE_FUNC)
+ {
+ if (val < 128)
+ {
+ len = TYPE_NFN_FIELDS (domain);
+ for (i = 0; i < len; i++)
+ {
+ f = TYPE_FN_FIELDLIST1 (domain, i);
+ len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ if (TYPE_FN_FIELD_VOFFSET (f, j) == val)
+ {
+ kind = "virtual";
+ goto common;
+ }
+ }
+ }
+ }
+ else
+ {
+ struct symbol *sym = find_pc_function ((CORE_ADDR) val);
+ if (sym == 0)
+ error ("invalid pointer to member function");
+ len = TYPE_NFN_FIELDS (domain);
+ for (i = 0; i < len; i++)
+ {
+ f = TYPE_FN_FIELDLIST1 (domain, i);
+ len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ if (!strcmp (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
+ goto common;
+ }
+ }
+ }
+ common:
+ if (i < len)
+ {
+ fputc ('&', stream);
+ type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
+ fprintf (stream, kind);
+ if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+ && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
+ type_print_method_args
+ (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
+ TYPE_FN_FIELDLIST_NAME (domain, i), stream);
+ else
+ type_print_method_args
+ (TYPE_FN_FIELD_ARGS (f, j), "",
+ TYPE_FN_FIELDLIST_NAME (domain, i), stream);
+ break;
+ }
+ }
+ else
+ {
+ /* VAL is a byte offset into the structure type DOMAIN.
+ Find the name of the field for that offset and
+ print it. */
+ int extra = 0;
+ int bits = 0;
+ len = TYPE_NFIELDS (domain);
+ val <<= 3; /* @@@@ Make VAL into bit offset */
+ for (i = 0; i < len; i++)
+ {
+ int bitpos = TYPE_FIELD_BITPOS (domain, i);
+ QUIT;
+ if (val == bitpos)
+ break;
+ if (val < bitpos && i > 0)
+ {
+ int ptrsize = (TYPE_LENGTH (builtin_type_char) * TYPE_LENGTH (target));
+ /* Somehow pointing into a field. */
+ i -= 1;
+ extra = (val - TYPE_FIELD_BITPOS (domain, i));
+ if (extra & 0x3)
+ bits = 1;
+ else
+ extra >>= 3;
+ break;
+ }
+ }
+ if (i < len)
+ {
+ fputc ('&', stream);
+ type_print_base (domain, stream, 0, 0);
+ fprintf (stream, "::");
+ fprintf (stream, "%s", TYPE_FIELD_NAME (domain, i));
+ if (extra)
+ fprintf (stream, " + %d bytes", extra);
+ if (bits)
+ fprintf (stream, " (offset in bits)");
+ break;
+ }
+ }
+ fputc ('(', stream);
+ type_print (type, "", stream, -1);
+ fprintf (stream, ") %d", val >> 3);
+ }
+ else
+ {
+ fprintf (stream, "0x%x", * (int *) valaddr);
+ /* For a pointer to char or unsigned char,
+ also print the string pointed to, unless pointer is null. */
+
+ /* For an array of chars, print with string syntax. */
+ elttype = TYPE_TARGET_TYPE (type);
+ i = 0; /* Number of characters printed. */
+ if (TYPE_LENGTH (elttype) == 1
+ && TYPE_CODE (elttype) == TYPE_CODE_INT
+ && format == 0
+ /* Convex needs this typecast to a long */
+ && (long) unpack_long (type, valaddr) != 0
+ && print_max)
+ {
+ fputc (' ', stream);
+
+ /* Get first character. */
+ if (read_memory ( (CORE_ADDR) unpack_long (type, valaddr),
+ &c, 1))
+ {
+ /* First address out of bounds. */
+ fprintf (stream, "<Address 0x%x out of bounds>",
+ (* (int *) valaddr));
+ break;
+ }
+ else
+ {
+ /* A real string. */
+ int out_of_bounds = 0;
+
+ fputc ('"', stream);
+ while (c)
+ {
+ QUIT;
+ printchar (c, stream, '"');
+ if (++i >= print_max)
+ break;
+ if (read_memory ((CORE_ADDR) unpack_long (type, valaddr)
+ + i, &c, 1))
+ {
+ /* This address was out of bounds. */
+ fprintf (stream,
+ "\"*** <Address 0x%x out of bounds>",
+ (* (int *) valaddr) + i);
+ out_of_bounds = 1;
+ break;
+ }
+ }
+ if (!out_of_bounds)
+ {
+ fputc ('"', stream);
+ if (i == print_max)
+ fprintf (stream, "...");
+ }
+ }
+ fflush (stream);
+ }
+ /* Return number of characters printed, plus one for the
+ terminating null if we have "reached the end". */
+ return i + (print_max && i != print_max);
+ }
+ break;
+
+ case TYPE_CODE_MEMBER:
+ error ("not implemented: member type in val_print");
+ break;
+
+ case TYPE_CODE_REF:
+ fprintf (stream, "(0x%x &) = ", * (int *) valaddr);
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+ {
+ value val = value_at (TYPE_TARGET_TYPE (type), * (int *) valaddr);
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+ VALUE_ADDRESS (val), stream, format, deref_ref);
+ }
+ else
+ fprintf (stream, "???");
+ }
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ fprintf (stream, "{");
+ len = TYPE_NFIELDS (type);
+ n_baseclasses = TYPE_N_BASECLASSES (type);
+ for (i = 1; i <= n_baseclasses; i++)
+ {
+ fprintf (stream, "\n<%s> = ", TYPE_NAME (TYPE_BASECLASS (type, i)));
+ val_print (TYPE_FIELD_TYPE (type, 0),
+ valaddr + TYPE_FIELD_BITPOS (type, i-1) / 8,
+ 0, stream, 0, 0);
+ }
+ if (i > 1) fprintf (stream, "\nmembers of %s: ", TYPE_NAME (type));
+ for (i -= 1; i < len; i++)
+ {
+ if (i > n_baseclasses) fprintf (stream, ", ");
+ fprintf (stream, "%s = ", TYPE_FIELD_NAME (type, i));
+ /* check if static field */
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ value v;
+
+ v = value_static_field (type, TYPE_FIELD_NAME (type, i), i);
+ val_print (TYPE_FIELD_TYPE (type, i),
+ VALUE_CONTENTS (v), 0, stream, format, deref_ref);
+ }
+ else if (TYPE_FIELD_PACKED (type, i))
+ {
+ val = unpack_field_as_long (type, valaddr, i);
+ val_print (TYPE_FIELD_TYPE (type, i), &val, 0,
+ stream, format, deref_ref);
+ }
+ else
+ {
+ val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
+ 0, stream, format, deref_ref);
+ }
+ }
+ fprintf (stream, "}");
+ break;
+
+ case TYPE_CODE_ENUM:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ len = TYPE_NFIELDS (type);
+ val = (long) unpack_long (builtin_type_int, valaddr);
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (val == TYPE_FIELD_BITPOS (type, i))
+ break;
+ }
+ if (i < len)
+ fprintf (stream, "%s", TYPE_FIELD_NAME (type, i));
+ else
+ fprintf (stream, "%d", val);
+ break;
+
+ case TYPE_CODE_FUNC:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ fprintf (stream, "{");
+ type_print (type, "", stream, -1);
+ fprintf (stream, "} ");
+ fprintf (stream, "0x%x", address);
+ break;
+
+ case TYPE_CODE_INT:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ fprintf (stream,
+ TYPE_UNSIGNED (type) ? "%u" : "%d",
+ unpack_long (type, valaddr));
+ if (TYPE_LENGTH (type) == 1)
+ {
+ fprintf (stream, " '");
+ printchar ((unsigned char) unpack_long (type, valaddr),
+ stream, '\'');
+ fputc ('\'', stream);
+ }
+ break;
+
+ case TYPE_CODE_FLT:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ /* FIXME: When printing NaNs or invalid floats, print them
+ in raw hex in addition to the message. */
+#ifdef IEEE_FLOAT
+ if (is_nan ((void *)valaddr, TYPE_LENGTH(type)))
+ {
+ fprintf (stream, "NaN");
+ break;
+ }
+#endif
+ {
+ double doub;
+ int inv;
+
+ doub = unpack_double (type, valaddr, &inv);
+ if (inv)
+ fprintf (stream, "Invalid float value");
+ else
+ fprintf (stream, TYPE_LENGTH (type) <= 4? "%.6g": "%.16g", doub);
+ }
+ break;
+
+ case TYPE_CODE_VOID:
+ fprintf (stream, "void");
+ break;
+
+ default:
+ error ("Invalid type code in symbol table.");
+ }
+ fflush (stream);
+}
+
+#ifdef IEEE_FLOAT
+
+/* Nonzero if ARG (a double) is a NAN. */
+
+int
+is_nan (fp, len)
+ void *fp;
+ int len;
+{
+ int lowhalf, highhalf;
+ union ieee {
+ long i[2]; /* ASSUMED 32 BITS */
+ float f; /* ASSUMED 32 BITS */
+ double d; /* ASSUMED 64 BITS */
+ } *arg;
+
+ arg = (union ieee *)fp;
+
+ /*
+ * Single precision float.
+ */
+ if (len == sizeof(long)) {
+ highhalf = arg->i[0];
+ return ((((highhalf >> 23) & 0xFF) == 0xFF)
+ && 0 != (highhalf & 0x7FFFFF));
+ }
+
+ /* Separate the high and low words of the double.
+ Distinguish big and little-endian machines. */
+#ifdef WORDS_BIG_ENDIAN
+ lowhalf = arg->i[1], highhalf = arg->i[0];
+#else
+ lowhalf = arg->i[0], highhalf = arg->i[1];
+#endif
+
+ /* Nan: exponent is the maximum possible, and fraction is nonzero. */
+ return (((highhalf>>20) & 0x7ff) == 0x7ff
+ &&
+ ! ((highhalf & 0xfffff == 0) && (lowhalf == 0)));
+}
+#endif
+
+/* Print a description of a type TYPE
+ in the form of a declaration of a variable named VARSTRING.
+ Output goes to STREAM (via stdio).
+ If SHOW is positive, we show the contents of the outermost level
+ of structure even if there is a type name that could be used instead.
+ If SHOW is negative, we never show the details of elements' types. */
+
+void
+type_print (type, varstring, stream, show)
+ struct type *type;
+ char *varstring;
+ FILE *stream;
+ int show;
+{
+ type_print_1 (type, varstring, stream, show, 0);
+}
+
+/* LEVEL is the depth to indent lines by. */
+
+void
+type_print_1 (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ FILE *stream;
+ int show;
+ int level;
+{
+ register enum type_code code;
+ type_print_base (type, stream, show, level);
+ code = TYPE_CODE (type);
+ if ((varstring && *varstring)
+ ||
+ /* Need a space if going to print stars or brackets;
+ but not if we will print just a type name. */
+ ((show > 0 || TYPE_NAME (type) == 0)
+ &&
+ (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
+ || code == TYPE_CODE_ARRAY
+ || code == TYPE_CODE_MEMBER
+ || code == TYPE_CODE_REF)))
+ fprintf (stream, " ");
+ type_print_varspec_prefix (type, stream, show, 0);
+ fprintf (stream, "%s", varstring);
+ type_print_varspec_suffix (type, stream, show, 0);
+}
+
+/* Print the method arguments ARGS to the file STREAM. */
+static void
+type_print_method_args (args, prefix, varstring, stream)
+ struct type **args;
+ char *prefix, *varstring;
+ FILE *stream;
+{
+ int i;
+
+ fprintf (stream, " %s%s (", prefix, varstring);
+ if (args[1] && args[1]->code != TYPE_CODE_VOID)
+ {
+ i = 1; /* skip the class variable */
+ while (1)
+ {
+ type_print (args[i++], "", stream, 0);
+ if (!args[i])
+ {
+ fprintf (stream, " ...");
+ break;
+ }
+ else if (args[i]->code != TYPE_CODE_VOID)
+ {
+ fprintf (stream, ", ");
+ }
+ else break;
+ }
+ }
+ fprintf (stream, ")");
+}
+
+/* If TYPE is a derived type, then print out derivation
+ information. Print out all layers of the type heirarchy
+ until we encounter one with multiple inheritance.
+ At that point, print out that ply, and return. */
+static void
+type_print_derivation_info (stream, type)
+ FILE *stream;
+ struct type *type;
+{
+ char *name;
+ int i, n_baseclasses = TYPE_N_BASECLASSES (type);
+ struct type *basetype = 0;
+
+ while (type && n_baseclasses == 1)
+ {
+ basetype = TYPE_BASECLASS (type, 1);
+ if (TYPE_NAME (basetype) && (name = TYPE_NAME (basetype)))
+ {
+ while (*name != ' ') name++;
+ fprintf (stream, ": %s%s %s ",
+ TYPE_VIA_PUBLIC (basetype) ? "public" : "private",
+ TYPE_VIA_VIRTUAL (basetype) ? " virtual" : "",
+ name + 1);
+ }
+ n_baseclasses = TYPE_N_BASECLASSES (basetype);
+ type = basetype;
+ }
+
+ if (type)
+ {
+ if (n_baseclasses != 0)
+ fprintf (stream, ": ");
+ for (i = 1; i <= n_baseclasses; i++)
+ {
+ basetype = TYPE_BASECLASS (type, i);
+ if (TYPE_NAME (basetype) && (name = TYPE_NAME (basetype)))
+ {
+ while (*name != ' ') name++;
+ fprintf (stream, "%s%s %s",
+ TYPE_VIA_PUBLIC (basetype) ? "public" : "private",
+ TYPE_VIA_VIRTUAL (basetype) ? " virtual" : "",
+ name + 1);
+ }
+ if (i < n_baseclasses)
+ fprintf (stream, ", ");
+ }
+ putc (' ', stream);
+ }
+}
+
+/* Print any asterisks or open-parentheses needed before the
+ variable name (to describe its type).
+
+ On outermost call, pass 0 for PASSED_A_PTR.
+ On outermost call, SHOW > 0 means should ignore
+ any typename for TYPE and show its details.
+ SHOW is always zero on recursive calls. */
+
+static void
+type_print_varspec_prefix (type, stream, show, passed_a_ptr)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int passed_a_ptr;
+{
+ if (type == 0)
+ return;
+
+ if (TYPE_NAME (type) && show <= 0)
+ return;
+
+ QUIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ fputc ('*', stream);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr);
+ fputc (' ', stream);
+ type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0,
+ passed_a_ptr);
+ fprintf (stream, "::");
+ break;
+
+ case TYPE_CODE_REF:
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ fputc ('&', stream);
+ break;
+
+ case TYPE_CODE_FUNC:
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr);
+ if (passed_a_ptr)
+ fputc ('(', stream);
+ break;
+
+ case TYPE_CODE_ARRAY:
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr);
+ }
+}
+
+/* Print any array sizes, function arguments or close parentheses
+ needed after the variable name (to describe its type).
+ Args work like type_print_varspec_prefix. */
+
+static void
+type_print_varspec_suffix (type, stream, show, passed_a_ptr)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int passed_a_ptr;
+{
+ if (type == 0)
+ return;
+
+ if (TYPE_NAME (type) && show <= 0)
+ return;
+
+ QUIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr);
+ fprintf (stream, "[");
+ if (TYPE_LENGTH (type) >= 0
+ && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+ fprintf (stream, "%d",
+ TYPE_LENGTH (type) / TYPE_LENGTH (TYPE_TARGET_TYPE (type)));
+ fprintf (stream, "]");
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fputc (')', stream);
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ break;
+
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ break;
+
+ case TYPE_CODE_FUNC:
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr);
+ if (passed_a_ptr)
+ fprintf (stream, ")");
+ fprintf (stream, "()");
+ break;
+ }
+}
+
+/* Print the name of the type (or the ultimate pointer target,
+ function value or array element), or the description of a
+ structure or union.
+
+ SHOW nonzero means don't print this type as just its name;
+ show its real definition even if it has a name.
+ SHOW zero means print just typename or struct tag if there is one
+ SHOW negative means abbreviate structure elements.
+ SHOW is decremented for printing of structure elements.
+
+ LEVEL is the depth to indent by.
+ We increase it for some recursive calls. */
+
+static void
+type_print_base (type, stream, show, level)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int level;
+{
+ char *name;
+ register int i;
+ register int len;
+ register int lastval;
+
+ QUIT;
+
+ if (type == 0)
+ {
+ fprintf (stream, "type unknown");
+ return;
+ }
+
+ if (TYPE_NAME (type) && show <= 0)
+ {
+ fprintf (stream, TYPE_NAME (type));
+ return;
+ }
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_MEMBER:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_FUNC:
+ type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ fprintf (stream, "struct ");
+ goto struct_union;
+
+ case TYPE_CODE_UNION:
+ fprintf (stream, "union ");
+ struct_union:
+ if (TYPE_NAME (type) && (name = TYPE_NAME (type)))
+ {
+ while (*name != ' ') name++;
+ fprintf (stream, "%s ", name + 1);
+ }
+ if (show < 0)
+ fprintf (stream, "{...}");
+ else
+ {
+ int i;
+
+ type_print_derivation_info (stream, type);
+
+ fprintf (stream, "{");
+ len = TYPE_NFIELDS (type);
+ if (len) fprintf (stream, "\n");
+ else fprintf (stream, "<no data fields>\n");
+
+ /* If there is a base class for this type,
+ do not print the field that it occupies. */
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ {
+ QUIT;
+ /* Don't print out virtual function table. */
+ if (! strncmp (TYPE_FIELD_NAME (type, i),
+ "_vptr$", 6))
+ continue;
+
+ print_spaces (level + 4, stream);
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ fprintf (stream, "static ");
+ }
+ type_print_1 (TYPE_FIELD_TYPE (type, i),
+ TYPE_FIELD_NAME (type, i),
+ stream, show - 1, level + 4);
+ if (!TYPE_FIELD_STATIC (type, i)
+ && TYPE_FIELD_PACKED (type, i))
+ {
+ /* ??? don't know what to put here ??? */;
+ }
+ fprintf (stream, ";\n");
+ }
+
+ /* C++: print out the methods */
+ len = TYPE_NFN_FIELDS (type);
+ if (len) fprintf (stream, "\n");
+ for (i = 0; i < len; i++)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ print_spaces (level + 4, stream);
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ fprintf (stream, "virtual ");
+ type_print (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j))), "", stream, 0);
+ if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+ && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
+ type_print_method_args
+ (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
+ TYPE_FN_FIELDLIST_NAME (type, i), stream);
+ else
+ type_print_method_args
+ (TYPE_FN_FIELD_ARGS (f, j), "",
+ TYPE_FN_FIELDLIST_NAME (type, i), stream);
+
+ fprintf (stream, ";\n");
+ }
+ if (len2) fprintf (stream, "\n");
+ }
+
+ print_spaces (level, stream);
+ fputc ('}', stream);
+ }
+ break;
+
+ case TYPE_CODE_ENUM:
+ fprintf (stream, "enum ");
+ if (TYPE_NAME (type))
+ {
+ name = TYPE_NAME (type);
+ while (*name != ' ') name++;
+ fprintf (stream, "%s ", name + 1);
+ }
+ if (show < 0)
+ fprintf (stream, "{...}");
+ else
+ {
+ fprintf (stream, "{");
+ len = TYPE_NFIELDS (type);
+ lastval = 0;
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (i) fprintf (stream, ", ");
+ fprintf (stream, "%s", TYPE_FIELD_NAME (type, i));
+ if (lastval != TYPE_FIELD_BITPOS (type, i))
+ {
+ fprintf (stream, " : %d", TYPE_FIELD_BITPOS (type, i));
+ lastval = TYPE_FIELD_BITPOS (type, i);
+ }
+ lastval++;
+ }
+ fprintf (stream, "}");
+ }
+ break;
+
+ case TYPE_CODE_INT:
+ if (TYPE_UNSIGNED (type))
+ name = unsigned_type_table[TYPE_LENGTH (type)];
+ else
+ name = signed_type_table[TYPE_LENGTH (type)];
+ fprintf (stream, "%s", name);
+ break;
+
+ case TYPE_CODE_FLT:
+ name = float_type_table[TYPE_LENGTH (type)];
+ fprintf (stream, "%s", name);
+ break;
+
+ case TYPE_CODE_VOID:
+ fprintf (stream, "void");
+ break;
+
+ case 0:
+ fprintf (stream, "struct unknown");
+ break;
+
+ default:
+ error ("Invalid type code in symbol table.");
+ }
+}
+
+static void
+set_maximum_command (arg)
+ char *arg;
+{
+ if (!arg) error_no_arg ("value for maximum elements to print");
+ print_max = atoi (arg);
+}
+
+extern struct cmd_list_element *setlist;
+
+void
+_initialize_valprint ()
+{
+ add_cmd ("array-max", class_vars, set_maximum_command,
+ "Set NUMBER as limit on string chars or array elements to print.",
+ &setlist);
+
+ print_max = 200;
+
+ unsigned_type_table
+ = (char **) xmalloc ((1 + sizeof (unsigned LONGEST)) * sizeof (char *));
+ bzero (unsigned_type_table, (1 + sizeof (unsigned LONGEST)));
+ unsigned_type_table[sizeof (unsigned char)] = "unsigned char";
+ unsigned_type_table[sizeof (unsigned short)] = "unsigned short";
+ unsigned_type_table[sizeof (unsigned long)] = "unsigned long";
+ unsigned_type_table[sizeof (unsigned int)] = "unsigned int";
+#ifdef LONG_LONG
+ unsigned_type_table[sizeof (unsigned long long)] = "unsigned long long";
+#endif
+
+ signed_type_table
+ = (char **) xmalloc ((1 + sizeof (LONGEST)) * sizeof (char *));
+ bzero (signed_type_table, (1 + sizeof (LONGEST)));
+ signed_type_table[sizeof (char)] = "char";
+ signed_type_table[sizeof (short)] = "short";
+ signed_type_table[sizeof (long)] = "long";
+ signed_type_table[sizeof (int)] = "int";
+#ifdef LONG_LONG
+ signed_type_table[sizeof (long long)] = "long long";
+#endif
+
+ float_type_table
+ = (char **) xmalloc ((1 + sizeof (double)) * sizeof (char *));
+ bzero (float_type_table, (1 + sizeof (double)));
+ float_type_table[sizeof (float)] = "float";
+ float_type_table[sizeof (double)] = "double";
+}
+
+@
+
+
+1.2
+log
+@(1) Use XXX_BIG_ENDIAN macros rather than testing at runtime.
+(2) Change args to is_nan, support floats, change one call to it.
+(3) Change args to unpack_double.
+@
+text
+@d488 1
+a488 1
+ fprintf (stream, "Nan");
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d483 2
+d486 1
+a486 1
+ if (is_nan (unpack_double (type, valaddr)))
+d492 10
+a501 4
+ if (TYPE_LENGTH (type) <= 4)
+ fprintf (stream, "%.6g", unpack_double (type, valaddr));
+ else
+ fprintf (stream, "%.16g", unpack_double (type, valaddr));
+a515 5
+union ieee {
+ int i[2];
+ double d;
+};
+
+d519 3
+a521 2
+is_nan (arg)
+ union ieee arg;
+d524 16
+a539 1
+ union { int i; char c; } test;
+d543 5
+a547 6
+ test.i = 1;
+ if (test.c != 1)
+ /* Big-endian machine */
+ lowhalf = arg.i[1], highhalf = arg.i[0];
+ else
+ lowhalf = arg.i[0], highhalf = arg.i[1];
+@
diff --git a/gdb/RCS/values.c,v b/gdb/RCS/values.c,v
new file mode 100644
index 0000000..bc32f31
--- /dev/null
+++ b/gdb/RCS/values.c,v
@@ -0,0 +1,1047 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.04.26.01.05.45; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.04.25.15.38.44; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@(1) use XXX_BIG_ENDIAN macros rather than runtime tests.
+(2) Invalid values aren't stored in the value history, but they do
+not cause an error; a -1 is returned as their value index.
+(3) unpack_double takes a new arg, and callers check it.
+@
+text
+@
+/* Low level packing and unpacking of values for GDB.
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+
+/* The value-history records all the values printed
+ by print commands during this session. Each chunk
+ records 60 consecutive values. The first chunk on
+ the chain records the most recent values.
+ The total number of values is in value_history_count. */
+
+#define VALUE_HISTORY_CHUNK 60
+
+struct value_history_chunk
+{
+ struct value_history_chunk *next;
+ value values[VALUE_HISTORY_CHUNK];
+};
+
+/* Chain of chunks now in use. */
+
+static struct value_history_chunk *value_history_chain;
+
+static int value_history_count; /* Abs number of last entry stored */
+
+
+/* List of all value objects currently allocated
+ (except for those released by calls to release_value)
+ This is so they can be freed after each command. */
+
+static value all_values;
+
+/* Allocate a value that has the correct length for type TYPE. */
+
+value
+allocate_value (type)
+ struct type *type;
+{
+ register value val;
+
+ val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type));
+ VALUE_NEXT (val) = all_values;
+ all_values = val;
+ VALUE_TYPE (val) = type;
+ VALUE_LVAL (val) = not_lval;
+ VALUE_ADDRESS (val) = 0;
+ VALUE_FRAME (val) = 0;
+ VALUE_OFFSET (val) = 0;
+ VALUE_BITPOS (val) = 0;
+ VALUE_BITSIZE (val) = 0;
+ VALUE_REPEATED (val) = 0;
+ VALUE_REPETITIONS (val) = 0;
+ VALUE_REGNO (val) = -1;
+ return val;
+}
+
+/* Allocate a value that has the correct length
+ for COUNT repetitions type TYPE. */
+
+value
+allocate_repeat_value (type, count)
+ struct type *type;
+ int count;
+{
+ register value val;
+
+ val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type) * count);
+ VALUE_NEXT (val) = all_values;
+ all_values = val;
+ VALUE_TYPE (val) = type;
+ VALUE_LVAL (val) = not_lval;
+ VALUE_ADDRESS (val) = 0;
+ VALUE_FRAME (val) = 0;
+ VALUE_OFFSET (val) = 0;
+ VALUE_BITPOS (val) = 0;
+ VALUE_BITSIZE (val) = 0;
+ VALUE_REPEATED (val) = 1;
+ VALUE_REPETITIONS (val) = count;
+ VALUE_REGNO (val) = -1;
+ return val;
+}
+
+/* Free all the values that have been allocated (except for those released).
+ Called after each command, successful or not. */
+
+void
+free_all_values ()
+{
+ register value val, next;
+
+ for (val = all_values; val; val = next)
+ {
+ next = VALUE_NEXT (val);
+ free (val);
+ }
+
+ all_values = 0;
+}
+
+/* Remove VAL from the chain all_values
+ so it will not be freed automatically. */
+
+void
+release_value (val)
+ register value val;
+{
+ register value v;
+
+ if (all_values == val)
+ {
+ all_values = val->next;
+ return;
+ }
+
+ for (v = all_values; v; v = v->next)
+ {
+ if (v->next == val)
+ {
+ v->next = val->next;
+ break;
+ }
+ }
+}
+
+/* Return a copy of the value ARG.
+ It contains the same contents, for same memory address,
+ but it's a different block of storage. */
+
+static value
+value_copy (arg)
+ value arg;
+{
+ register value val;
+ register struct type *type = VALUE_TYPE (arg);
+ if (VALUE_REPEATED (arg))
+ val = allocate_repeat_value (type, VALUE_REPETITIONS (arg));
+ else
+ val = allocate_value (type);
+ VALUE_LVAL (val) = VALUE_LVAL (arg);
+ VALUE_ADDRESS (val) = VALUE_ADDRESS (arg);
+ VALUE_OFFSET (val) = VALUE_OFFSET (arg);
+ VALUE_BITPOS (val) = VALUE_BITPOS (arg);
+ VALUE_BITSIZE (val) = VALUE_BITSIZE (arg);
+ VALUE_REGNO (val) = VALUE_REGNO (arg);
+ bcopy (VALUE_CONTENTS (arg), VALUE_CONTENTS (val),
+ TYPE_LENGTH (VALUE_TYPE (arg))
+ * (VALUE_REPEATED (arg) ? VALUE_REPETITIONS (arg) : 1));
+ return val;
+}
+
+/* Access to the value history. */
+
+/* Record a new value in the value history.
+ Returns the absolute history index of the entry. */
+
+int
+record_latest_value (val)
+ value val;
+{
+ int i;
+ double foo;
+
+ /* Check error now if about to store an invalid float. We return -1
+ to the caller, but allow them to continue, e.g. to print it as "Nan". */
+ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT) {
+ foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &i);
+ if (i) return -1; /* Indicate value not saved in history */
+ }
+
+ /* Here we treat value_history_count as origin-zero
+ and applying to the value being stored now. */
+
+ i = value_history_count % VALUE_HISTORY_CHUNK;
+ if (i == 0)
+ {
+ register struct value_history_chunk *new
+ = (struct value_history_chunk *) xmalloc (sizeof (struct value_history_chunk));
+ bzero (new->values, sizeof new->values);
+ new->next = value_history_chain;
+ value_history_chain = new;
+ }
+
+ value_history_chain->values[i] = val;
+ release_value (val);
+
+ /* Now we regard value_history_count as origin-one
+ and applying to the value just stored. */
+
+ return ++value_history_count;
+}
+
+/* Return a copy of the value in the history with sequence number NUM. */
+
+value
+access_value_history (num)
+ int num;
+{
+ register struct value_history_chunk *chunk;
+ register int i;
+ register int absnum = num;
+
+ if (absnum <= 0)
+ absnum += value_history_count;
+
+ if (absnum <= 0)
+ {
+ if (num == 0)
+ error ("The history is empty.");
+ else if (num == 1)
+ error ("There is only one value in the history.");
+ else
+ error ("History does not go back to $$%d.", -num);
+ }
+ if (absnum > value_history_count)
+ error ("History has not yet reached $%d.", absnum);
+
+ absnum--;
+
+ /* Now absnum is always absolute and origin zero. */
+
+ chunk = value_history_chain;
+ for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK;
+ i > 0; i--)
+ chunk = chunk->next;
+
+ return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]);
+}
+
+/* Clear the value history entirely.
+ Must be done when new symbol tables are loaded,
+ because the type pointers become invalid. */
+
+void
+clear_value_history ()
+{
+ register struct value_history_chunk *next;
+ register int i;
+ register value val;
+
+ while (value_history_chain)
+ {
+ for (i = 0; i < VALUE_HISTORY_CHUNK; i++)
+ if (val = value_history_chain->values[i])
+ free (val);
+ next = value_history_chain->next;
+ free (value_history_chain);
+ value_history_chain = next;
+ }
+ value_history_count = 0;
+}
+
+static void
+history_info (num_exp)
+ char *num_exp;
+{
+ register int i;
+ register value val;
+ register int num;
+
+ if (num_exp)
+ num = parse_and_eval_address (num_exp) - 5;
+ else
+ num = value_history_count - 9;
+
+ if (num <= 0)
+ num = 1;
+
+ for (i = num; i < num + 10 && i <= value_history_count; i++)
+ {
+ val = access_value_history (i);
+ printf ("$%d = ", i);
+ value_print (val, stdout, 0);
+ printf ("\n");
+ }
+}
+
+/* Internal variables. These are variables within the debugger
+ that hold values assigned by debugger commands.
+ The user refers to them with a '$' prefix
+ that does not appear in the variable names stored internally. */
+
+static struct internalvar *internalvars;
+
+/* Look up an internal variable with name NAME. NAME should not
+ normally include a dollar sign.
+
+ If the specified internal variable does not exist,
+ one is created, with a void value. */
+
+struct internalvar *
+lookup_internalvar (name)
+ char *name;
+{
+ register struct internalvar *var;
+
+ for (var = internalvars; var; var = var->next)
+ if (!strcmp (var->name, name))
+ return var;
+
+ var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
+ var->name = concat (name, "", "");
+ var->value = allocate_value (builtin_type_void);
+ release_value (var->value);
+ var->next = internalvars;
+ internalvars = var;
+ return var;
+}
+
+value
+value_of_internalvar (var)
+ struct internalvar *var;
+{
+ register value val = value_copy (var->value);
+ VALUE_LVAL (val) = lval_internalvar;
+ VALUE_INTERNALVAR (val) = var;
+ return val;
+}
+
+void
+set_internalvar_component (var, offset, bitpos, bitsize, newval)
+ struct internalvar *var;
+ int offset, bitpos, bitsize;
+ value newval;
+{
+ register char *addr = VALUE_CONTENTS (var->value) + offset;
+ if (bitsize)
+ modify_field (addr, (int) value_as_long (newval),
+ bitpos, bitsize);
+ else
+ bcopy (VALUE_CONTENTS (newval), addr,
+ TYPE_LENGTH (VALUE_TYPE (newval)));
+}
+
+void
+set_internalvar (var, val)
+ struct internalvar *var;
+ value val;
+{
+ free (var->value);
+ var->value = value_copy (val);
+ release_value (var->value);
+}
+
+char *
+internalvar_name (var)
+ struct internalvar *var;
+{
+ return var->name;
+}
+
+/* Free all internalvars. Done when new symtabs are loaded,
+ because that makes the values invalid. */
+
+void
+clear_internalvars ()
+{
+ register struct internalvar *var;
+
+ while (internalvars)
+ {
+ var = internalvars;
+ internalvars = var->next;
+ free (var->name);
+ free (var->value);
+ free (var);
+ }
+}
+
+static void
+convenience_info ()
+{
+ register struct internalvar *var;
+
+ if (internalvars)
+ printf ("Debugger convenience variables:\n\n");
+ else
+ printf ("No debugger convenience variables now defined.\n\
+Convenience variables have names starting with \"$\";\n\
+use \"set\" as in \"set $foo = 5\" to define them.\n");
+
+ for (var = internalvars; var; var = var->next)
+ {
+ printf ("$%s: ", var->name);
+ value_print (var->value, stdout, 0);
+ printf ("\n");
+ }
+}
+
+/* Extract a value as a C number (either long or double).
+ Knows how to convert fixed values to double, or
+ floating values to long.
+ Does not deallocate the value. */
+
+LONGEST
+value_as_long (val)
+ register value val;
+{
+ return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val));
+}
+
+double
+value_as_double (val)
+ register value val;
+{
+ double foo;
+ int inv;
+
+ foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &inv);
+ if (inv)
+ error ("Invalid floating value found in program.");
+ return foo;
+}
+
+/* Unpack raw data (copied from debugee) at VALADDR
+ as a long, or as a double, assuming the raw data is described
+ by type TYPE. Knows how to convert different sizes of values
+ and can convert between fixed and floating point.
+
+ C++: It is assumed that the front-end has taken care of
+ all matters concerning pointers to members. A pointer
+ to member which reaches here is considered to be equivalent
+ to an INT (or some size). After all, it is only an offset. */
+
+LONGEST
+unpack_long (type, valaddr)
+ struct type *type;
+ char *valaddr;
+{
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+ register int nosign = TYPE_UNSIGNED (type);
+
+ if (code == TYPE_CODE_ENUM)
+ code = TYPE_CODE_INT;
+ if (code == TYPE_CODE_FLT)
+ {
+ if (len == sizeof (float))
+ return * (float *) valaddr;
+
+ if (len == sizeof (double))
+ return * (double *) valaddr;
+ }
+ else if (code == TYPE_CODE_INT && nosign)
+ {
+ if (len == sizeof (char))
+ return * (unsigned char *) valaddr;
+
+ if (len == sizeof (short))
+ return * (unsigned short *) valaddr;
+
+ if (len == sizeof (int))
+ return * (unsigned int *) valaddr;
+
+ if (len == sizeof (long))
+ return * (unsigned long *) valaddr;
+ }
+ else if (code == TYPE_CODE_INT)
+ {
+ if (len == sizeof (char))
+ return * (char *) valaddr;
+
+ if (len == sizeof (short))
+ return * (short *) valaddr;
+
+ if (len == sizeof (int))
+ return * (int *) valaddr;
+
+ if (len == sizeof (long))
+ return * (long *) valaddr;
+
+#ifdef LONG_LONG
+ if (len == sizeof (long long))
+ return * (long long *) valaddr;
+#endif
+ }
+ else if (code == TYPE_CODE_PTR
+ || code == TYPE_CODE_REF)
+ {
+ if (len == sizeof (char *))
+ return (CORE_ADDR) * (char **) valaddr;
+ }
+ else if (code == TYPE_CODE_MEMBER)
+ error ("not implemented: member types in unpack_long");
+
+ error ("Value not integer or pointer.");
+}
+
+/* Return a double value from the specified type and address.
+ * INVP points to an int which is set to 0 for valid value,
+ * 1 for invalid value (bad float format). In either case,
+ * the returned double is OK to use. */
+
+double
+unpack_double (type, valaddr, invp)
+ struct type *type;
+ char *valaddr;
+ int *invp;
+{
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+ register int nosign = TYPE_UNSIGNED (type);
+
+ *invp = 0; /* Assume valid */
+ if (code == TYPE_CODE_FLT)
+ {
+ if (INVALID_FLOAT (valaddr, len)) {
+ *invp = 1;
+ return 1.234567891011121314;
+ }
+
+ if (len == sizeof (float))
+ return * (float *) valaddr;
+
+ if (len == sizeof (double))
+ {
+ /* Some machines require doubleword alignment for doubles.
+ This code works on them, and on other machines. */
+ double temp;
+ bcopy ((char *) valaddr, (char *) &temp, sizeof (double));
+ return temp;
+ }
+ }
+ else if (code == TYPE_CODE_INT && nosign)
+ {
+ if (len == sizeof (char))
+ return * (unsigned char *) valaddr;
+
+ if (len == sizeof (short))
+ return * (unsigned short *) valaddr;
+
+ if (len == sizeof (int))
+ return * (unsigned int *) valaddr;
+
+ if (len == sizeof (long))
+ return * (unsigned long *) valaddr;
+
+#ifdef LONG_LONG
+ if (len == sizeof (long long))
+ return * (unsigned long long *) valaddr;
+#endif
+ }
+ else if (code == TYPE_CODE_INT)
+ {
+ if (len == sizeof (char))
+ return * (char *) valaddr;
+
+ if (len == sizeof (short))
+ return * (short *) valaddr;
+
+ if (len == sizeof (int))
+ return * (int *) valaddr;
+
+ if (len == sizeof (long))
+ return * (long *) valaddr;
+
+#ifdef LONG_LONG
+ if (len == sizeof (long long))
+ return * (long long *) valaddr;
+#endif
+ }
+
+ error ("Value not floating number.");
+}
+
+/* Given a value ARG1 of a struct or union type,
+ extract and return the value of one of its fields.
+ FIELDNO says which field.
+
+ For C++, must also be able to return values from static fields */
+
+value
+value_field (arg1, fieldno)
+ register value arg1;
+ register int fieldno;
+{
+ register value v;
+ register struct type *type = TYPE_FIELD_TYPE (VALUE_TYPE (arg1), fieldno);
+ register int offset;
+
+ /* Handle packed fields */
+
+ offset = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) / 8;
+ if (TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno))
+ {
+ v = value_from_long (type,
+ (LONGEST) unpack_field_as_long (VALUE_TYPE (arg1),
+ VALUE_CONTENTS (arg1),
+ fieldno));
+ VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) % 8;
+ VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno);
+ }
+ else
+ {
+ v = allocate_value (type);
+ bcopy (VALUE_CONTENTS (arg1) + offset,
+ VALUE_CONTENTS (v),
+ TYPE_LENGTH (type));
+ }
+ VALUE_LVAL (v) = VALUE_LVAL (arg1);
+ if (VALUE_LVAL (arg1) == lval_internalvar)
+ VALUE_LVAL (v) = lval_internalvar_component;
+ VALUE_ADDRESS (v) = VALUE_ADDRESS (arg1);
+ VALUE_OFFSET (v) = offset + VALUE_OFFSET (arg1);
+ return v;
+}
+
+value
+value_fn_field (arg1, fieldno, subfieldno)
+ register value arg1;
+ register int fieldno;
+{
+ register value v;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (VALUE_TYPE (arg1), fieldno);
+ register struct type *type = TYPE_FN_FIELD_TYPE (f, subfieldno);
+ struct symbol *sym;
+
+ sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, subfieldno),
+ 0, VAR_NAMESPACE, 0);
+ if (! sym) error ("Internal error: could not find physical method named %s",
+ TYPE_FN_FIELD_PHYSNAME (f, subfieldno));
+
+ v = allocate_value (type);
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ VALUE_TYPE (v) = type;
+ return v;
+}
+
+/* Return a virtual function as a value.
+ ARG1 is the object which provides the virtual function
+ table pointer.
+ F is the list of member functions which contains the desired virtual
+ function.
+ J is an index into F which provides the desired virtual function.
+ TYPE is the basetype which first provides the virtual function table. */
+value
+value_virtual_fn_field (arg1, f, j, type)
+ value arg1;
+ struct fn_field *f;
+ int j;
+ struct type *type;
+{
+ /* First, get the virtual function table pointer. That comes
+ with a strange type, so cast it to type `pointer to long' (which
+ should serve just fine as a function type). Then, index into
+ the table, and convert final value to appropriate function type. */
+ value vfn, vtbl;
+ value vi = value_from_long (builtin_type_int,
+ (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j));
+ VALUE_TYPE (arg1) = TYPE_VPTR_BASETYPE (type);
+
+ /* This type may have been defined before its virtual function table
+ was. If so, fill in the virtual function table entry for the
+ type now. */
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ TYPE_VPTR_FIELDNO (type)
+ = fill_in_vptr_fieldno (type);
+
+ /* Pretend that this array is just an array of pointers to integers.
+ This will have to change for multiple inheritance. */
+ vtbl = value_copy (value_field (arg1, TYPE_VPTR_FIELDNO (type)));
+ VALUE_TYPE (vtbl) = lookup_pointer_type (builtin_type_int);
+
+ /* Index into the virtual function table. */
+ vfn = value_subscript (vtbl, vi);
+
+ /* Reinstantiate the function pointer with the correct type. */
+ VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j));
+ return vfn;
+}
+
+/* The value of a static class member does not depend
+ on its instance, only on its type. If FIELDNO >= 0,
+ then fieldno is a valid field number and is used directly.
+ Otherwise, FIELDNAME is the name of the field we are
+ searching for. If it is not a static field name, an
+ error is signaled. TYPE is the type in which we look for the
+ static field member. */
+value
+value_static_field (type, fieldname, fieldno)
+ register struct type *type;
+ char *fieldname;
+ register int fieldno;
+{
+ register value v;
+ struct symbol *sym;
+
+ if (fieldno < 0)
+ {
+ register struct type *t = type;
+ /* Look for static field. */
+ while (t)
+ {
+ int i;
+ for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ if (! strcmp (TYPE_FIELD_NAME (t, i), fieldname))
+ {
+ if (TYPE_FIELD_STATIC (t, i))
+ {
+ fieldno = i;
+ goto found;
+ }
+ else
+ error ("field `%s' is not static");
+ }
+ t = TYPE_BASECLASSES (t) ? TYPE_BASECLASS (t, 1) : 0;
+ }
+
+ t = type;
+
+ if (destructor_name_p (fieldname, t))
+ error ("use `info method' command to print out value of destructor");
+
+ while (t)
+ {
+ int i, j;
+
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; i--)
+ {
+ if (! strcmp (TYPE_FN_FIELDLIST_NAME (t, i), fieldname))
+ {
+ error ("use `info method' command to print value of method \"%s\"", fieldname);
+ }
+ }
+ t = TYPE_BASECLASSES (t) ? TYPE_BASECLASS (t, 1) : 0;
+ }
+ error("there is no field named %s", fieldname);
+ }
+
+ found:
+
+ sym = lookup_symbol (TYPE_FIELD_STATIC_PHYSNAME (type, fieldno),
+ 0, VAR_NAMESPACE, 0);
+ if (! sym) error ("Internal error: could not find physical static variable named %s", TYPE_FIELD_BITSIZE (type, fieldno));
+
+ type = TYPE_FIELD_TYPE (type, fieldno);
+ v = value_at (type, (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym));
+ return v;
+}
+
+long
+unpack_field_as_long (type, valaddr, fieldno)
+ struct type *type;
+ char *valaddr;
+ int fieldno;
+{
+ long val;
+ int bitpos = TYPE_FIELD_BITPOS (type, fieldno);
+ int bitsize = TYPE_FIELD_BITSIZE (type, fieldno);
+
+ bcopy (valaddr + bitpos / 8, &val, sizeof val);
+
+ /* Extracting bits depends on endianness of the target machine. */
+#ifdef BITS_BIG_ENDIAN
+ val = val >> (sizeof val * 8 - bitpos % 8 - bitsize);
+#else
+ val = val >> (bitpos % 8);
+#endif
+
+ val &= (1 << bitsize) - 1;
+ return val;
+}
+
+void
+modify_field (addr, fieldval, bitpos, bitsize)
+ char *addr;
+ int fieldval;
+ int bitpos, bitsize;
+{
+ long oword;
+
+ bcopy (addr, &oword, sizeof oword);
+
+ /* Shifting for bit field depends on endianness of the target machine. */
+#ifdef BITS_BIG_ENDIAN
+ bitpos = sizeof oword * 8 - bitpos - bitsize;
+#endif
+
+ oword &= ~(((1 << bitsize) - 1) << bitpos);
+ oword |= fieldval << bitpos;
+ bcopy (&oword, addr, sizeof oword);
+}
+
+/* Convert C numbers into newly allocated values */
+
+value
+value_from_long (type, num)
+ struct type *type;
+ register LONGEST num;
+{
+ register value val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ if (code == TYPE_CODE_INT || code == TYPE_CODE_ENUM)
+ {
+ if (len == sizeof (char))
+ * (char *) VALUE_CONTENTS (val) = num;
+ else if (len == sizeof (short))
+ * (short *) VALUE_CONTENTS (val) = num;
+ else if (len == sizeof (int))
+ * (int *) VALUE_CONTENTS (val) = num;
+ else if (len == sizeof (long))
+ * (long *) VALUE_CONTENTS (val) = num;
+#ifdef LONG_LONG
+ else if (len == sizeof (long long))
+ * (long long *) VALUE_CONTENTS (val) = num;
+#endif
+ else
+ error ("Integer type encountered with unexpected data length.");
+ }
+ else
+ error ("Unexpected type encountered for integer constant.");
+
+ return val;
+}
+
+value
+value_from_double (type, num)
+ struct type *type;
+ double num;
+{
+ register value val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ if (code == TYPE_CODE_FLT)
+ {
+ if (len == sizeof (float))
+ * (float *) VALUE_CONTENTS (val) = num;
+ else if (len == sizeof (double))
+ * (double *) VALUE_CONTENTS (val) = num;
+ else
+ error ("Floating type encountered with unexpected data length.");
+ }
+ else
+ error ("Unexpected type encountered for floating constant.");
+
+ return val;
+}
+
+/* Deal with the value that is "about to be returned". */
+
+/* Return the value that a function returning now
+ would be returning to its caller, assuming its type is VALTYPE.
+ RETBUF is where we look for what ought to be the contents
+ of the registers (in raw form). This is because it is often
+ desirable to restore old values to those registers
+ after saving the contents of interest, and then call
+ this function using the saved values.
+ struct_return is non-zero when the function in question is
+ using the structure return conventions on the machine in question;
+ 0 when it is using the value returning conventions (this often
+ means returning pointer to where structure is vs. returning value). */
+
+value
+value_being_returned (valtype, retbuf, struct_return)
+ register struct type *valtype;
+ char retbuf[REGISTER_BYTES];
+ int struct_return;
+{
+ register value val;
+
+ if (struct_return)
+ return value_at (valtype, EXTRACT_STRUCT_VALUE_ADDRESS (retbuf));
+
+ val = allocate_value (valtype);
+ EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS (val));
+
+ return val;
+}
+
+/* Return true if the function specified is using the structure returning
+ convention on this machine to return arguments, or 0 if it is using
+ the value returning convention. FUNCTION is the value representing
+ the function, FUNCADDR is the address of the function, and VALUE_TYPE
+ is the type returned by the function */
+
+struct block *block_for_pc ();
+
+int
+using_struct_return (function, funcaddr, value_type)
+ value function;
+ CORE_ADDR funcaddr;
+ struct type *value_type;
+{
+ register enum type_code code = TYPE_CODE (value_type);
+
+ if (code == TYPE_CODE_STRUCT ||
+ code == TYPE_CODE_ENUM ||
+ code == TYPE_CODE_ARRAY)
+ {
+ struct block *b = block_for_pc (funcaddr);
+
+ if (!(BLOCK_GCC_COMPILED (b) && TYPE_LENGTH (value_type) < 8))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Store VAL so it will be returned if a function returns now.
+ Does not verify that VAL's type matches what the current
+ function wants to return. */
+
+void
+set_return_value (val)
+ value val;
+{
+ register enum type_code code = TYPE_CODE (VALUE_TYPE (val));
+ char regbuf[REGISTER_BYTES];
+ double dbuf;
+ LONGEST lbuf;
+
+ if (code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION)
+ error ("Specifying a struct or union return value is not supported.");
+
+ if (code == TYPE_CODE_FLT)
+ {
+ dbuf = value_as_double (val);
+
+ STORE_RETURN_VALUE (VALUE_TYPE (val), &dbuf);
+ }
+ else
+ {
+ lbuf = value_as_long (val);
+ STORE_RETURN_VALUE (VALUE_TYPE (val), &lbuf);
+ }
+}
+
+void
+_initialize_values ()
+{
+ add_info ("convenience", convenience_info,
+ "Debugger convenience (\"$foo\") variables.\n\
+These variables are created when you assign them values;\n\
+thus, \"print $foo=1\" gives \"$foo\" the value 1. Values may be any type.\n\n\
+A few convenience variables are given values automatically GDB:\n\
+\"$_\"holds the last address examined with \"x\" or \"info lines\",\n\
+\"$__\" holds the contents of the last address examined with \"x\".");
+
+ add_info ("history", history_info,
+ "Elements of value history (around item number IDX, or last ten).");
+}
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d182 2
+a183 1
+ register int i;
+d185 6
+a190 3
+ /* Get error now if about to store an invalid float. */
+ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT)
+ value_as_double (val);
+d427 7
+a433 1
+ return unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val));
+d510 5
+d516 1
+a516 1
+unpack_double (type, valaddr)
+d519 1
+d525 1
+d528 4
+a531 2
+ if (INVALID_FLOAT (valaddr, len))
+ error ("Invalid floating value found in program.");
+a770 1
+ union { int i; char c; } test;
+d774 6
+a779 7
+ /* Extracting bits depends on endianness of the machine. */
+ test.i = 1;
+ if (test.c == 1)
+ /* Little-endian. */
+ val = val >> (bitpos % 8);
+ else
+ val = val >> (sizeof val * 8 - bitpos % 8 - bitsize);
+a791 1
+ union { int i; char c; } test;
+d795 4
+a798 5
+ /* Shifting for bit field depends on endianness of the machine. */
+ test.i = 1;
+ if (test.c != 1)
+ /* not little-endian: assume big-endian. */
+ bitpos = sizeof oword * 8 - bitpos - bitsize;
+@