From: K. Richard Pixley Date: Thu, 28 Mar 1991 16:28:29 +0000 (+0000) Subject: Johns release X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dd3b648e8b12ceb7bfce66e7f179b671403aea9c;p=binutils-gdb.git Johns release --- diff --git a/gdb/.gdbinit b/gdb/.gdbinit new file mode 100644 index 00000000000..bcacd5dc7e8 --- /dev/null +++ b/gdb/.gdbinit @@ -0,0 +1,15 @@ +echo Setting up the environment for debugging gdb.\n + +b fatal + +b info_command +commands + silent + return +end + +define rr + run +end + +set prompt (top-gdb) diff --git a/gdb/Convex.notes b/gdb/Convex.notes new file mode 100644 index 00000000000..28d336bfed8 --- /dev/null +++ b/gdb/Convex.notes @@ -0,0 +1,163 @@ + +@node Convex,,, Top +@appendix Convex-specific info +@cindex Convex notes + +Scalar registers are 64 bits long, which is a pain since +left half of an S register frequently contains noise. +Therefore there are two ways to obtain the value of an S register. + +@table @kbd +@item $s0 +returns the low half of the register as an int + +@item $S0 +returns the whole register as a long long +@end table + +You can print the value in floating point by using @samp{p/f $s0} or @samp{p/f $S0} +to print a single or double precision value. + +@cindex vector registers +Vector registers are handled similarly, with @samp{$V0} denoting the whole +64-bit register and @kbd{$v0} denoting the 32-bit low half; @samp{p/f $v0} +or @samp{p/f $V0} can be used to examine the register in floating point. +The length of the vector registers is taken from @samp{$vl}. + +Individual elements of a vector register are denoted in the obvious way; +@samp{print $v3[9]} prints the tenth element of register @kbd{v3}, and +@samp{set $v3[9] = 1234} alters it. + +@kbd{$vl} and @kbd{$vs} are int, and @kbd{$vm} is an int vector. +Elements of @kbd{$vm} can't be assigned to. + +@cindex communication registers +@kindex info comm-registers +Communication registers have names @kbd{$C0 .. $C63}, with @kbd{$c0 .. $c63} +denoting the low-order halves. @samp{info comm-registers} will print them +all out, and tell which are locked. (A communication register is +locked when a value is sent to it, and unlocked when the value is +received.) Communication registers are, of course, global to all +threads, so it does not matter what the currently selected thread is. +@samp{info comm-reg @var{name}} prints just that one communication +register; @samp{name} may also be a communication register number +@samp{nn} or @samp{0xnn}. +@samp{info comm-reg @var{address}} prints the contents of the resource +structure at that address. + +@kindex info psw +The command @samp{info psw} prints the processor status word @kbd{$ps} +bit by bit. + +@kindex set base +GDB normally prints all integers in base 10, but the leading +@kbd{0x80000000} of pointers is intolerable in decimal, so the default +output radix has been changed to try to print addresses appropriately. +The @samp{set base} command can be used to change this. + +@table @code +@item set base 10 +Integer values always print in decimal. + +@item set base 16 +Integer values always print in hex. + +@item set base +Go back to the initial state, which prints integer values in hex if they +look like pointers (specifically, if they start with 0x8 or 0xf in the +stack), otherwise in decimal. +@end table + +@kindex set pipeline +When an exception such as a bus error or overflow happens, usually the PC +is several instructions ahead by the time the exception is detected. +The @samp{set pipe} command will disable this. + +@table @code +@item set pipeline off +Forces serial execution of instructions; no vector chaining and no +scalar instruction overlap. With this, exceptions are detected with +the PC pointing to the instruction after the one in error. + +@item set pipeline on +Returns to normal, fast, execution. This is the default. +@end table + +@cindex parallel +In a parallel program, multiple threads may be executing, each +with its own registers, stack, and local memory. When one of them +hits a breakpoint, that thread is selected. Other threads do +not run while the thread is in the breakpoint. + +@kindex 1cont +The selected thread can be single-stepped, given signals, and so +on. Any other threads remain stopped. When a @samp{cont} command is given, +all threads are resumed. To resume just the selected thread, use +the command @samp{1cont}. + +@kindex thread +The @samp{thread} command will show the active threads and the +instruction they are about to execute. The selected thread is marked +with an asterisk. The command @samp{thread @var{n}} will select thread @var{n}, +shifting the debugger's attention to it for single-stepping, +registers, local memory, and so on. + +@kindex info threads +The @samp{info threads} command will show what threads, if any, have +invisibly hit breakpoints or signals and are waiting to be noticed. + +@kindex set parallel +The @samp{set parallel} command controls how many threads can be active. + +@table @code +@item set parallel off +One thread. Requests by the program that other threads join in +(spawn and pfork instructions) do not cause other threads to start up. +This does the same thing as the @samp{limit concurrency 1} command. + +@item set parallel fixed +All CPUs are assigned to your program whenever it runs. When it +executes a pfork or spawn instruction, it begins parallel execution +immediately. This does the same thing as the @samp{mpa -f} command. + +@item set parallel on +One or more threads. Spawn and pfork cause CPUs to join in when and if +they are free. This is the default. It is very good for system +throughput, but not very good for finding bugs in parallel code. If you +suspect a bug in parallel code, you probably want @samp{set parallel fixed.} +@end table + +@subsection Limitations + +WARNING: Convex GDB evaluates expressions in long long, because S +registers are 64 bits long. However, GDB expression semantics are not +exactly C semantics. This is a bug, strictly speaking, but it's not one I +know how to fix. If @samp{x} is a program variable of type int, then it +is also type int to GDB, but @samp{x + 1} is long long, as is @samp{x + y} +or any other expression requiring computation. So is the expression +@samp{1}, or any other constant. You only really have to watch out for +calls. The innocuous expression @samp{list_node (0x80001234)} has an +argument of type long long. You must explicitly cast it to int. + +It is not possible to continue after an uncaught fatal signal by using +@samp{signal 0}, @samp{return}, @samp{jump}, or anything else. The difficulty is with +Unix, not GDB. + +I have made no big effort to make such things as single-stepping a +@kbd{join} instruction do something reasonable. If the program seems to +hang when doing this, type @kbd{ctrl-c} and @samp{cont}, or use +@samp{thread} to shift to a live thread. Single-stepping a @kbd{spawn} +instruction apparently causes new threads to be born with their T bit set; +this is not handled gracefully. When a thread has hit a breakpoint, other +threads may have invisibly hit the breakpoint in the background; if you +clear the breakpoint gdb will be surprised when threads seem to continue +to stop at it. All of these situations produce spurious signal 5 traps; +if this happens, just type @samp{cont}. If it becomes a nuisance, use +@samp{handle 5 nostop}. (It will ask if you are sure. You are.) + +There is no way in GDB to store a float in a register, as with +@kbd{set $s0 = 3.1416}. The identifier @kbd{$s0} denotes an integer, +and like any C expression which assigns to an integer variable, the +right-hand side is casted to type int. If you should need to do +something like this, you can assign the value to @kbd{@{float@} ($sp-4)} +and then do @kbd{set $s0 = $sp[-4]}. Same deal with @kbd{set $v0[69] = 6.9}. diff --git a/gdb/Makefile.dist b/gdb/Makefile.dist new file mode 100755 index 00000000000..7b4e3ce9fa8 --- /dev/null +++ b/gdb/Makefile.dist @@ -0,0 +1,506 @@ +##Copyright (C) 1989-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# Place to install binaries. +bindir=/usr/local/bin + +# System V: If you compile gdb with a compiler which uses the coff +# encapsulation feature (this is a function of the compiler used, NOT +# of the m-?.h file selected by config.gdb), you must make sure that +# the GNU nm is the one that is used by munch. + +# If you are compiling with GCC, make sure that either 1) You use the +# -traditional flag, or 2) You have the fixed include files where GCC +# can reach them. Otherwise the ioctl calls in inflow.c and readline.c +# will be incorrectly compiled. The "fixincludes" script in the gcc +# distribution will fix your include files up. +#CC=cc +#CC=gcc -traditional +GCC=gcc + +VPATH=$(srcdir) + +# It is also possible that you will need to add -I/usr/include/sys to the +# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which +# is where it should be according to Posix). + +YACC=bison -y +# YACC=yacc +SHELL=/bin/sh +MAKE=make + +# Set this up with gcc if you have gnu ld and the loader will print out +# line numbers for undefinded refs. +#CC-LD=gcc -static +CC-LD=${CC} + +# define this to be "gmalloc.o" if you want to use the gnu malloc routine +# (useful for debugging memory allocation problems in gdb). To use your +# system malloc, uncomment the following two lines. +#GNU_MALLOC = +#MALLOC_CFLAGS = -DNO_MALLOC_CHECK +GNU_MALLOC = gmalloc.o mcheck.o +MALLOC_CFLAGS = + +# Where is the "include" directory? Traditionally ../include or ./include +INCLUDE_DIR = ${srcdir}/../include +INCLUDE_DEP = $$(INCLUDE_DIR) + +# Where is the BFD library? Traditionally ../bfd or ./bfd +BFD_DIR = ${srcdir}/../bfd +BFD_DEP = $$(BFD_DIR) + +# All the includes used for CFLAGS and for lint. +# -I. for config files. +# -I${srcdir} for , possibly regex.h also. +INCLUDE_CFLAGS = -I. -I${srcdir} -I$(INCLUDE_DIR) -I${srcdir}/vx-share + +# {X,T}M_CFLAGS, if defined, has system-dependent CFLAGS. +# CFLAGS for both GDB and readline. +GLOBAL_CFLAGS = -g ${TM_CFLAGS} ${XM_CFLAGS} +#PROFILE_CFLAGS = -pg + +CFLAGS = ${GLOBAL_CFLAGS} ${PROFILE_CFLAGS} ${MALLOC_CFLAGS} ${INCLUDE_CFLAGS} +# None of the things in CFLAGS will do any harm, and on some systems +# (e.g. SunOS4) it is important to use the M_CFLAGS. +LDFLAGS = $(CFLAGS) + +# define this to be "obstack.o" if you don't have the obstack library installed +# so that the dependencies work right. +OBSTACK = obstack.o + +# Requires GNU getopt_long features. +GETOPT = getopt.o getopt1.o +# Where is the getopt directory? Traditionally ../getopt or ./getopt +GETOPT_DIR = ${srcdir}/../getopt +GETOPT_DEP = $$(GETOPT_DIR) + +# Flags that describe where you can find the termcap library. +# You may need to make other arrangements for USG. +TERMCAP = -ltermcap + +# You must define REGEX and REGEX1 on USG machines. +# If your sysyem is missing alloca(), or, more likely, it's there but +# it doesn't work, define ALLOCA & ALLOCA1 + +# {X,T}M_CLIBS, if defined, has system-dependent libs +# For example, -lPW for System V to get alloca(). +# FIXME STOPGAP FOR BFD LIBRARY: BFD stuff +CLIBS = ${TERMCAP} $(XM_CLIBS) ${TM_CLIBS} ${BFD_DIR}/libbfd.a +CDEPS = ${XM_CDEPS} ${TM_CDEPS} ${BFD_DIR}/libbfd.a + +ADD_FILES = ${OBSTACK} ${REGEX} ${ALLOCA} ${GNU_MALLOC} ${GETOPT} +ADD_DEPS = ${OBSTACK} ${REGEX1} ${ALLOCA1} ${GNU_MALLOC} ${GETOPT} + +VERSION = 3.94.2 +DIST=gdb-$(VERSION) + +LINT=/usr/5bin/lint +LINTFLAGS= + +# Source files in the main directory. +# Files which are included via a tconfig/* or xconfig/* file +# should *not* be specified here; they're in "ALLDEPFILES". +SFILES_MAINDIR = \ + blockframe.c breakpoint.c command.c core.c \ + environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \ + main.c printcmd.c \ + remote.c source.c stack.c symmisc.c symtab.c symfile.c \ + utils.c valarith.c valops.c valprint.c values.c expread.y \ + signame.c cplus-dem.c mem-break.c target.c inftarg.c \ + dbxread.c coffread.c \ + ieee-float.c + +# Source files in subdirectories (which will be handled separately by +# 'make gdb.tar.Z'). +# Files which are included via a tconfig/* or xconfig/* file +# should *not* be specified here; they're in "ALLDEPFILES". +SFILES_SUBDIR = \ + ${srcdir}/vx-share/dbgRpcLib.h \ + ${srcdir}/vx-share/ptrace.h \ + ${srcdir}/vx-share/reg.h \ + ${srcdir}/vx-share/vxTypes.h \ + ${srcdir}/vx-share/vxWorks.h \ + ${srcdir}/vx-share/wait.h \ + ${srcdir}/vx-share/xdr_ld.h \ + ${srcdir}/vx-share/xdr_ptrace.h \ + ${srcdir}/vx-share/xdr_rdb.h \ + ${srcdir}/vx-share/xdr_regs.h \ + ${srcdir}/nindy-share/Makefile \ + ${srcdir}/nindy-share/VERSION \ + ${srcdir}/nindy-share/b.out.h \ + ${srcdir}/nindy-share/block_io.h \ + ${srcdir}/nindy-share/coff.h \ + ${srcdir}/nindy-share/demux.h \ + ${srcdir}/nindy-share/env.h \ + ${srcdir}/nindy-share/stop.h \ + ${srcdir}/nindy-share/ttycntl.h + +# All source files that go into linking GDB, except config-specified files. +SFILES = $(SFILES_MAINDIR) $(SFILES_SUBDIR) + +# All source files that lint should look at +LINTFILES = $(SFILES) expread.tab.c init.c + +# Any additional files specified on these lines should also be added to +# the OTHERS = definition below, so they go in the tar files. +SFILES_STAND = $(SFILES) standalone.c +SFILES_KGDB = $(SFILES) stuff.c kdb-start.c + +# Header files that are not named in tconfig/* or xconfig/* go here. +HFILES= breakpoint.h command.h defs.h environ.h \ + expression.h frame.h gdbcmd.h gdbcore.h \ + getpagesize.h ieee-float.h inferior.h param-no-tm.h param.h \ + signals.h signame.h symfile.h symtab.h \ + target.h tdesc.h terminal.h tm-68k.h tm-i960.h tm-sunos.h \ + value.h + +OPCODES = pn-opcode.h np1-opcode.h sparc-opcode.h vax-opcode.h m68k-opcode.h \ + ns32k-opcode.h convex-opcode.h pyr-opcode.h mips-opcode.h \ + am29k-opcode.h + +REMOTE_EXAMPLES = remote-sa.m68k.shar remote-multi.shar + +MALLOCSRC = gmalloc.c mcheck.c ansidecl.h stdlib.h gmalloc.h stddef.h +GETOPTSRC = $(GETOPT_DIR)/getopt.c $(GETOPT_DIR)/getopt1.c + +POSSLIBS_MAINDIR = obstack.h obstack.c regex.c regex.h alloca.c \ + $(MALLOCSRC) +POSSLIBS = $(POSSLIBS_MAINDIR) $(GETOPTSRC) + +TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c + +# tdesc-lib cannot be named simply tdesc, because if if it were GNU make +# would try to make it from tdesc.c. +# tdesc-lib removed from the list due to Motorola copyrights...gnu@cygnus.com +OTHERS = Makefile.dist depend alldeps.mak Makefile.srcdir \ + createtags munch config.gdb config.status \ + ChangeLog ChangeLog-3.x \ + README TODO TAGS WHATS.NEW \ + gdb.texinfo gdb-int.texinfo gdbrc.tex threecol.tex \ + .gdbinit COPYING expread.tab.c stab.def \ + copying.c Projects Convex.notes copying.awk \ + saber.suppress standalone.c stuff.c kdb-start.c \ + hp-include # tests + +DEPFILES= ${TDEPFILES} ${XDEPFILES} + +SOURCES=$(SFILES) $(ALLDEPFILES) +TAGFILES = $(SOURCES) ${HFILES} ${OPCODES} ${ALLPARAM} ${POSSLIBS} +TAGFILES_MAINDIR = $(SFILES_MAINDIR) $(ALLDEPFILES_MAINDIR) \ + ${HFILES} ${OPCODES} ${ALLPARAM} ${POSSLIBS_MAINDIR} +TARFILES = ${TAGFILES_MAINDIR} ${OTHERS} ${REMOTE_EXAMPLES} + +OBS = main.o blockframe.o breakpoint.o findvar.o stack.o source.o \ + values.o eval.o valops.o valarith.o valprint.o printcmd.o \ + symtab.o symfile.o symmisc.o infcmd.o infrun.o remote.o \ + command.o utils.o expread.o expprint.o environ.o version.o \ + copying.o $(DEPFILES) signame.o cplus-dem.o mem-break.o target.o \ + inftarg.o ieee-float.o \ + dbxread.o coffread.o # mipsread.o + +RAPP_OBS = rgdb.o rudp.o rserial.o serial.o udp.o $(XDEPFILES) + +TSOBS = core.o inflow.o + +NTSOBS = standalone.o + +TSSTART = /lib/crt0.o + +NTSSTART = kdb-start.o + +RL_LIB = readline/libreadline.a +RL_LIB_DEP = $(RL_LIB) + +# Prevent Sun make from putting in the machine type. Setting +# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1. +.c.o: + ${CC} -c ${CFLAGS} $< + +all: gdb + +install: gdb + cp gdb $(bindir)/gdb.new + mv $(bindir)/gdb.new $(bindir)/gdb + $(M_INSTALL) + +init.c: $(srcdir)/munch $(MUNCH_DEFINE) $(OBS) $(TSOBS) + $(srcdir)/munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) > init.c + +gdb: $(OBS) $(TSOBS) ${ADD_DEPS} ${RL_LIB_DEP} ${CDEPS} init.o + ${CC-LD} $(LDFLAGS) -o gdb init.o $(OBS) $(TSOBS) $(ADD_FILES) \ + ${RL_LIB} $(CLIBS) + +saber_gdb: $(SFILES) $(GETOPTSRC) $(DEPFILES) copying.c obstack.c version.c + #setopt load_flags $(CFLAGS) -I$(BFD_DIR) + #load ./init.c $(SFILES) + #unload ${srcdir}/expread.y + #load ${srcdir}/expread.tab.c readline/libreadline.a + #load copying.c version.c + #load obstack.c $(GETOPTSRC) + #load `echo " "$(DEPFILES) | sed -e 's/\.o/.c/g' -e 's, , ../,g'` + #load ${BFD_DIR}/libbfd.a -ltermcap + ##void mcheck(a) void (*a)(); { } + + + +# This is useful when debugging GDB, because some Unix's don't let you run GDB +# on itself without copying the executable. So "make gdb1" will make +# gdb and put a copy in gdb1, and you can run it with "gdb gdb1". +# Removing gdb1 before the copy is the right thing if gdb1 is open +# in another process. +gdb1: gdb + rm -f gdb1 + cp gdb gdb1 + +# This is a remote stub which runs under unix and starts up an +# inferior process. This is at least useful for debugging GDB's +# remote support. +rapp: $(RAPP_OBS) + rm -f rapp_init.c + ${srcdir}/munch ${RAPP_OBS} > rapp_init.c + ${CC-LD} $(LDFLAGS) -o $@ rapp_init.c $(RAPP_OBS) + +Makefiles= Makefile.srcdir $(M_MAKEFILE) \ + ${srcdir}/alldeps.mak ${srcdir}/Makefile.dist + +MAKE_MAKEFILE= echo "M_MAKEFILE=$(M_MAKEFILE)" | \ + cat - ${Makefiles} ${srcdir}/depend >Makefile + +Makefile: $(Makefiles) + $(MAKE_MAKEFILE) + +alldeps.mak: ${srcdir}/tconfig ${srcdir}/xconfig + rm -f alldeps.mak alldeps.tmp allparam.tmp allconfig.tmp + for i in `ls -d ${srcdir}/tconfig/*[0-9A-Za-z] \ + ${srcdir}/xconfig/*[0-9A-Za-z] | grep -v RCS` ; do \ + echo $$i >>allconfig.tmp; \ + awk <$$i ' \ + $$1 == "TDEPFILES=" || $$1 == "XDEPFILES=" { \ + for (i = 2; i <= NF; i++) \ + print $$i >> "alldeps.tmp" ; \ + } \ + $$1 == "TM_FILE=" || $$1 == "XM_FILE=" { \ + print $$2 >> "allparam.tmp" }' ; \ + done + sort alldeps2.tmp + echo 'ALLDEPFILES = $$(ALLDEPFILES_MAINDIR) $$(ALLDEPFILES_SUBDIR)' \ + >>alldeps.mak; + grep -v / alldeps2.tmp | \ + awk 'BEGIN {printf "ALLDEPFILES_MAINDIR="} \ + NR == 0 {printf $$0;} \ + NR != 0 {printf "\\\n" $$0} \ + END {printf "\n\n"}' >>alldeps.mak; + grep / alldeps2.tmp | \ + awk 'BEGIN {printf "ALLDEPFILES_SUBDIR="} \ + NR == 0 {printf $$0;} \ + NR != 0 {printf "\\\n" $$0} \ + END {printf "\n\n"}' >>alldeps.mak; + sort >alldeps.mak; + sort >alldeps.mak; + rm -f alldeps.tmp alldeps2.tmp allparam.tmp allconfig.tmp + +# The sed script makes everything which depends on {x,t}m.h depend on +# config.status as well, in case someone reconfigures gdb out from +# under an already compiled gdb. +depend: $(SOURCES) Makefile.dist + @echo Ignore errors about non-existent system-supplied include files + @echo for systems other than the one you are using. + @echo "If xm.h and tm.h don't exist, the error messages saying so" + @echo can safely be ignored. + @echo Also ignore parse errors in valops.c, and any errors in + @echo arm-convert.s. + -$(GCC) -MM $(CFLAGS) -I$(BFD_DIR) \ + `ls $(SOURCES) | sort -u` >depend.tmp + depend + $(MAKE_MAKEFILE) + rm depend.tmp + +config.status: + @echo "You must configure gdb. Look at the README file for details." + @false + +# These are not generated by "make depend" because they only are there +# for some machines. +tm-isi.h tm-sun3.h tm-news.h tm-hp300bsd.h tm-altos.h : tm-68k.h +tm-hp300hpux.h tm-sun2.h tm-3b1.h : tm-68k.h +xm-news1000.h : xm-news.h +xm-i386-sv32.h : xm-i386.h +tm-i386gas.h: tm-i386.h +xm-sun4os4.h : xm-sparc.h +tm-sun4os4.h : tm-sparc.h + +kdb : $(NTSSTART) $(OBS) $(NTSOBS) ${ADD_DEPS} ${RL_LIB_DEP} + rm -f init.c + $(srcdir)/munch ${MUNCH_DEFINE} $(OBS) $(NTSOBS) > init.c + $(CC) $(LDFLAGS) -c init.c $(CLIBS) + ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o $(ADD_FILES) \ + ${RL_LIB} -lc $(CLIBS) + +# Put the proper machine-specific files first. +# createtags will edit the .o in DEPFILES into .c +TAGS: ${TAGFILES} + $(srcdir)/createtags $(TM_FILE) ${XM_FILE} $(DEPFILES) ${TAGFILES} +tags: TAGS + +# FIXME: Get alldeps.mak up to date, config.gdb none, THEN make gdb.tar.Z! +gdb.tar.Z: ${TARFILES} + rm -f gdb.tar; rm -rf $(DIST) + cd readline ; make readline.tar + mkdir $(DIST) + cd $(DIST) ; for i in ${TARFILES} ; do ln -s ../$$i . ; done + mkdir $(DIST)/readline + cd $(DIST)/readline ; tar xf ../../readline/readline.tar + mkdir $(DIST)/xconfig ${DIST}/tconfig + cd $(DIST)/tconfig ; \ + for i in $(ALLCONFIG) ; do ln -s ../../$$i ../$$i ; done + mkdir $(DIST)/vx-share $(DIST)/nindy-share + cd $(DIST)/tconfig ; \ + for i in $(SFILES_SUBDIR) $(ALLDEPFILES_SUBDIR); \ + do ln -s ../../$$i ../$$i ; done + tar chf - $(DIST) | compress >gdb.tar.Z + rm -rf $(DIST) + +clean: + rm -f ${OBS} ${TSOBS} ${NTSOBS} ${ADD_FILES} + rm -f init.c init.o version.c + rm -f gdb core gdb.tar gdb.tar.Z make.log + rm -f gdb[0-9] + cd readline ; make clean + +distclean: clean expread.tab.c TAGS + rm -f tm.h xm.h config.status + rm -f y.output yacc.acts yacc.tmp + rm -f ${TESTS} Makefile + +realclean: clean + rm -f expread.tab.c TAGS + rm -f tm.h xm.h config.status + rm -f Makefile + +gdb.dvi : gdb.texinfo + tex gdb.texinfo + texindex gdb.?? + tex gdb.texinfo + +# Make copying.c from COPYING +copying.c : COPYING copying.awk + awk -f copying.awk < COPYING > copying.c + +version.c : Makefile.dist + echo 'char *version = "$(VERSION)";' >version.c + +${srcdir}/expread.tab.c : $(srcdir)/expread.y + @echo 'Expect 4 shift/reduce conflict.' + ${YACC} $(srcdir)/expread.y + mv y.tab.c ${srcdir}/expread.tab.c + +expread.o : ${srcdir}/expread.tab.c defs.h param.h symtab.h \ + frame.h expression.h + $(CC) -c ${CFLAGS} `echo ${srcdir}/expread.tab.c | sed 's,^\./,,'` + mv expread.tab.o expread.o + +# dbxread, coffread, mipsread have dependencies on BFD header files. +dbxread.o: ${srcdir}/dbxread.c + ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/dbxread.c + +coffread.o: ${srcdir}/coffread.c + ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/coffread.c + +mipsread.o: ${srcdir}/mipsread.c + ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/mipsread.c + +# Drag in the files that are in another directory. + +getopt1.o: $(GETOPT_DIR)/getopt1.c + ${CC} -c ${CFLAGS} $(GETOPT_DIR)/getopt1.c + +getopt.o: $(GETOPT_DIR)/getopt.c + ${CC} -c ${CFLAGS} $(GETOPT_DIR)/getopt.c + +xdr_ld.o: ${srcdir}/vx-share/xdr_ld.c + ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_ld.c + +xdr_ptrace.o: ${srcdir}/vx-share/xdr_ptrace.c + ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_ptrace.c + +xdr_rdb.o: ${srcdir}/vx-share/xdr_rdb.c + ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_rdb.c + +xdr_regs.o: ${srcdir}/vx-share/xdr_regs.c + ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_regs.c + +nindy.o: ${srcdir}/nindy-share/nindy.c + ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/nindy.c + +Onindy.o: ${srcdir}/nindy-share/Onindy.c + ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/Onindy.c + +ttybreak.o: ${srcdir}/nindy-share/ttybreak.c + ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/ttybreak.c + +ttyflush.o: ${srcdir}/nindy-share/ttyflush.c + ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/ttyflush.c + +tdesc-lib/libdc.o : force_update + cd tdesc-lib ; ${MAKE} "SYSV_DEFINE=${SYSV_DEFINE}" + +# In LOCAL_INCLUDES, -I${srcdir} is right if srcdir is an absolute path, +# and -I../${srcdir} is right if it is relative (e.g. ".."), so search both. +readline/libreadline.a : force_update + cd readline ; ${MAKE} "SYSV=${SYSV_DEFINE}"\ + "VPATH=${srcdir}/readline:../${srcdir}/readline"\ + "LOCAL_INCLUDES=-I../ -I${srcdir}/ -I../${srcdir}/"\ + "DEBUG_FLAGS=${GLOBAL_CFLAGS}" "CC=${CC}" libreadline.a + +lint: $(LINTFILES) + $(LINT) $(INCLUDE_CFLAGS) $(LINTFLAGS) $(LINTFILES) + +gdb.cxref: $(SFILES) + cxref -I. $(SFILES) >gdb.cxref + +force_update : + +# When used with GDB, the demangler should never look for leading underscores +# because GDB strips them off during symbol read-in. Thus -Dnounderscore. +cplus-dem.o : cplus-dem.c + ${CC} -c -Dnounderscore `echo ${srcdir}/cplus-dem.c | sed 's,^\./,,'` diff --git a/gdb/Makefile.srcdir b/gdb/Makefile.srcdir new file mode 100755 index 00000000000..b5fb6b3f64f --- /dev/null +++ b/gdb/Makefile.srcdir @@ -0,0 +1 @@ +srcdir=. diff --git a/gdb/Projects b/gdb/Projects new file mode 100644 index 00000000000..b30d268ea62 --- /dev/null +++ b/gdb/Projects @@ -0,0 +1,97 @@ + + Suggested projects for aspiring or current GDB hackers + ====================================================== + + (You should probably chat with bug-gdb@cygnus.com to make sure that + no one else is doing the project you chose). + +Rewrite proceed, wait_for_inferior, and normal_stop to clean them up. +Suggestions: + + 1) Make each test in wait_for_inferior a seperate subroutine + call. + 2) Combine wait_for_inferior and normal_stop to clean up + communication via global variables. + 3) See if you can find some way to clean up the global + variables that are used; possibly group them by data flow + and information content? + +Work out some kind of way to allow running the inferior to be done as +a sub-execution of, eg. breakpoint command lists. Currently running +the inferior interupts any command list execution. This would require +some rewriting of wait_for_inferior & friends, and hence should +probably be done in concert with the above. + +Add function arguments to gdb user defined functions. + +Add convenience variables that refer to exec file, symbol file, +selected frame source file, selected frame function, selected frame +line number, etc. + +Add a "suspend" subcommand of the "continue" command to suspend gdb +while continuing execution of the subprocess. Useful when you are +debugging servers and you want to dodge out and initiate a connection +to a server running under gdb. + +Work out and implement a reasonably general mechanism for multi-threaded +processies. There are parts of one implemented in convex-dep.c, if +you want an example. + +Add stab information to allow reasonable debugging of inline functions +(possibly they should show up on a stack backtrace? With a note +indicating that they weren't "real"?). + +Implement support for specifying arbitrary locations of stack frames +(in practice, this usually requires specification of both the top and +bottom of the stack frame (fp and sp), since you *must* retrieve the +pc that was saved in the innermost frame). + +Modify the naked "until" command to step until past the current source +line, rather than past the current pc value. This is tricky simply +because the low level routines have no way of specifying a multi-line +step range, and there is no way of saying "don't print stuff when we +stop" from above (otherwise could just call step many times). + +Modify the handling of symbols grouped through BINCL/EINCL stabs to +allocate a partial symtab for each BINCL/EINCL grouping. This will +seriously decrease the size of inter-psymtab dependencies and hence +lessen the amount that needs to be read in when a new source file is +accessed. + +Do an "x/i $pc" after each stepi or nexti. + +Modify all of the disassemblers to use printf_filtered to get correct +more filtering. + +Modify gdb to work correctly with Pascal. + +Rewrite macros that handle frame chaining and frameless functions. +They should be able to tell the difference between start, main, and a +frameless function called from main. + +Work out what information would need to be included in an executable +by the compiler to allow gdb to debug functions which do not have a +frame pointer. Modify gdb and gcc to do this. + +When `attached' to a program (via either OS support or remote +debugging), gdb should arrange to catch signals which the terminal +might send, as it is unlikely that the program will be able to notice +them. SIGINT and SIGTSTP are obvious examples. + +Enhance the gdb manual with extra examples where needed. + +Arrange for list_command not to use decode_line_1 and thus not require +symbols to be read in simply to read a source file. + +Allow patching of executables, a la "adb -w". + +Improve the target interface so that targets can be stacked; e.g. an +exec file and a core file (memory references that the core file can't +satisfy are directed to the exec file); those two plus a child process. +The child doesn't let any refs through, but when the child terminates, +you are back to debugging the core file -- you might even want to swap +back and forth between the two, or between two core files. + +# Local Variables: +# mode: text +# End: diff --git a/gdb/TODO b/gdb/TODO new file mode 100644 index 00000000000..93dce626fe0 --- /dev/null +++ b/gdb/TODO @@ -0,0 +1,325 @@ + + gdb bug list + John Gilmore, gnu@cygnus.com + +This bug list is probably not up to date or accurate, but it reflects +some known bugs in gdb, if you are into bug-hunting. + + +Update the TODO list with all the lists of gdb bugs lying around on paper. + +"share" command should not need to be manually run. It should be run +as soon as possible, automatically, both on "run" and on core files. + +It should be possible to use symbols from shared libraries before we know +exactly where the libraries will be loaded. E.g. "b perror" before running +the program. This could maybe be done as an extension of the "breakpoint +re-evaluation" after new symbols are loaded. + +Make single_step() insert and remove breakpoints in one operation. + +Speed up single stepping by avoiding extraneous ptrace calls. + +Speed up single stepping by not inserting and removing breakpoints +each time the inferior starts and stops. + +Speed up watchpoints by not single-stepping them, but do something +faster like single-line execution. + +Update gdb.texinfo to include doc on the directory structure and +the various tricks of building gdb. + +Do a tutorial in gdb.texinfo on how to do simple things in gdb. +E.g. how to set a breakpoint that just prints something and continues. +How to break on aborts. Etc. + +Do a "new features" section for release 4. + +Provide "voodoo" debugging of core files. This creates a zombie +process as a child of the debugger, and loads it up with the data, +stack, and regs of the core file. This allows you to call functions +in the executable, to manipulate the data in the core file. + +GDB reopens the source file on every line, as you "next" through it. + +Referencing the vtbl member of a struct doesn't work. It prints OK +if you print the struct, but it gets 0 if you try to deref it. + +Persistent command history: A feature where you could save off a list +of the commands you did, so you can edit it into something that will bring +the target to the same place every time you source it. Sun wants it. +This would also be useful for automated fast watchpointing; if you go +past the place where it watchpoints, you just start it over again and +do it more carefully. + +Deal with the Sun ptrace bug that loses the registers if the stack is +paged out. + +Finish the C++ exception handling stub routines. Lint points them out +as unused statics functions. + +"i source" only shows you info about files that it can read. When it +can't read a file and complains, you can't see any info about it, like +where it was compiled. Perhaps "i source" should take an argument +like that of "list". + +See if coredep.c's fetch_core_registers can be used on more machines. +E.g. MIPS (mips-xdep.c). + +coredep.c is completely broken. Needs work just to compile, it uses +"u" and doesn't declare it, etc. + +unpack_double() does not handle IEEE float on the target unless the host +is also IEEE. Death on a vax. + +Test cross-debugging Unix-to-Unix. + +Check the RAPP remote protocol. What is it? It's in Makefile.dist +and one ChangeLog entry. + +Set up interface between GDB and INFO so that you can hop into interactive +INFO and back out again. When running under Emacs, should use Emacs +info, else fork the info program. Installation of GDB should install +its texinfo files into the info tree automagically, including the readline +texinfo files.. + +Improve backtrace output to avoid line wraps. Prettify it. + +"help address" ought to find the "help set addressprint" entry. + +Remove the VTBL internal guts from printouts of C++ structs, unless +vtblprint is set. + +Remove "at 0xnnnn" from the "b foo" response, if !addressprint and if +it matches the source line indicated. + +The prompt at end of screen should accept space as well as CR. + +"List" should put you into a pseudo-"more" where you can hit space +to get more, forever to eof. + +Check STORE_RETURN_VALUE on all architectures. Check near it in tm-sparc.h +for other bogosities. + +Check for storage leaks in GDB, I'm sure there are a lot! + +vtblprint of a vtbl should demangle the names it's printing. + +Backtrace should point out what the currently selected frame is, in its +display, perhaps showing ">3 foo (bar, ...)" rather than "#3 foo (bar, ...)". + +"i program" should work for core files, and display more info, like what +actually caused it to die. + +Hitting ^Z to an inferior doesn't work right, it takes several continues +to make it actually go. + +"i fun" doesn't show misc function vector symbols. + +"x/10i" should shorten the long name, if any, on subsequent lines. + +Check through the code for FIXME comments and fix them. dbxread.c, +blockframe.c, and plenty more. + +"next" over a function that longjumps, never stops until next time you happen +to get to that spot by accident. E.g. "n" over execute_command which has +an error. + +Watchpoints seem not entirely reliable. + +"set zeroprint off", don't bother printing members of structs which are entirely +zero. Useful for those big structs with few useful members. + +GDB does four ioctl's for every command, probably switching terminal modes +to/from inferior or for readline or something. + +terminal_ours versus terminal_inferior: cache state. Switch should be a noop +if the state is the same, too. + +ptype $i6 = void??! + +Clean up invalid_float handling so gdb doesn't coredump when it tries to +access a NaN. While this might work on SPARC, other machines are not +configured right. + +"b value_at ; commands ; continue ; end" stops EVERY OTHER TIME! +Then once you enter a command, it does the command, runs two more +times, and then stops again! Bizarre... (This behaviour has been +modified, but it is not yet 100% predictable when e.g. the commands +call functions in the child, and while there, the child is interrupted +with a signal, or hits a breakpoint.) + +Symbol completion with TAB does not unmangle names! + +help completion, help history should work. + +Symbol completion doesn't handle e.g. W::f. (symtab.c, +make_symbol_completion_list). + +AMD version: ^C should do ^Ak to stop ebmon. + +Check that we can handle stack trace through varargs AND alloca in same +function, on 29K. + +wait_for_inferior loops forever if wait() gives it an error. + +"i frame" arg formatting sucks. Should wrap lines. +"bt" arg formatting needs the same treatment . + +"i frame" shows wrong "arglist at" location, doesn't show where the args +should be found, only their actual values. + +Symbolic display of addrs, (& disassembly prefixes), don't show static +fns, e.g. enable_command in gdb. + +'ptype yylval' ==> "union YYSTYPE { ..... }". However, it is not a +union YYSTYPE, but is simply a YYSTYPE, which is a typedef for an +unnamed union. + +"show all" should work. + +There should be a way for "set" commands to validate the new setting +before it takes effect. + +The "display" command should become the "always" command, e.g. + "always print XXX" + "always p/xxx XXX" + "always echo foo" + "always call XXX" + "always x/i $pc", etc. + +A mess of floating point opcodes are missing from sparc-opcode.h. +Also, a little program should test the table for bits that are +overspecified or underspecified. E.g. if the must-be-ones bits +and the must-be-zeroes bits leave some fields unexamined, and the format +string leaves them unprinted, then point this out. If multiple +non-alias patterns match, point this out too. Finally, there should +be a sparc-optest.s file that tries each pattern out. This file +should end up coming back the same (modulo transformation comments) +if fed to "gas" then the .o is fed to gdb for disassembly. + +Merge the xxx-opcode.h files with gas again... + +Eliminate all the core_file_command's in all the xdep files. +Eliminate separate declarations of registers[] everywhere. + +"ena d" is ambiguous, why? "ena delete" seems to think it is a command! + +Line numbers are off in some spots. In proceed() at 1st "oneproc = 1", +it seems to run that statement, but it doesn't actually. + +Perhaps the tdep and xdep files, and the tm and xm files, into a config +subdirectory. If not, at least straighten out their names so that +they all start with the machine name. + +inferior_status should include stop_print_frame. It won't need to be +reset in wait_for_inferior after bpstat_stop_status call, then. + +i line VAR produces "Line number not known for symbol ``var''.". I +thought we were stashing that info now! + +Make sure we can handle executables with no symbol info, e.g. /bin/csh. + +We should be able to write to executables that aren't running. + +We should be able to write to random files at hex offsets like adb. + +Tiemann: It is very painful to look at fp registers that hold +double precision values. GDB is happy to show them to you as single +precision, but you cannot look at them as doubles. Perhaps casting +should be changed to make this work; or maybe a new "set" option that +sets the default fp precision to single, double, or quad. This is not +urgent, but would be nice to get into GDB 4.0. + +Make "target xxx" command interruptible. + +Handle add_file with separate text, data, and bss addresses. Maybe +handle separate addresses for each segment in the object file? + +Handle free_named_symtab to cope with multiply-loaded object files +in a dynamic linking environment. Should remember the last copy loaded, +but not get too snowed if it finds references to the older copy. + +Implement have_memory, have_stack, have_registers, have_execution. +Memory: core, exec, child, vxworks even without child. +stack: core, child, vxworks with child +registers: core, child, vxworks with child +execution: child, vxworks with child. + +The original BFD core dump reading routine would itself coredump when fed +a garbage file as a core file. Does the current one? + +Breakpoints should not be inserted and deleted all the time. Only the +one(s) there should be removed when we have to step over one. Support +breakpoints that don't have to be removed to step over them. + +Stop reading stop_registers! + +Generalize and Standardize the RPC interface to a target program, +improve it beyond the "ptrace" interface, and see if it can become a standard +for remote debugging. Is WRS interested in donating their target-end +code? + +Remove all references to: + text_offset + data_offset + text_data_start + text_end + exec_data_offset + ... +now that we have BFD. All remaining are in machine dependent files. + +When quitting with a running program, if a core file was previously +examined, you get "Couldn't read float regs from core file"...if +indeed it can't. generic_mourn_inferior... + +... + +Check signal argument to remote proceed's and error if set. + +Handle floating point registers in core files under BFD. Currently +they are punted. + +Sort help and info output. + +Re-organize help categories into things that tend to fit on a screen +and hang together. + +When trying to print source lines but you can't find the file, +print the file name and line number, and leave it selected anyway +so "i source" will show it. + +renote-nindy.c handles interrupts poorly; it error()s out of badly +chosen places, e.g. leaving current_frame zero, which causes core dumps +on the next command. + +Add in commands like ADB's for searching for patterns, etc. We should +be able to examine and patch raw unsymboled binaries as well in gdb as +we can in adb. (E.g. increase the timeout in /bin/login without source). + +Those xdep files that call register_addr without defining it are +probably simply broken. When reconfiguring this part of gdb, I could +only make guesses about how to redo some of those files, and I +probably guessed wrong, or left them "for later" when I have a +machine that can attempt to build them. + +Use the complain() mechanism for handling all the error() calls in dbxread.c, +and in similar situations in coffread.c and mipsread.c. + +When doing "step" or "next", if a few lines of source are skipped between +the previous line and the current one, print those lines, not just the +last line of a multiline statement. + +When searching for C++ superclasses in value_cast in valops.c, we must +not search the "fields", only the "superclasses". There might be a +struct with a field name that matches the superclass name. This can +happen when the struct was defined before the superclass (before the +name became a typedef). + +For "float point[15];": +ptype &point[4] ==> Attempt to take address of non-lvalue. +p &point[4] ==> Dereferences point[4] rather than giving you point+4. + +Fix symbol reading in the presence of interrupts. It currently leaves a +cleanup to blow away the entire symbol table when a QUIT occurs. + diff --git a/gdb/WHATS.NEW b/gdb/WHATS.NEW new file mode 100755 index 00000000000..97b0415ad23 --- /dev/null +++ b/gdb/WHATS.NEW @@ -0,0 +1,223 @@ + GDB 4.0 -- what has changed since 3.5? + + * New Facilities + +Gdb now paginates its output, with a ``more''-like interface. You can +set the screen width and screen height with new ``set'' commands; they +default to your terminal settings. Wide output is wrapped at good +places to make the output more readable. + +Gdb now reads its input via the ``readline'' interface. This provides +inline editing of commands, using familiar Emacs or VI commands (like +``tcsh'' or the korn shell); history substitutions a la the C shell; +and storage and recall of your command history across debugging +sessions. The default is Emacs mode; to switch temporarily to vi mode, +use control-meta-J or ESC control-j. You can switch permanently to vi +mode by putting the line ``set editing-mode vi'' in the file .inputrc +in your home directory. For full details, see the description in +readline/inc-readline.texinfo and readline/inc-history.texinfo. + +Gdb now supports cross-debugging from a host machine of one type to a +target machine of another type. Communication with the target system +is over serial lines. The ``target'' command handles connecting to the +remote system; the ``load'' command will download a program into the +remote system. It also supports debugging of realtime processes +running under VxWorks, using SunRPC Remote Procedure Calls over TCP/IP +to talk to a debugger stub on the target system. + +New CPUs supported include the AMD 29000 and Intel 960. + +GDB now reads object files and symbol tables via a ``binary file'' +library, which allows a single copy of GDB to debug programs of multiple +object file types such as a.out and coff. + +There is now a GDB reference card in "gdbrc.tex". + + + * Control-Variable user interface simplified + +All variables that control the operation of the debugger can be set +by the ``set'' command, and displayed by the ``show'' command. + +For example, ``set prompt new-gdb=>'' will change your prompt to new-gdb=>. +``Show prompt'' produces the response: +Gdb's prompt is new-gdb=>. + +What follows are the NEW set commands. The command ``help set'' will +print a complete list of old and new set commands. ``help set FOO'' +will give a longer description of the variable FOO. + +caution on/off: Enables warning questions for operations that are + hard to recover from, e.g. rerunning the program while + it is already running. Default is ON. + +editing on/off: Enables EMACS style command line editing + of input. Previous lines can be recalled with + control-P, the current line can be edited with control-B, + you can search for commands with control-R, etc. + Default is ON. + +history filename NAME: NAME is where the gdb command history + will be stored. The default is .gdb_history, + or the value of the environment variable + GDBHISTFILE. + +history size N: The size, in commands, of the command history. The + default is 256, or the value of the environment variable + HISTSIZE. + +history write on/off: If this value is set to ON, the history file will + be saved after exiting gdb. If set to OFF, the + file will not be saved. The default is OFF. + +history expansion on/off: If this value is set to ON, then csh-like + history expansion will be performed on + command line input. The default is OFF. + +radix N: Sets the default radix for input and output. It can be set + to 8, 10, or 16. Note that the argument to "radix" is interpreted + in the current radix, so "set radix 10" is always a no-op. + +screen-height N: This integer value is the number of lines on a page. Default + is 24, the current `stty rows'' setting, or the ``li#'' + setting from the termcap entry matching the environment + variable TERM. + +screen-width N: This integer value is the number of characters on a line. + Default is 80, the current `stty cols'' setting, or the ``co#'' + setting from the termcap entry matching the environment + variable TERM. + +Note: ``set screensize'' is obsolete. Use ``set screen-height'' and +``set screen-width'' instead. + +addressprint on/off: Print memory addresses in various command displays, + such as stack traces and structure values. Gdb looks + more ``symbolic'' if you turn this off; it looks more + ``machine level'' with it on. Default is ON. + +arrayprint on/off: Prettyprint arrays. New convenient format! Default + is OFF. + +demangle on/off: Print C++ symbols in "source" form if on, "raw" form if off. + +asm-demangle on/off: Same, for assembler level printouts like instructions. + +vtblprint on/off: Prettyprint C++ virtual function tables. Default is OFF. + + + * Support for Epoch Environment. + +The epoch environment is a version of Emacs v18 with windowing. One +new command, ``inspect'', is identical to ``print'', except that if you +are running in the epoch environment, the value is printed in its own +window. + + + * Support for Shared Libraries + +GDB can now debug programs and core files that use SunOS shared libraries. +Symbols from a shared library cannot be referenced +before the shared library has been linked with the program (this +happens after you type ``run'' and before the function main() is entered). +At any time after this linking (including when examining core files +from dynamically linked programs), gdb reads the symbols from each +shared library when you type the ``sharedlibrary'' command. +It can be abbreviated ``share''. + +sharedlibrary REGEXP: Load shared object library symbols for files + matching a unix regular expression. No argument + indicates to load symbols for all shared libraries. + +info sharedlibrary: Status of loaded shared libraries. + + + * Watchpoints + +A watchpoint stops execution of a program whenever the value of an +expression changes. Checking for this slows down execution +tremendously whenever you are in the scope of the expression, but is +quite useful for catching tough ``bit-spreader'' or pointer misuse +problems. Some machines such as the 386 have hardware for doing this +more quickly, and future versions of gdb will use this hardware. + +watch EXP: Set a watchpoint (breakpoint) for an expression. + +info watchpoints: Information about your watchpoints. + +delete N: Deletes watchpoint number N (same as breakpoints). +disable N: Temporarily turns off watchpoint number N (same as breakpoints). +enable N: Re-enables watchpoint number N (same as breakpoints). + + + * C++ multiple inheritance + +When used with a GCC version 2 compiler, GDB supports multiple inheritance +for C++ programs. + + * C++ exception handling + +Gdb now supports limited C++ exception handling. Besides the existing +ability to breakpoint on an exception handler, gdb can breakpoint on +the raising of an exception (before the stack is peeled back to the +handler's context). + +catch FOO: If there is a FOO exception handler in the dynamic scope, + set a breakpoint to catch exceptions which may be raised there. + Multiple exceptions (``catch foo bar baz'') may be caught. + +info catch: Lists all exceptions which may be caught in the + current stack frame. + + + * Minor command changes + +The command ``call func (arg, arg, ...)'' now acts like the print +command, except it does not print or save a value if the function's result +is void. This is similar to dbx usage. + +The ``up'' and ``down'' commands now always print the frame they end up +at; ``up-silently'' and `down-silently'' can be used in scripts to change +frames without printing. + + * New directory command + +'dir' now adds directories to the FRONT of the source search path. +The path starts off empty. Source files that contain debug information +about the directory in which they were compiled can be found even +with an empty path; GCC includes this information. If GDB can't find +your source file in the current directory, type "dir .". + + * Features removed in this release + +``info types'' has been removed, since it printed builtin types in a +confusing fashion, and did not do useful things with typedefs. ``ptype'' +or ``whatis'' are more useful commands for dealing with types.. + + + * Configuring GDB for compilation + +For normal use, type ``config.gdb host''. Hosts now handled are: + +3b1 altos altosgas arm bigmips convex hp300bsd hp300hpux i386v i386v-g +i386v32 i386v32-g isi littlemips m88k merlin news news1000 none np1 pn +pyramid sun2os3 sun2os4 sun386 sun3os3 sun3os4 sun4os3 sun4os4 symmetry +umax vax + +Type config.gdb +host to get a full description of each host. + +You can now build gdb conveniently for several architectures from the +same sources. If config.gdb is run from a subdirectory, it configures +the Makefile to use source files from '..'. Each subdirectory can be +indpendently configured. An explicit source file directory can also +be specified with the +srcdir=xxx option. Due to obscure search rules +in the C preprocessor, if you have previously built gdb in the main +directory, run 'make cleanconfig' in the top level directory before +building it in a subdirectory. + +GDB now handles cross debugging. If you are remotely debugging between +two different machines, type ``config.gdb host target''. +Host is the machine where gdb will run; target is the machine +where the program that you are debugging will run. + +Type config.gdb +target to get a full description of each target. diff --git a/gdb/alldeps.mak b/gdb/alldeps.mak new file mode 100644 index 00000000000..73e6cb8c8c3 --- /dev/null +++ b/gdb/alldeps.mak @@ -0,0 +1,196 @@ +ALLDEPFILES = $(ALLDEPFILES_MAINDIR) $(ALLDEPFILES_SUBDIR) +ALLDEPFILES_MAINDIR=\ +altos-xdep.c\ +am29k-pinsn.c\ +am29k-tdep.c\ +arm-convert.s\ +arm-pinsn.c\ +arm-tdep.c\ +arm-xdep.c\ +convex-pinsn.c\ +convex-tdep.c\ +convex-xdep.c\ +coredep.c\ +exec.c\ +gould-pinsn.c\ +gould-xdep.c\ +hp300hpux-xdep.c\ +i386-pinsn.c\ +i386-tdep.c\ +i386-xdep.c\ +i960-pinsn.c\ +i960-tdep.c\ +infptrace.c\ +m68k-pinsn.c\ +m68k-tdep.c\ +mips-pinsn.c\ +mips-tdep.c\ +mips-xdep.c\ +mipsread.c\ +news-xdep.c\ +nindy-tdep.c\ +ns32k-pinsn.c\ +pyr-pinsn.c\ +pyr-tdep.c\ +pyr-xdep.c\ +remote-eb.c\ +remote-nindy.c\ +remote-vx.c\ +solib.c\ +sparc-pinsn.c\ +sparc-tdep.c\ +sparc-xdep.c\ +sun3-xdep.c\ +sun386-xdep.c\ +symmetry-tdep.c\ +symmetry-xdep.c\ +tdesc.c\ +umax-xdep.c\ +vax-pinsn.c + +ALLDEPFILES_SUBDIR=\ +nindy-share/Onindy.c\ +nindy-share/nindy.c\ +nindy-share/ttybreak.c\ +nindy-share/ttyflush.c\ +vx-share/xdr_ld.c\ +vx-share/xdr_ptrace.c\ +vx-share/xdr_rdb.c\ +vx-share/xdr_regs.c + +ALLPARAM=\ +tm-29k.h\ +tm-3b1.h\ +tm-88k.h\ +tm-altos.h\ +tm-altosgas.h\ +tm-arm.h\ +tm-bigmips.h\ +tm-convex.h\ +tm-hp300bsd.h\ +tm-hp300hpux.h\ +tm-i386v-g.h\ +tm-i386v.h\ +tm-isi.h\ +tm-merlin.h\ +tm-mips.h\ +tm-news.h\ +tm-nindy960.h\ +tm-np1.h\ +tm-pn.h\ +tm-pyr.h\ +tm-sparc.h\ +tm-sun2.h\ +tm-sun2os4.h\ +tm-sun3.h\ +tm-sun386.h\ +tm-sun3os4.h\ +tm-sun4os4.h\ +tm-symmetry.h\ +tm-umax.h\ +tm-vax.h\ +tm-vxworks68.h\ +tm-vxworks960.h\ +xm-3b1.h\ +xm-88k.h\ +xm-altos.h\ +xm-arm.h\ +xm-bigmips.h\ +xm-convex.h\ +xm-hp300bsd.h\ +xm-hp300hpux.h\ +xm-i386v.h\ +xm-i386v32.h\ +xm-isi.h\ +xm-merlin.h\ +xm-mips.h\ +xm-news.h\ +xm-news1000.h\ +xm-np1.h\ +xm-pn.h\ +xm-pyr.h\ +xm-sparc.h\ +xm-sun2.h\ +xm-sun3.h\ +xm-sun386.h\ +xm-sun3os4.h\ +xm-sun4os4.h\ +xm-symmetry.h\ +xm-umax.h\ +xm-vax.h + +ALLCONFIG=\ +./tconfig/3b1\ +./tconfig/altos\ +./tconfig/altosgas\ +./tconfig/am29k\ +./tconfig/arm\ +./tconfig/bigmips\ +./tconfig/convex\ +./tconfig/hp300bsd\ +./tconfig/hp300hpux\ +./tconfig/i386v\ +./tconfig/i386v-g\ +./tconfig/i386v32\ +./tconfig/i386v32-g\ +./tconfig/i960\ +./tconfig/isi\ +./tconfig/littlemips\ +./tconfig/m88k\ +./tconfig/merlin\ +./tconfig/news\ +./tconfig/news1000\ +./tconfig/nindy960\ +./tconfig/none\ +./tconfig/np1\ +./tconfig/pn\ +./tconfig/pyramid\ +./tconfig/sun2os3\ +./tconfig/sun2os4\ +./tconfig/sun3\ +./tconfig/sun386\ +./tconfig/sun3os3\ +./tconfig/sun3os4\ +./tconfig/sun4\ +./tconfig/sun4os3\ +./tconfig/sun4os4\ +./tconfig/symmetry\ +./tconfig/umax\ +./tconfig/vax\ +./tconfig/vxworks68\ +./tconfig/vxworks960\ +./xconfig/3b1\ +./xconfig/altos\ +./xconfig/altosgas\ +./xconfig/arm\ +./xconfig/bigmips\ +./xconfig/convex\ +./xconfig/hp300bsd\ +./xconfig/hp300hpux\ +./xconfig/i386v\ +./xconfig/i386v-g\ +./xconfig/i386v32\ +./xconfig/i386v32-g\ +./xconfig/isi\ +./xconfig/littlemips\ +./xconfig/m88k\ +./xconfig/merlin\ +./xconfig/news\ +./xconfig/news1000\ +./xconfig/none\ +./xconfig/np1\ +./xconfig/pn\ +./xconfig/pyramid\ +./xconfig/sun2os3\ +./xconfig/sun2os4\ +./xconfig/sun3\ +./xconfig/sun386\ +./xconfig/sun3os3\ +./xconfig/sun3os4\ +./xconfig/sun4\ +./xconfig/sun4os3\ +./xconfig/sun4os4\ +./xconfig/symmetry\ +./xconfig/umax\ +./xconfig/vax + diff --git a/gdb/alloca.c b/gdb/alloca.c new file mode 100644 index 00000000000..d5de3dea44e --- /dev/null +++ b/gdb/alloca.c @@ -0,0 +1,191 @@ +/* + alloca -- (mostly) portable public-domain implementation -- D A Gwyn + + last edit: 86/05/30 rms + include config.h, since on VMS it renames some symbols. + Use xmalloc instead of malloc. + + This implementation of the PWB library alloca() function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + + It should work under any C implementation that uses an + actual procedure stack (as opposed to a linked list of + frames). There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca()-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. +*/ +#ifndef lint +static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ +#endif + +#ifdef emacs +#include "config.h" +#ifdef static +/* actually, only want this if static is defined as "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif static +#endif emacs + +#ifdef __STDC__ +typedef void *pointer; /* generic pointer type */ +#else +typedef char *pointer; /* generic pointer type */ +#endif + +#define NULL 0 /* null pointer constant */ + +extern void free(); +extern pointer xmalloc(); + +/* + Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown +*/ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* direction unknown */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* known at compile-time */ + +#else /* STACK_DIRECTION == 0; need run-time code */ + +static int stack_dir; /* 1 or -1 once known */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (/* void */) +{ + static char *addr = NULL; /* address of first + `dummy', once known */ + auto char dummy; /* to get stack address */ + + if (addr == NULL) + { /* initial entry */ + addr = &dummy; + + find_stack_direction (); /* recurse once */ + } + else /* second entry */ + if (&dummy > addr) + stack_dir = 1; /* stack grew upward */ + else + stack_dir = -1; /* stack grew downward */ +} + +#endif /* STACK_DIRECTION == 0 */ + +/* + An "alloca header" is used to: + (a) chain together all alloca()ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc() + alignment chunk size. The following default should work okay. +*/ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* to force sizeof(header) */ + struct + { + union hdr *next; /* for chaining headers */ + char *deep; /* for stack depth measure */ + } h; +} header; + +/* + alloca( size ) returns a pointer to at least `size' bytes of + storage which will be automatically reclaimed upon exit from + the procedure that called alloca(). Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. +*/ + +static header *last_alloca_header = NULL; /* -> last alloca header */ + +pointer +alloca (size) /* returns pointer to storage */ + unsigned size; /* # bytes to allocate */ +{ + auto char probe; /* probes stack depth: */ + register char *depth = &probe; + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* unknown growth direction */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca()ed storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* traverses linked list */ + + for (hp = last_alloca_header; hp != NULL;) + if (STACK_DIR > 0 && hp->h.deep > depth + || STACK_DIR < 0 && hp->h.deep < depth) + { + register header *np = hp->h.next; + + free ((pointer) hp); /* collect garbage */ + + hp = np; /* -> next header */ + } + else + break; /* rest are not deeper */ + + last_alloca_header = hp; /* -> last valid storage */ + } + + if (size == 0) + return NULL; /* no allocation required */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = xmalloc (sizeof (header) + size); + /* address of header */ + + ((header *)new)->h.next = last_alloca_header; + ((header *)new)->h.deep = depth; + + last_alloca_header = (header *)new; + + /* User storage begins just after header. */ + + return (pointer)((char *)new + sizeof(header)); + } +} + diff --git a/gdb/altos-xdep.c b/gdb/altos-xdep.c new file mode 100644 index 00000000000..1949c8d0b36 --- /dev/null +++ b/gdb/altos-xdep.c @@ -0,0 +1,166 @@ +/* Low level interface to ptrace, for GDB when running under m68k SVR2 Unix + on Altos 3068. Report bugs to Jyrki Kuoppala + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include +#ifdef USG +#include +#ifdef ALTOS +#include +#include +#endif +#endif + +#include "gdbcore.h" +#include /* After a.out.h */ +#include +#include + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +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) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + + unsigned int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + data_start = exec_data_start; + +#if !defined (NBPG) +#define NBPG NBPP +#endif +#if !defined (UPAGES) +#define UPAGES USIZE +#endif + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES + exec_data_start % NBPG /* Not sure about this //jkp */; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* Some machines put an absolute address in here and some put + the offset in the upage of the regs. */ + reg_offset = (int) u.u_state; + if (reg_offset > NBPG * UPAGES) + reg_offset -= KERNEL_U_ADDR; + + bcopy (&u.u_exdata, &core_aouthdr, sizeof (AOUTHDR)); + printf ("Core file is from \"%s\".\n", u.u_comm); + + /* I don't know where to find this info. + So, for now, mark it as not available. */ + N_SET_MAGIC (core_aouthdr, 0); + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0 + || (val = myread (corechan, buf, sizeof buf)) < 0) + { + char * buffer = (char *) alloca (strlen (reg_names[regno]) + + 30); + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} diff --git a/gdb/am29k-opcode.h b/gdb/am29k-opcode.h new file mode 100644 index 00000000000..96aff4030dd --- /dev/null +++ b/gdb/am29k-opcode.h @@ -0,0 +1,271 @@ +/* Table of opcodes for the AMD 29000 + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Jim Kingdon. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct am29k_opcode { + /* Name of the instruction. */ + char *name; + + /* Opcode (i.e. most significant byte of the word). */ + unsigned char opcode; + + /* A string of characters which describe the operands. + Valid characters are: + , Itself. The character appears in the assembly code. + a RA. The register number is in bits 8-15 of the instruction. + b RB. The register number is in bits 0-7 of the instruction. + c RC. The register number is in bits 16-23 of the instruction. + i An immediate operand is in bits 0-7 of the instruction. + x Bits 0-7 and 16-23 of the instruction are bits 0-7 and 8-15 + (respectively) of the immediate operand. + h Same as x but the instruction contains bits 16-31 of the + immediate operand. + X Same as x but bits 16-31 of the signed immediate operand + are set to 1 (thus the operand is always negative). + P,A Bits 0-7 and 16-23 of the instruction are bits 2-9 and 10-17 + (respectively) of the immediate operand. + P=PC-relative, sign-extended to 32 bits. + A=Absolute, zero-extended to 32 bits. + e CE bit (bit 23) for a load/store instruction. + n Control field (bits 16-22) for a load/store instruction. + v Immediate operand in bits 16-23 of the instruction. + (used for trap numbers). + s SA. Special-purpose register number in bits 8-15 + of the instruction. + u UI--bit 7 of the instruction. + r RND--bits 4-6 of the instruction. + d FD--bits 2-3 of the instruction. + f FS--bits 0-1 of the instruction. */ + char *args; +}; + +static struct am29k_opcode am29k_opcodes[] = +{ + +{ "add", 0x14, "c,a,b" }, +{ "add", 0x15, "c,a,i" }, +{ "addc", 0x1c, "c,a,b" }, +{ "addc", 0x1d, "c,a,i" }, +{ "addcs", 0x18, "c,a,b" }, +{ "addcs", 0x19, "c,a,i" }, +{ "addcu", 0x1a, "c,a,b" }, +{ "addcu", 0x1b, "c,a,i" }, +{ "adds", 0x10, "c,a,b" }, +{ "adds", 0x11, "c,a,i" }, +{ "addu", 0x12, "c,a,b" }, +{ "addu", 0x13, "c,a,i" }, +{ "and", 0x90, "c,a,b" }, +{ "and", 0x91, "c,a,i" }, +{ "andn", 0x9c, "c,a,b" }, +{ "andn", 0x9d, "c,a,i" }, +{ "aseq", 0x70, "v,a,b" }, +{ "aseq", 0x71, "v,a,i" }, +{ "asge", 0x5c, "v,a,b" }, +{ "asge", 0x5d, "v,a,i" }, +{ "asgeu", 0x5e, "v,a,b" }, +{ "asgeu", 0x5f, "v,a,i" }, +{ "asgt", 0x58, "v,a,b" }, +{ "asgt", 0x59, "v,a,i" }, +{ "asgtu", 0x5a, "v,a,b" }, +{ "asgtu", 0x5b, "v,a,i" }, +{ "asle", 0x54, "v,a,b" }, +{ "asle", 0x55, "v,a,i" }, +{ "asleu", 0x56, "v,a,b" }, +{ "asleu", 0x57, "v,a,i" }, +{ "aslt", 0x50, "v,a,b" }, +{ "aslt", 0x51, "v,a,i" }, +{ "asltu", 0x52, "v,a,b" }, +{ "asltu", 0x53, "v,a,i" }, +{ "asneq", 0x72, "v,a,b" }, +{ "asneq", 0x73, "v,a,i" }, +{ "call", 0xa8, "a,P" }, +{ "call", 0xa9, "a,A" }, +{ "calli", 0xc8, "a,b" }, +{ "class", 0xe6, "c,a,f" }, +{ "clz", 0x08, "c,b" }, +{ "clz", 0x09, "c,i" }, +{ "const", 0x03, "a,x" }, +{ "consth", 0x02, "a,h" }, +{ "consthz", 0x05, "a,h" }, +{ "constn", 0x01, "a,X" }, +{ "convert", 0xe4, "c,a,u,r,d,f" }, +{ "cpbyte", 0x2e, "c,a,b" }, +{ "cpbyte", 0x2f, "c,a,i" }, +{ "cpeq", 0x60, "c,a,b" }, +{ "cpeq", 0x61, "c,a,i" }, +{ "cpge", 0x4c, "c,a,b" }, +{ "cpge", 0x4d, "c,a,i" }, +{ "cpgeu", 0x4e, "c,a,b" }, +{ "cpgeu", 0x4f, "c,a,i" }, +{ "cpgt", 0x48, "c,a,b" }, +{ "cpgt", 0x49, "c,a,i" }, +{ "cpgtu", 0x4a, "c,a,b" }, +{ "cpgtu", 0x4b, "c,a,i" }, +{ "cple", 0x44, "c,a,b" }, +{ "cple", 0x45, "c,a,i" }, +{ "cpleu", 0x46, "c,a,b" }, +{ "cpleu", 0x47, "c,a,i" }, +{ "cplt", 0x40, "c,a,b" }, +{ "cplt", 0x41, "c,a,i" }, +{ "cpltu", 0x42, "c,a,b" }, +{ "cpltu", 0x43, "c,a,i" }, +{ "cpneq", 0x62, "c,a,b" }, +{ "cpneq", 0x63, "c,a,i" }, +{ "dadd", 0xf1, "c,a,b" }, +{ "ddiv", 0xf7, "c,a,b" }, +{ "deq", 0xeb, "c,a,b" }, +{ "dge", 0xef, "c,a,b" }, +{ "dgt", 0xed, "c,a,b" }, +{ "div", 0x6a, "c,a,b" }, +{ "div", 0x6b, "c,a,i" }, +{ "div0", 0x68, "c,b" }, +{ "div0", 0x69, "c,i" }, +{ "divide", 0xe1, "c,a,b" }, +{ "dividu", 0xe3, "c,a,b" }, +{ "divl", 0x6c, "c,a,b" }, +{ "divl", 0x6d, "c,a,i" }, +{ "divrem", 0x6e, "c,a,b" }, +{ "divrem", 0x6f, "c,a,i" }, +{ "dmac", 0xd9, "F,C,a,b" }, +{ "dmsm", 0xdb, "c,a,b" }, +{ "dmul", 0xf5, "c,a,b" }, +{ "dsub", 0xf3, "c,a,b" }, +{ "emulate", 0xd7, "v,a,b" }, +{ "exbyte", 0x0a, "c,a,b" }, +{ "exbyte", 0x0b, "c,a,i" }, +{ "exhw", 0x7c, "c,a,b" }, +{ "exhw", 0x7d, "c,a,i" }, +{ "exhws", 0x7e, "c,a" }, +{ "extract", 0x7a, "c,a,b" }, +{ "extract", 0x7b, "c,a,i" }, +{ "fadd", 0xf0, "c,a,b" }, +{ "fdiv", 0xf6, "c,a,b" }, +{ "fdmul", 0xf9, "c,a,b" }, +{ "feq", 0xea, "c,a,b" }, +{ "fge", 0xee, "c,a,b" }, +{ "fgt", 0xec, "c,a,b" }, +{ "fmac", 0xd8, "F,C,a,b" }, +{ "fmsm", 0xda, "c,a,b" }, +{ "fmul", 0xf4, "c,a,b" }, +{ "fsub", 0xf2, "c,a,b" }, +{ "halt", 0x89, "" }, +{ "inbyte", 0x0c, "c,a,b" }, +{ "inbyte", 0x0d, "c,a,i" }, +{ "inhw", 0x78, "c,a,b" }, +{ "inhw", 0x79, "c,a,i" }, +{ "inv", 0x9f, "" }, +{ "iret", 0x88, "" }, +{ "iretinv", 0x8c, "" }, +{ "jmp", 0xa0, "P" }, +{ "jmp", 0xa1, "A" }, +{ "jmpf", 0xa4, "a,P" }, +{ "jmpf", 0xa5, "a,A" }, +{ "jmpfdec", 0xb4, "a,P" }, +{ "jmpfdec", 0xb5, "a,A" }, +{ "jmpfi", 0xc4, "a,b" }, +{ "jmpi", 0xc0, "b" }, +{ "jmpt", 0xac, "a,P" }, +{ "jmpt", 0xad, "a,A" }, +{ "jmpti", 0xcc, "a,b" }, +{ "load", 0x16, "e,n,a,b" }, +{ "load", 0x17, "e,n,a,i" }, +{ "loadl", 0x06, "e,n,a,b" }, +{ "loadl", 0x07, "e,n,a,i" }, +{ "loadm", 0x36, "e,n,a,b" }, +{ "loadm", 0x37, "e,n,a,i" }, +{ "loadset", 0x26, "e,n,a,b" }, +{ "loadset", 0x27, "e,n,a,i" }, +{ "mfacc", 0xe9, "c,d,f" }, +{ "mfsr", 0xc6, "c,s" }, +{ "mftlb", 0xb6, "c,a" }, +{ "mtacc", 0xe8, "c,d,f" }, +{ "mtsr", 0xce, "s,b" }, +{ "mtsrim", 0x04, "s,x" }, +{ "mttlb", 0xbe, "a,b" }, +{ "mul", 0x64, "c,a,b" }, +{ "mul", 0x65, "c,a,i" }, +{ "mull", 0x66, "c,a,b" }, +{ "mull", 0x67, "c,a,i" }, +{ "multiplu", 0xe2, "c,a,b" }, +{ "multiply", 0xe0, "c,a,b" }, +{ "multm", 0xde, "c,a,b" }, +{ "multmu", 0xdf, "c,a,b" }, +{ "mulu", 0x74, "c,a,b" }, +{ "mulu", 0x75, "c,a,i" }, +{ "nand", 0x9a, "c,a,b" }, +{ "nand", 0x9b, "c,a,i" }, +{ "nor", 0x98, "c,a,b" }, +{ "nor", 0x99, "c,a,i" }, +{ "or", 0x92, "c,a,b" }, +{ "or", 0x93, "c,a,i" }, +{ "orn", 0xaa, "c,a,b" }, +{ "orn", 0xab, "c,a,i" }, + +/* The description of "setip" in Chapter 8 ("instruction set") of the user's + manual claims that these are absolute register numbers. But section + 7.2.1 explains that they are not. The latter is correct, so print + these normally ("lr0", "lr5", etc.). */ +{ "setip", 0x9e, "c,a,b" }, + +{ "sll", 0x80, "c,a,b" }, +{ "sll", 0x81, "c,a,i" }, +{ "sqrt", 0xe5, "c,a,f" }, +{ "sra", 0x86, "c,a,b" }, +{ "sra", 0x87, "c,a,i" }, +{ "srl", 0x82, "c,a,b" }, +{ "srl", 0x83, "c,a,i" }, +{ "store", 0x1e, "e,n,a,b" }, +{ "store", 0x1f, "e,n,a,i" }, +{ "storel", 0x0e, "e,n,a,b" }, +{ "storel", 0x0f, "e,n,a,i" }, +{ "storem", 0x3e, "e,n,a,b" }, +{ "storem", 0x3f, "e,n,a,i" }, +{ "sub", 0x24, "c,a,b" }, +{ "sub", 0x25, "c,a,i" }, +{ "subc", 0x2c, "c,a,b" }, +{ "subc", 0x2d, "c,a,i" }, +{ "subcs", 0x28, "c,a,b" }, +{ "subcs", 0x29, "c,a,i" }, +{ "subcu", 0x2a, "c,a,b" }, +{ "subcu", 0x2b, "c,a,i" }, +{ "subr", 0x34, "c,a,b" }, +{ "subr", 0x35, "c,a,i" }, +{ "subrc", 0x3c, "c,a,b" }, +{ "subrc", 0x3d, "c,a,i" }, +{ "subrcs", 0x38, "c,a,b" }, +{ "subrcs", 0x39, "c,a,i" }, +{ "subrcu", 0x3a, "c,a,b" }, +{ "subrcu", 0x3b, "c,a,i" }, +{ "subrs", 0x30, "c,a,b" }, +{ "subrs", 0x31, "c,a,i" }, +{ "subru", 0x32, "c,a,b" }, +{ "subru", 0x33, "c,a,i" }, +{ "subs", 0x20, "c,a,b" }, +{ "subs", 0x21, "c,a,i" }, +{ "subu", 0x22, "c,a,b" }, +{ "subu", 0x23, "c,a,i" }, +{ "xnor", 0x96, "c,a,b" }, +{ "xnor", 0x97, "c,a,i" }, +{ "xor", 0x94, "c,a,b" }, +{ "xor", 0x95, "c,a,i" } + +}; + +#define NUM_OPCODES ((sizeof am29k_opcodes) / (sizeof am29k_opcodes[0])) + diff --git a/gdb/am29k-pinsn.c b/gdb/am29k-pinsn.c new file mode 100644 index 00000000000..c933629d7ac --- /dev/null +++ b/gdb/am29k-pinsn.c @@ -0,0 +1,296 @@ +/* Instruction printing code for the AMD 29000 + Copyright (C) 1990 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Jim Kingdon. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#include "defs.h" +#include "target.h" +#include "am29k-opcode.h" + +/* Print a symbolic representation of a general-purpose + register number NUM on STREAM. + NUM is a number as found in the instruction, not as found in + debugging symbols; it must be in the range 0-255. */ +static void +print_general (num, stream) + int num; + FILE *stream; +{ + if (num < 128) + fprintf_filtered (stream, "gr%d", num); + else + fprintf_filtered (stream, "lr%d", num - 128); +} + +/* Like print_general but a special-purpose register. + + The mnemonics used by the AMD assembler are not quite the same + as the ones in the User's Manual. We use the ones that the + assembler uses. */ +static void +print_special (num, stream) + int num; + FILE *stream; +{ + /* Register names of registers 0-SPEC0_NUM-1. */ + static char *spec0_names[] = { + "vab", "ops", "cps", "cfg", "cha", "chd", "chc", "rbp", "tmc", "tmr", + "pc0", "pc1", "pc2", "mmu", "lru" + }; +#define SPEC0_NUM ((sizeof spec0_names) / (sizeof spec0_names[0])) + + /* Register names of registers 128-128+SPEC128_NUM-1. */ + static char *spec128_names[] = { + "ipc", "ipa", "ipb", "q", "alu", "bp", "fc", "cr" + }; +#define SPEC128_NUM ((sizeof spec128_names) / (sizeof spec128_names[0])) + + /* Register names of registers 160-160+SPEC160_NUM-1. */ + static char *spec160_names[] = { + "fpe", "inte", "fps", "sr163", "exop" + }; +#define SPEC160_NUM ((sizeof spec160_names) / (sizeof spec160_names[0])) + + if (num < SPEC0_NUM) + fprintf_filtered (stream, spec0_names[num]); + else if (num >= 128 && num < 128 + SPEC128_NUM) + fprintf_filtered (stream, spec128_names[num-128]); + else if (num >= 160 && num < 160 + SPEC160_NUM) + fprintf_filtered (stream, spec160_names[num-160]); + else + fprintf_filtered (stream, "sr%d", num); +} + +/* Is an instruction with OPCODE a delayed branch? */ +static int +is_delayed_branch (opcode) + int opcode; +{ + return (opcode == 0xa8 || opcode == 0xa9 || opcode == 0xa0 || opcode == 0xa1 + || opcode == 0xa4 || opcode == 0xa5 + || opcode == 0xb4 || opcode == 0xb5 + || opcode == 0xc4 || opcode == 0xc0 + || opcode == 0xac || opcode == 0xad + || opcode == 0xcc); +} + +/* Now find the four bytes of INSN and put them in *INSN{0,8,16,24}. + Note that the amd can be set up as either + big or little-endian (the tm file says which) and we can't assume + the host machine is the same. */ +static void +find_bytes (insn, insn0, insn8, insn16, insn24) + char *insn; + unsigned char *insn0; + unsigned char *insn8; + unsigned char *insn16; + unsigned char *insn24; +{ +#if TARGET_BYTE_ORDER == BIG_ENDIAN + *insn24 = insn[0]; + *insn16 = insn[1]; + *insn8 = insn[2]; + *insn0 = insn[3]; +#else /* Little-endian. */ + *insn24 = insn[3]; + *insn16 = insn[2]; + *insn8 = insn[1]; + *insn0 = insn[0]; +#endif /* Little-endian. */ +} + +/* Print one instruction from MEMADDR on STREAM. + Return the size of the instruction (always 4 on am29k). */ +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + /* The raw instruction. */ + char insn[4]; + + /* The four bytes of the instruction. */ + unsigned char insn24, insn16, insn8, insn0; + + struct am29k_opcode *opcode; + + read_memory (memaddr, &insn[0], 4); + + find_bytes (insn, &insn0, &insn8, &insn16, &insn24); + + /* The opcode is always in insn24. */ + for (opcode = &am29k_opcodes[0]; + opcode < &am29k_opcodes[NUM_OPCODES]; + ++opcode) + { + if (insn24 == opcode->opcode) + { + char *s; + + fprintf_filtered (stream, "%s ", opcode->name); + for (s = opcode->args; *s != '\0'; ++s) + { + switch (*s) + { + case 'a': + print_general (insn8, stream); + break; + + case 'b': + print_general (insn0, stream); + break; + + case 'c': + print_general (insn16, stream); + break; + + case 'i': + fprintf_filtered (stream, "%d", insn0); + break; + + case 'x': + fprintf_filtered (stream, "%d", (insn16 << 8) + insn0); + break; + + case 'h': + fprintf_filtered (stream, "0x%x", + (insn16 << 24) + (insn0 << 16)); + break; + + case 'X': + fprintf_filtered (stream, "%d", + ((insn16 << 8) + insn0) | 0xffff0000); + break; + + case 'P': + /* This output looks just like absolute addressing, but + maybe that's OK (it's what the GDB 68k and EBMON + 29k disassemblers do). */ + /* All the shifting is to sign-extend it. p*/ + print_address + (memaddr + + (((int)((insn16 << 10) + (insn0 << 2)) << 14) >> 14), + stream); + break; + + case 'A': + print_address ((insn16 << 10) + (insn0 << 2), stream); + break; + + case 'e': + fprintf_filtered (stream, "%d", insn16 >> 7); + break; + + case 'n': + fprintf_filtered (stream, "0x%x", insn16 & 0x7f); + break; + + case 'v': + fprintf_filtered (stream, "%#x", insn16); + break; + + case 's': + print_special (insn8, stream); + break; + + case 'u': + fprintf_filtered (stream, "%d", insn0 >> 7); + break; + + case 'r': + fprintf_filtered (stream, "%d", (insn0 >> 4) & 7); + break; + + case 'd': + fprintf_filtered (stream, "%d", (insn0 >> 2) & 3); + break; + + case 'f': + fprintf_filtered (stream, "%d", insn0 & 3); + break; + + case 'F': + fprintf_filtered (stream, "%d", (insn0 >> 18) & 15); + break; + + case 'C': + fprintf_filtered (stream, "%d", (insn0 >> 16) & 3); + break; + + default: + fprintf_filtered (stream, "%c", *s); + } + } + + /* Now we look for a const,consth pair of instructions, + in which case we try to print the symbolic address. */ + if (insn24 == 2) /* consth */ + { + int errcode; + char prev_insn[4]; + unsigned char prev_insn0, prev_insn8, prev_insn16, prev_insn24; + + errcode = target_read_memory (memaddr - 4, + &prev_insn[0], + 4); + if (errcode == 0) + { + /* If it is a delayed branch, we need to look at the + instruction before the delayed brach to handle + things like + + const _foo + call _printf + consth _foo + */ + find_bytes (prev_insn, &prev_insn0, &prev_insn8, + &prev_insn16, &prev_insn24); + if (is_delayed_branch (prev_insn24)) + { + errcode = target_read_memory + (memaddr - 8, &prev_insn[0], 4); + find_bytes (prev_insn, &prev_insn0, &prev_insn8, + &prev_insn16, &prev_insn24); + } + } + + /* If there was a problem reading memory, then assume + the previous instruction was not const. */ + if (errcode == 0) + { + /* Is it const to the same register? */ + if (prev_insn24 == 3 + && prev_insn8 == insn8) + { + fprintf_filtered (stream, "\t; "); + print_address (((insn16 << 24) + (insn0 << 16) + + (prev_insn16 << 8) + (prev_insn0)), + stream); + } + } + } + + return 4; + } + } + fprintf_filtered (stream, ".word %#8x", + (insn24 << 24) + (insn16 << 16) + (insn8 << 8) + insn0); + return 4; +} diff --git a/gdb/am29k-tdep.c b/gdb/am29k-tdep.c new file mode 100644 index 00000000000..e58847b3e79 --- /dev/null +++ b/gdb/am29k-tdep.c @@ -0,0 +1,695 @@ +/* Target-machine dependent code for the AMD 29000 + Copyright (C) 1990 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Jim Kingdon. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "gdbcore.h" +#include +#include "frame.h" +#include "value.h" +#include "param.h" +#include "symtab.h" +#include "inferior.h" + +/* Structure to hold cached info about function prologues. */ +struct prologue_info +{ + CORE_ADDR pc; /* First addr after fn prologue */ + unsigned rsize, msize; /* register stack frame size, mem stack ditto */ + unsigned mfp_used : 1; /* memory frame pointer used */ + unsigned rsize_valid : 1; /* Validity bits for the above */ + unsigned msize_valid : 1; + unsigned mfp_valid : 1; +}; + +/* Examine the prologue of a function which starts at PC. Return + the first addess past the prologue. If MSIZE is non-NULL, then + set *MSIZE to the memory stack frame size. If RSIZE is non-NULL, + then set *RSIZE to the register stack frame size (not including + incoming arguments and the return address & frame pointer stored + with them). If no prologue is found, *RSIZE is set to zero. + If no prologue is found, or a prologue which doesn't involve + allocating a memory stack frame, then set *MSIZE to zero. + + Note that both msize and rsize are in bytes. This is not consistent + with the _User's Manual_ with respect to rsize, but it is much more + convenient. + + If MFP_USED is non-NULL, *MFP_USED is set to nonzero if a memory + frame pointer is being used. */ +CORE_ADDR +examine_prologue (pc, rsize, msize, mfp_used) + CORE_ADDR pc; + unsigned *msize; + unsigned *rsize; + int *mfp_used; +{ + long insn; + CORE_ADDR p = pc; + int misc_index = find_pc_misc_function (pc); + struct prologue_info *mi = 0; + + if (misc_index >= 0) + mi = (struct prologue_info *)misc_function_vector[misc_index].misc_info; + + if (mi != 0) + { + int valid = 1; + if (rsize != NULL) + { + *rsize = mi->rsize; + valid &= mi->rsize_valid; + } + if (msize != NULL) + { + *msize = mi->msize; + valid &= mi->msize_valid; + } + if (mfp_used != NULL) + { + *mfp_used = mi->mfp_used; + valid &= mi->mfp_valid; + } + if (valid) + return mi->pc; + } + + if (rsize != NULL) + *rsize = 0; + if (msize != NULL) + *msize = 0; + if (mfp_used != NULL) + *mfp_used = 0; + + /* Prologue must start with subtracting a constant from gr1. + Normally this is sub gr1,gr1,. */ + insn = read_memory_integer (p, 4); + if ((insn & 0xffffff00) != 0x25010100) + { + /* If the frame is large, instead of a single instruction it + might be a pair of instructions: + const , + sub gr1,gr1, + */ + int reg; + /* Possible value for rsize. */ + unsigned int rsize0; + + if ((insn & 0xff000000) != 0x03000000) + { + p = pc; + goto done; + } + reg = (insn >> 8) & 0xff; + rsize0 = (((insn >> 8) & 0xff00) | (insn & 0xff)); + p += 4; + insn = read_memory_integer (p, 4); + if ((insn & 0xffffff00) != 0x24010100 + || (insn & 0xff) != reg) + { + p = pc; + goto done; + } + if (rsize != NULL) + *rsize = rsize0; + } + else + { + if (rsize != NULL) + *rsize = (insn & 0xff); + } + p += 4; + + /* Next instruction must be asgeu V_SPILL,gr1,rab. */ + insn = read_memory_integer (p, 4); + if (insn != 0x5e40017e) + { + p = pc; + goto done; + } + p += 4; + + /* Next instruction usually sets the frame pointer (lr1) by adding + from gr1. However, this can (and high C does) be + deferred until anytime before the first function call. So it is + OK if we don't see anything which sets lr1. */ + /* Normally this is just add lr1,gr1,. */ + insn = read_memory_integer (p, 4); + if ((insn & 0xffffff00) == 0x15810100) + p += 4; + else + { + /* However, for large frames it can be + const , + add lr1,gr1, + */ + int reg; + CORE_ADDR q; + + if ((insn & 0xff000000) == 0x03000000) + { + reg = (insn >> 8) & 0xff; + q = p + 4; + insn = read_memory_integer (q, 4); + if ((insn & 0xffffff00) == 0x14810100 + && (insn & 0xff) == reg) + p = q; + } + } + + /* Next comes "add lr{},msp,0", but only if a memory + frame pointer is in use. We just check for add lr,msp,0; + we don't check this rsize against the first instruction, and + we don't check that the trace-back tag indicates a memory frame pointer + is in use. + + The recommended instruction is actually "sll lr,msp,0". + We check for that, too. Originally Jim Kingdon's code seemed + to be looking for a "sub" instruction here, but the mask was set + up to lose all the time. */ + insn = read_memory_integer (p, 4); + if (((insn & 0xff80ffff) == 0x15807d00) /* add */ + || ((insn & 0xff80ffff) == 0x81807d00) ) /* sll */ + { + p += 4; + if (mfp_used != NULL) + *mfp_used = 1; + } + + /* Next comes a subtraction from msp to allocate a memory frame, + but only if a memory frame is + being used. We don't check msize against the trace-back tag. + + Normally this is just + sub msp,msp, + */ + insn = read_memory_integer (p, 4); + if ((insn & 0xffffff00) == 0x257d7d00) + { + p += 4; + if (msize != NULL) + *msize = insn & 0xff; + } + else + { + /* For large frames, instead of a single instruction it might + be + + const , + consth , ; optional + sub msp,msp, + */ + int reg; + unsigned msize0; + CORE_ADDR q = p; + + if ((insn & 0xff000000) == 0x03000000) + { + reg = (insn >> 8) & 0xff; + msize0 = ((insn >> 8) & 0xff00) | (insn & 0xff); + q += 4; + insn = read_memory_integer (q, 4); + /* Check for consth. */ + if ((insn & 0xff000000) == 0x02000000 + && (insn & 0x0000ff00) == reg) + { + msize0 |= (insn << 8) & 0xff000000; + msize0 |= (insn << 16) & 0x00ff0000; + q += 4; + insn = read_memory_integer (q, 4); + } + /* Check for sub msp,msp,. */ + if ((insn & 0xffffff00) == 0x247d7d00 + && (insn & 0xff) == reg) + { + p = q + 4; + if (msize != NULL) + *msize = msize0; + } + } + } + + done: + if (misc_index >= 0) + { + if (mi == 0) + { + /* Add a new cache entry. */ + mi = (struct prologue_info *)xmalloc (sizeof (struct prologue_info)); + misc_function_vector[misc_index].misc_info = (char *)mi; + mi->rsize_valid = 0; + mi->msize_valid = 0; + mi->mfp_valid = 0; + } + /* else, cache entry exists, but info is incomplete. */ + mi->pc = p; + if (rsize != NULL) + { + mi->rsize = *rsize; + mi->rsize_valid = 1; + } + if (msize != NULL) + { + mi->msize = *msize; + mi->msize_valid = 1; + } + if (mfp_used != NULL) + { + mi->mfp_used = *mfp_used; + mi->mfp_valid = 1; + } + } + return p; +} + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +CORE_ADDR +skip_prologue (pc) + CORE_ADDR pc; +{ + return examine_prologue (pc, (unsigned *)NULL, (unsigned *)NULL, + (int *)NULL); +} + +/* Initialize the frame. In addition to setting "extra" frame info, + we also set ->frame because we use it in a nonstandard way, and ->pc + because we need to know it to get the other stuff. See the diagram + of stacks and the frame cache in tm-29k.h for more detail. */ +static void +init_frame_info (innermost_frame, fci) + int innermost_frame; + struct frame_info *fci; +{ + CORE_ADDR p; + long insn; + unsigned rsize; + unsigned msize; + int mfp_used; + struct symbol *func; + + p = fci->pc; + + if (innermost_frame) + fci->frame = read_register (GR1_REGNUM); + else + fci->frame = fci->next_frame + fci->next->rsize; + +#if CALL_DUMMY_LOCATION == ON_STACK + This wont work; +#else + if (PC_IN_CALL_DUMMY (p, 0, 0)) +#endif + { + fci->rsize = DUMMY_FRAME_RSIZE; + /* This doesn't matter since we never try to get locals or args + from a dummy frame. */ + fci->msize = 0; + /* Dummy frames always use a memory frame pointer. */ + fci->saved_msp = + read_register_stack_integer (fci->frame + DUMMY_FRAME_RSIZE - 4, 4); + return; + } + + func = find_pc_function (p); + if (func != NULL) + p = BLOCK_START (SYMBOL_BLOCK_VALUE (func)); + else + { + /* Search backward to find the trace-back tag. However, + do not trace back beyond the start of the text segment + (just as a sanity check to avoid going into never-never land). */ + while (p >= text_start + && ((insn = read_memory_integer (p, 4)) & 0xff000000) != 0) + p -= 4; + + if (p < text_start) + { + /* Couldn't find the trace-back tag. + Something strange is going on. */ + fci->saved_msp = 0; + fci->rsize = 0; + fci->msize = 0; + return; + } + else + /* Advance to the first word of the function, i.e. the word + after the trace-back tag. */ + p += 4; + } + /* We've found the start of the function. Since High C interchanges + the meanings of bits 23 and 22 (as of Jul 90), and we + need to look at the prologue anyway to figure out + what rsize is, ignore the contents of the trace-back tag. */ + examine_prologue (p, &rsize, &msize, &mfp_used); + fci->rsize = rsize; + fci->msize = msize; + if (innermost_frame) + { + fci->saved_msp = read_register (MSP_REGNUM) + msize; + } + else + { + if (mfp_used) + fci->saved_msp = + read_register_stack_integer (fci->frame + rsize - 1, 4); + else + fci->saved_msp = fci->next->saved_msp + msize; + } +} + +void +init_extra_frame_info (fci) + struct frame_info *fci; +{ + if (fci->next == 0) + /* Assume innermost frame. May produce strange results for "info frame" + but there isn't any way to tell the difference. */ + init_frame_info (1, fci); + else + /* We're in get_prev_frame_info. + Take care of everything in init_frame_pc. */ + ; +} + +void +init_frame_pc (fromleaf, fci) + int fromleaf; + struct frame_info *fci; +{ + fci->pc = (fromleaf ? SAVED_PC_AFTER_CALL (fci->next) : + fci->next ? FRAME_SAVED_PC (fci->next) : read_pc ()); + init_frame_info (0, fci); +} + +/* Local variables (i.e. LOC_LOCAL) are on the memory stack, with their + offsets being relative to the memory stack pointer (high C) or + saved_msp (gcc). */ + +CORE_ADDR +frame_locals_address (fi) + struct frame_info *fi; +{ + struct block *b = block_for_pc (fi->pc); + /* If compiled without -g, assume GCC. */ + if (b == NULL || BLOCK_GCC_COMPILED (b)) + return fi->saved_msp; + else + return fi->saved_msp - fi->msize; +} + +/* Routines for reading the register stack. The caller gets to treat + the register stack as a uniform stack in memory, from address $gr1 + straight through $rfb and beyond. */ + +/* Analogous to read_memory except the length is understood to be 4. + Also, myaddr can be NULL (meaning don't bother to read), and + if actual_mem_addr is non-NULL, store there the address that it + was fetched from (or if from a register the offset within + registers). Set *LVAL to lval_memory or lval_register, depending + on where it came from. */ +void +read_register_stack (memaddr, myaddr, actual_mem_addr, lval) + CORE_ADDR memaddr; + char *myaddr; + CORE_ADDR *actual_mem_addr; + enum lval_type *lval; +{ + long rfb = read_register (RFB_REGNUM); + long rsp = read_register (RSP_REGNUM); + if (memaddr < rfb) + { + /* It's in a register. */ + int regnum = (memaddr - rsp) / 4 + LR0_REGNUM; + if (regnum < LR0_REGNUM || regnum > LR0_REGNUM + 127) + error ("Attempt to read register stack out of range."); + if (myaddr != NULL) + read_register_gen (regnum, myaddr); + if (lval != NULL) + *lval = lval_register; + if (actual_mem_addr != NULL) + *actual_mem_addr = REGISTER_BYTE (regnum); + } + else + { + /* It's in the memory portion of the register stack. */ + if (myaddr != NULL) + read_memory (memaddr, myaddr, 4); + if (lval != NULL) + *lval = lval_memory; + if (actual_mem_addr != NULL) + *actual_mem_addr == memaddr; + } +} + +/* Analogous to read_memory_integer + except the length is understood to be 4. */ +long +read_register_stack_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + long buf; + read_register_stack (memaddr, &buf, NULL, NULL); + SWAP_TARGET_AND_HOST (&buf, 4); + return buf; +} + +/* Copy 4 bytes from GDB memory at MYADDR into inferior memory + at MEMADDR and put the actual address written into in + *ACTUAL_MEM_ADDR. */ +static void +write_register_stack (memaddr, myaddr, actual_mem_addr) + CORE_ADDR memaddr; + char *myaddr; + CORE_ADDR *actual_mem_addr; +{ + long rfb = read_register (RFB_REGNUM); + long rsp = read_register (RSP_REGNUM); + if (memaddr < rfb) + { + /* It's in a register. */ + int regnum = (memaddr - rsp) / 4 + LR0_REGNUM; + if (regnum < LR0_REGNUM || regnum > LR0_REGNUM + 127) + error ("Attempt to read register stack out of range."); + if (myaddr != NULL) + write_register (regnum, *(long *)myaddr); + if (actual_mem_addr != NULL) + *actual_mem_addr = NULL; + } + else + { + /* It's in the memory portion of the register stack. */ + if (myaddr != NULL) + write_memory (memaddr, myaddr, 4); + if (actual_mem_addr != NULL) + *actual_mem_addr == memaddr; + } +} + +/* Find register number REGNUM relative to FRAME and put its + (raw) contents in *RAW_BUFFER. Set *OPTIMIZED if the variable + was optimized out (and thus can't be fetched). If the variable + was fetched from memory, set *ADDRP to where it was fetched from, + otherwise it was fetched from a register. + + The argument RAW_BUFFER must point to aligned memory. */ +void +get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lvalp) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + FRAME frame; + int regnum; + enum lval_type *lvalp; +{ + struct frame_info *fi = get_frame_info (frame); + CORE_ADDR addr; + enum lval_type lval; + + /* Once something has a register number, it doesn't get optimized out. */ + if (optimized != NULL) + *optimized = 0; + if (regnum == RSP_REGNUM) + { + if (raw_buffer != NULL) + *(CORE_ADDR *)raw_buffer = fi->frame; + if (lvalp != NULL) + *lvalp = not_lval; + return; + } + else if (regnum == PC_REGNUM) + { + if (raw_buffer != NULL) + *(CORE_ADDR *)raw_buffer = fi->pc; + + /* Not sure we have to do this. */ + if (lvalp != NULL) + *lvalp = not_lval; + + return; + } + else if (regnum == MSP_REGNUM) + { + if (raw_buffer != NULL) + { + if (fi->next != NULL) + *(CORE_ADDR *)raw_buffer = fi->next->saved_msp; + else + *(CORE_ADDR *)raw_buffer = read_register (MSP_REGNUM); + } + /* The value may have been computed, not fetched. */ + if (lvalp != NULL) + *lvalp = not_lval; + return; + } + else if (regnum < LR0_REGNUM || regnum >= LR0_REGNUM + 128) + { + /* These registers are not saved over procedure calls, + so just print out the current values. */ + if (raw_buffer != NULL) + *(CORE_ADDR *)raw_buffer = read_register (regnum); + if (lvalp != NULL) + *lvalp = lval_register; + if (addrp != NULL) + *addrp = REGISTER_BYTE (regnum); + return; + } + + addr = fi->frame + (regnum - LR0_REGNUM) * 4; + if (raw_buffer != NULL) + read_register_stack (addr, raw_buffer, &addr, &lval); + if (lvalp != NULL) + *lvalp = lval; + if (addrp != NULL) + *addrp = addr; +} + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +void +pop_frame () +{ + FRAME frame = get_current_frame (); + struct frame_info *fi = get_frame_info (frame); + CORE_ADDR rfb = read_register (RFB_REGNUM); + CORE_ADDR gr1 = fi->frame + fi->rsize; + CORE_ADDR lr1; + CORE_ADDR ret_addr; + int i; + + /* If popping a dummy frame, need to restore registers. */ + if (PC_IN_CALL_DUMMY (read_register (PC_REGNUM), + read_register (SP_REGNUM), + FRAME_FP (fi))) + { + for (i = 0; i < DUMMY_SAVE_SR128; ++i) + write_register + (SR_REGNUM (i + 128), + read_register (LR0_REGNUM + DUMMY_ARG / 4 + i)); + for (i = 0; i < DUMMY_SAVE_GR96; ++i) + write_register + (GR96_REGNUM + i, + read_register (LR0_REGNUM + DUMMY_ARG / 4 + DUMMY_SAVE_SR128 + i)); + } + + /* Restore the memory stack pointer. */ + write_register (MSP_REGNUM, fi->saved_msp); + /* Restore the register stack pointer. */ + write_register (GR1_REGNUM, gr1); + /* Check whether we need to fill registers. */ + lr1 = read_register (LR0_REGNUM + 1); + if (lr1 > rfb) + { + /* Fill. */ + int num_bytes = lr1 - rfb; + int i; + long word; + write_register (RAB_REGNUM, read_register (RAB_REGNUM) + num_bytes); + write_register (RFB_REGNUM, lr1); + for (i = 0; i < num_bytes; i += 4) + { + /* Note: word is in host byte order. */ + word = read_memory_integer (rfb + i, 4); + write_register (LR0_REGNUM + ((rfb - gr1) % 0x80) + i / 4, word); + } + } + ret_addr = read_register (LR0_REGNUM); + write_register (PC_REGNUM, ret_addr); + write_register (NPC_REGNUM, ret_addr + 4); + flush_cached_frames (); + set_current_frame (create_new_frame (0, read_pc())); +} + +/* Push an empty stack frame, to record the current PC, etc. */ + +void +push_dummy_frame () +{ + long w; + CORE_ADDR rab, gr1; + CORE_ADDR msp = read_register (MSP_REGNUM); + int i; + + /* Save the PC. */ + write_register (LR0_REGNUM, read_register (PC_REGNUM)); + + /* Allocate the new frame. */ + gr1 = read_register (GR1_REGNUM) - DUMMY_FRAME_RSIZE; + write_register (GR1_REGNUM, gr1); + + rab = read_register (RAB_REGNUM); + if (gr1 < rab) + { + /* We need to spill registers. */ + int num_bytes = rab - gr1; + CORE_ADDR rfb = read_register (RFB_REGNUM); + int i; + long word; + + write_register (RFB_REGNUM, rfb - num_bytes); + write_register (RAB_REGNUM, gr1); + for (i = 0; i < num_bytes; i += 4) + { + /* Note: word is in target byte order. */ + read_register_gen (LR0_REGNUM + i / 4, &word, 4); + write_memory (rfb - num_bytes + i, &word, 4); + } + } + + /* There are no arguments in to the dummy frame, so we don't need + more than rsize plus the return address and lr1. */ + write_register (LR0_REGNUM + 1, gr1 + DUMMY_FRAME_RSIZE + 2 * 4); + + /* Set the memory frame pointer. */ + write_register (LR0_REGNUM + DUMMY_FRAME_RSIZE / 4 - 1, msp); + + /* Allocate arg_slop. */ + write_register (MSP_REGNUM, msp - 16 * 4); + + /* Save registers. */ + for (i = 0; i < DUMMY_SAVE_SR128; ++i) + write_register (LR0_REGNUM + DUMMY_ARG / 4 + i, + read_register (SR_REGNUM (i + 128))); + for (i = 0; i < DUMMY_SAVE_GR96; ++i) + write_register (LR0_REGNUM + DUMMY_ARG / 4 + DUMMY_SAVE_SR128 + i, + read_register (GR96_REGNUM + i)); +} diff --git a/gdb/ansidecl.h b/gdb/ansidecl.h new file mode 100755 index 00000000000..9e8f3909861 --- /dev/null +++ b/gdb/ansidecl.h @@ -0,0 +1,93 @@ +/* Copyright (C) 1989 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU C Library; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macros + PTR - Generic pointer type + LONG_DOUBLE - `long double' type + CONST - `const' keyword + VOLATILE - `volatile' keyword + SIGNED - `signed' keyword + PTRCONST - Generic const pointer (void *const) + + EXFUN(name, prototype) - declare external function NAME + with prototype PROTOTYPE + DEFUN(name, arglist, args) - define function NAME with + args ARGLIST of types in ARGS + DEFUN_VOID(name) - define function NAME with no args + AND - argument separator for ARGS + NOARGS - null arglist + DOTS - `...' in args + + For example: + extern int EXFUN(printf, (CONST char *format DOTS)); + int DEFUN(fprintf, (stream, format), + FILE *stream AND CONST char *format DOTS) { ... } + void DEFUN_VOID(abort) { ... } +*/ + +#ifndef _ANSIDECL_H + +#define _ANSIDECL_H 1 + + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + + +#ifdef __STDC__ + +#define PTR void * +#define PTRCONST void *CONST +#define LONG_DOUBLE long double + +#define AND , +#define NOARGS void +#define CONST const +#define VOLATILE volatile +#define SIGNED signed +#define DOTS , ... + +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(NOARGS) + +#else /* Not ANSI C. */ + +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#define AND ; +#define NOARGS +#define CONST +#define VOLATILE +#define SIGNED +#define DOTS + +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() + +#endif /* ANSI C. */ + + +#endif /* ansidecl.h */ diff --git a/gdb/arm-convert.s b/gdb/arm-convert.s new file mode 100644 index 00000000000..416132b77c7 --- /dev/null +++ b/gdb/arm-convert.s @@ -0,0 +1,16 @@ + .text + .global _convert_from_extended + +_convert_from_extended: + + ldfe f0,[a1] + stfd f0,[a2] + movs pc,lr + + .global _convert_to_extended + +_convert_to_extended: + + ldfd f0,[a1] + stfe f0,[a2] + movs pc,lr diff --git a/gdb/arm-pinsn.c b/gdb/arm-pinsn.c new file mode 100644 index 00000000000..2da8fdc762a --- /dev/null +++ b/gdb/arm-pinsn.c @@ -0,0 +1,271 @@ +/* Print ARM instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "arm-opcode.h" + +extern char *reg_names[]; + +static char *shift_names[] = { + "lsl", "lsr", "asr", "ror", +}; + +static char *cond_names[] = { + "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "", "nv" +}; + +static char float_precision[] = "sdep"; +static char float_rounding[] = " pmz"; +static float float_immed[] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 0.5, 10.0 }; + +static void print_ldr_str_offset(); +static void print_ldc_stc_offset(); +static long immediate_value(); + +/* Print the ARM 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 long ins; + register struct opcode *op; + register char *p; + register int i, c; + int s, e, val; + + ins = read_memory_integer(memaddr, 4); + for (i = 0, op = opcodes; i < N_OPCODES; i++, op++) + if ((ins & op->mask) == op->value) break; + assert(i != N_OPCODES); + + for (p = op->assembler; *p;) { + c = *p++; + if (c == '%') { + s = e = 0; + while (isdigit(*p)) + s = s*10 + (*p++ - '0'); + if (*p == '-') { + p++; + while (isdigit(*p)) + e = e*10 + (*p++ - '0'); + } else + e = s; + assert(s >= 0 && s <= 31 && e >= 0 && e <= 31); + val = (ins >> s) & ((1 << (e + 1 - s)) - 1); + switch (*p++) { + case '%' : + putc('%', stream); + break; + case 'd' : + fprintf(stream, "%d", val); + break; + case 'x' : + fprintf(stream, "%x", val); + break; + case 'r' : + assert(val >= 0 && val <= 15); + fprintf(stream, "%s", reg_names[val]); + break; + case 'c' : + fprintf(stream, "%s", cond_names[ins >> 28]); + break; + case '\'' : + assert(*p); + c = *p++; + if (val) + putc(c, stream); + break; + case '`' : + assert(*p); + c = *p++; + if (!val) + putc(c, stream); + break; + case '?' : + assert(*p); + c = *p++; + assert(*p); + if (val) + p++; + else + c = *p++; + putc(c, stream); + break; + case 'p' : + if (((ins >> 12) & 0xf) == 0xf) + putc('p', stream); + break; + case 'o' : + if (ins & (1<<25)) { + int immed = immediate_value(ins & 0xfff); + fprintf (stream, "#%d (0x%x)", immed, immed); + } else { + int operand2 = ins & 0xfff; + /* in operand2 : + bits 0-3 are the base register + bits 5-6 are the shift (0=lsl, 1=lsr, 2=asr, 3=ror) + if bit 4 is zero then bits 7-11 are an immediate shift count + else bit 7 must be zero and bits 8-11 are the register + to be used as a shift count. + Note: no shift at all is encoded as "reg lsl #0" */ + fprintf (stream, "%s", reg_names[operand2 & 0xf]); + if (operand2 & 0xff0) { + /* ror #0 is really rrx (rotate right extend) */ + if ((operand2 & 0xff0) == 0x060) + fprintf (stream, ", rrx"); + else { + fprintf (stream, ", %s ", + shift_names[(operand2 >> 5) & 3]); + if (operand2 & (1<<4)) /* register shift */ + fprintf (stream, "%s", + reg_names[operand2 >> 8]); + else /* immediate shift */ + fprintf (stream, "#%d", + operand2 >> 7); + } + } + } + break; + case 'a' : + fprintf (stream, "[%s", reg_names[(ins >> 16) & 0xf]); + if (ins & (1<<24)) { + fprintf (stream, ", "); + print_ldr_str_offset (ins, stream); + putc (']', stream); + if (ins & (1<<21)) putc('!', stream); + /* If it is a pc relative load, then it is probably + a constant so print it */ + if (((ins >> 16) & 0xf) == 15 && + (ins & (1<<25)) == 0 && + (ins & (1<<20))) { + int addr = memaddr + 8 + + (ins & 0xfff) * ((ins & (1<<23)) ? 1 : -1); + fprintf (stream, " (contents="); + print_address (read_memory_integer(addr, 4), stream); + fprintf (stream, ")"); + } + } else { + fprintf (stream, "]," ); + print_ldr_str_offset (ins, stream); + } + break; + case 'b' : + print_address (memaddr + 8 + (((int)ins << 8) >> 6), stream); + break; + case 'A' : + fprintf (stream, "[%s", reg_names[(ins >> 16) & 0xf]); + if (ins & (1<<24)) { + fprintf (stream, ", "); + print_ldc_stc_offset (ins, stream); + putc(']', stream); + if (ins & (1<<21)) + putc('!', stream); + } else { + fprintf (stream, "], "); + print_ldc_stc_offset (ins, stream); + } + break; + case 'm' : + { + int regnum, first = 1; + putc('{', stream); + for (regnum = 0; regnum < 16; regnum++) + if (ins & (1<> 18) & 2) | ((ins >> 7) & 1); + putc(float_precision[val], stream); + break; + case 'Q' : + val = ((ins >> 21) & 2) | ((ins >> 15) & 1); + putc(float_precision[val], stream); + break; + case 'R' : + val = ((ins >> 5) & 3); + if (val) putc(float_rounding[val], stream); + break; + case 'f' : + assert(val >= 0 && val <= 15); + if (val > 7) + fprintf (stream, "#%3.1f", float_immed[val - 8]); + else + fprintf (stream, "f%d", val); + break; + default: + abort(); + } + } else + putc(c, stream); + } + return 4; +} + +static long +immediate_value(operand) +int operand; +{ + int val = operand & 0xff; + int shift = 2*(operand >> 8); + /* immediate value is (val ror shift) */ + return (val >> shift) | (val << (32 - shift)); +} + +static void +print_ldr_str_offset(ins, stream) +unsigned long ins; +FILE *stream; +{ + if ((ins & (1<<25)) == 0) + fprintf (stream, "#%d", + (ins & 0xfff) * ((ins & (1<<23)) ? 1 : -1)); + else { + fprintf (stream, "%s%s", reg_names[ins & 0xf], + (ins & (1<<23)) ? "" : "-"); + if (ins & 0xff0) + fprintf (stream, ", %s #%d", + shift_names[(ins >> 5) & 3], + (ins >> 7) & 0x1f); + } +} + +static void +print_ldc_stc_offset(ins, stream) +unsigned long ins; +FILE *stream; +{ + fprintf (stream, "#%d", + 4 * (ins & 0xff) * ((ins & (1<<23)) ? 1 : -1)); +} diff --git a/gdb/arm-xdep.c b/gdb/arm-xdep.c new file mode 100644 index 00000000000..b3979748abf --- /dev/null +++ b/gdb/arm-xdep.c @@ -0,0 +1,274 @@ +/* Acorn Risc Machine host machine support. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "arm-opcode.h" + +#include +#include +#include +#include +#include +#include +#include + +#define N_TXTADDR(hdr) 0x8000 +#define N_DATADDR(hdr) (hdr.a_text + 0x8000) + +#include "gdbcore.h" + +#include /* After a.out.h */ +#include +#include + +#include + +void +fetch_inferior_registers (regno) + int regno; +{ + 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 (PT_READ_U, inferior_pid, offset, 0) - KERNEL_U_ADDR; + + registers_fetched (); + + for (regno = 0; regno < 16; regno++) + { + regaddr = offset + regno * 4; + *(int *)&buf[0] = ptrace (PT_READ_U, inferior_pid, regaddr, 0); + if (regno == PC_REGNUM) + *(int *)&buf[0] = GET_PC_PART(*(int *)&buf[0]); + supply_register (regno, buf); + } + *(int *)&buf[0] = ptrace (PT_READ_U, inferior_pid, offset + PC*4); + supply_register (PS_REGNUM, buf); /* set virtual register ps same as pc */ + + /* read the floating point registers */ + offset = (char *) &u.u_fp_regs - (char *)&u; + *(int *)buf = ptrace (PT_READ_U, inferior_pid, offset, 0); + supply_register (FPS_REGNUM, buf); + for (regno = 16; regno < 24; regno++) { + regaddr = offset + 4 + 12 * (regno - 16); + for (i = 0; i < 12; i += sizeof(int)) + *(int *) &buf[i] = ptrace (PT_READ_U, inferior_pid, regaddr + i, 0); + 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 long value; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (PT_READ_U, inferior_pid, offset, 0) - KERNEL_U_ADDR; + + if (regno >= 0) { + if (regno >= 16) return; + regaddr = offset + 4 * regno; + errno = 0; + value = read_register(regno); + if (regno == PC_REGNUM) + value = SET_PC_PART(read_register (PS_REGNUM), value); + ptrace (PT_WRITE_U, inferior_pid, regaddr, value); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else for (regno = 0; regno < 15; regno++) + { + regaddr = offset + regno * 4; + errno = 0; + value = read_register(regno); + if (regno == PC_REGNUM) + value = SET_PC_PART(read_register (PS_REGNUM), value); + ptrace (6, inferior_pid, regaddr, value); + if (errno != 0) + { + sprintf (buf, "writing all regs, number %d", regno); + perror_with_name (buf); + } + } +} + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +/* Structure to describe the chain of shared libraries used + by the execfile. + e.g. prog shares Xt which shares X11 which shares c. */ + +struct shared_library { + struct exec_header header; + char name[SHLIBLEN]; + CORE_ADDR text_start; /* CORE_ADDR of 1st byte of text, this file */ + long data_offset; /* offset of data section in file */ + int chan; /* file descriptor for the file */ + struct shared_library *shares; /* library this one shares */ +}; +static struct shared_library *shlib = 0; + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +static CORE_ADDR unshared_text_start; + +/* extended header from exec file (for shared library info) */ + +static struct exec_header exec_header; + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + + unsigned int reg_offset, fp_reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + + /* We are depending on exec_file_command having been called + previously to set exec_data_start. Since the executable + and the core file share the same text segment, the address + of the data segment will be the same in both. */ + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* Some machines put an absolute address in here and some put + the offset in the upage of the regs. */ + reg_offset = (int) u.u_ar0; + if (reg_offset > NBPG * UPAGES) + reg_offset -= KERNEL_U_ADDR; + fp_reg_offset = (char *) &u.u_fp_regs - (char *)&u; + + /* 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]; + + if (regno < 16) + val = lseek (corechan, reg_offset + 4 * regno, 0); + else if (regno < 24) + val = lseek (corechan, fp_reg_offset + 4 + 12*(regno - 24), 0); + else if (regno == 24) + val = lseek (corechan, fp_reg_offset, 0); + else if (regno == 25) + val = lseek (corechan, reg_offset + 4 * PC, 0); + if (val < 0 + || (val = myread (corechan, buf, sizeof buf)) < 0) + { + char * buffer = (char *) alloca (strlen (reg_names[regno]) + + 30); + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + + if (regno == PC_REGNUM) + *(int *)buf = GET_PC_PART(*(int *)buf); + 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"); +} diff --git a/gdb/command.c b/gdb/command.c new file mode 100644 index 00000000000..0b541a7cc63 --- /dev/null +++ b/gdb/command.c @@ -0,0 +1,1150 @@ +/* Library for reading command lines and decoding commands. + Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "command.h" +#include "symtab.h" +#include "value.h" +#include +#include +#include + +extern char *getenv (); + +/* Add element named NAME to command list *LIST. + FUN should be the function to execute the command; + it will get a character string as argument, with leading + and trailing blanks already eliminated. + + DOC is a documentation string for the command. + Its first line should be a complete sentence. + It should start with ? for a command that is an abbreviation + or with * for a command that most users don't need to know about. */ + +struct cmd_list_element * +add_cmd (name, class, fun, doc, list) + char *name; + enum command_class class; + void (*fun) (); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + delete_cmd (name, list); + c->next = *list; + c->name = name; + c->class = class; + c->function = fun; + c->doc = doc; + c->prefixlist = 0; + c->prefixname = (char *)NULL; + c->allow_unknown = 0; + c->abbrev_flag = 0; + c->aux = 0; + c->type = not_set_cmd; + c->completer = make_symbol_completion_list; + c->var = 0; + c->var_type = var_boolean; + c->user_commands = 0; + *list = c; + return c; +} + +/* Same as above, except that the abbrev_flag is set. */ + +struct cmd_list_element * +add_abbrev_cmd (name, class, fun, doc, list) + char *name; + enum command_class class; + void (*fun) (); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = add_cmd (name, class, fun, doc, list); + + c->abbrev_flag = 1; + return c; +} + +struct cmd_list_element * +add_alias_cmd (name, oldname, class, abbrev_flag, list) + char *name; + char *oldname; + enum command_class class; + int abbrev_flag; + struct cmd_list_element **list; +{ + /* Must do this since lookup_cmd tries to side-effect its first arg */ + char *copied_name; + register struct cmd_list_element *old; + register struct cmd_list_element *c; + copied_name = (char *) alloca (strlen (oldname) + 1); + strcpy (copied_name, oldname); + old = lookup_cmd (&copied_name, *list, "", 1, 1); + + if (old == 0) + { + delete_cmd (name, list); + return 0; + } + + c = add_cmd (name, class, old->function, old->doc, list); + c->prefixlist = old->prefixlist; + c->prefixname = old->prefixname; + c->allow_unknown = old->allow_unknown; + c->abbrev_flag = abbrev_flag; + c->aux = old->aux; + return c; +} + +/* Like add_cmd but adds an element for a command prefix: + a name that should be followed by a subcommand to be looked up + in another command list. PREFIXLIST should be the address + of the variable containing that list. */ + +struct cmd_list_element * +add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + enum command_class class; + void (*fun) (); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + return c; +} + +/* Like add_prefix_cmd butsets the abbrev_flag on the new command. */ + +struct cmd_list_element * +add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + enum command_class class; + void (*fun) (); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + c->abbrev_flag = 1; + return c; +} + +void +not_just_help_class_command (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ +} + +/* Add element named NAME to command list LIST (the list for set + or some sublist thereof). + CLASS is as in add_cmd. + VAR_TYPE is the kind of thing we are setting. + VAR is address of the variable being controlled by this command. + DOC is the documentation string. */ +struct cmd_list_element * +add_set_cmd (name, class, var_type, var, doc, list) + char *name; + enum command_class class; + var_types var_type; + char *var; + char *doc; + struct cmd_list_element **list; +{ + /* For set/show, we have to call do_setshow_command + differently than an ordinary function (take commandlist as + well as arg), so the function field isn't helpful. However, + function == NULL means that it's a help class, so set the function + to not_just_help_class_command. */ + struct cmd_list_element *c + = add_cmd (name, class, not_just_help_class_command, doc, list); + + c->type = set_cmd; + c->var_type = var_type; + c->var = var; + return c; +} + +/* Where SETCMD has already been added, add the corresponding show + command to LIST and return a pointer to it. */ +struct cmd_list_element * +add_show_from_set (setcmd, list) + struct cmd_list_element *setcmd; + struct cmd_list_element **list; +{ + struct cmd_list_element *showcmd = + (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + bcopy (setcmd, showcmd, sizeof (struct cmd_list_element)); + delete_cmd (showcmd->name, list); + showcmd->type = show_cmd; + + /* Replace "set " at start of docstring with "show ". */ + if (setcmd->doc[0] == 'S' && setcmd->doc[1] == 'e' + && setcmd->doc[2] == 't' && setcmd->doc[3] == ' ') + showcmd->doc = concat ("Show ", setcmd->doc + 4, ""); + else + fprintf (stderr, "GDB internal error: Bad docstring for set command\n"); + + showcmd->next = *list; + *list = showcmd; + return showcmd; +} + +/* Remove the command named NAME from the command list. */ + +void +delete_cmd (name, list) + char *name; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c; + struct cmd_list_element *p; + + while (*list && !strcmp ((*list)->name, name)) + { + p = (*list)->next; + free (*list); + *list = p; + } + + if (*list) + for (c = *list; c->next;) + { + if (!strcmp (c->next->name, name)) + { + p = c->next->next; + free (c->next); + c->next = p; + } + else + c = c->next; + } +} + +void help_cmd (), help_list (), help_cmd_list (); + +/* This command really has to deal with two things: + * 1) I want documentation on *this string* (usually called by + * "help commandname"). + * 2) I want documentation on *this list* (usually called by + * giving a command that requires subcommands. Also called by saying + * just "help".) + * + * I am going to split this into two seperate comamnds, help_cmd and + * help_list. + */ + +void +help_cmd (command, stream) + char *command; + FILE *stream; +{ + struct cmd_list_element *c; + extern struct cmd_list_element *cmdlist; + + if (!command) + { + help_list (cmdlist, "", all_classes, stream); + return; + } + + c = lookup_cmd (&command, cmdlist, "", 0, 0); + + if (c == 0) + return; + + /* There are three cases here. + If c->prefixlist is nonzero, we have a prefix command. + Print its documentation, then list its subcommands. + + If c->function is nonzero, we really have a command. + Print its documentation and return. + + If c->function is zero, we have a class name. + Print its documentation (as if it were a command) + and then set class to the number of this class + so that the commands in the class will be listed. */ + + fputs_filtered (c->doc, stream); + fputs_filtered ("\n", stream); + + if (c->prefixlist == 0 && c->function != 0) + return; + fprintf_filtered (stream, "\n"); + + /* If this is a prefix command, print it's subcommands */ + if (c->prefixlist) + help_list (*c->prefixlist, c->prefixname, all_commands, stream); + + /* If this is a class name, print all of the commands in the class */ + if (c->function == 0) + help_list (cmdlist, "", c->class, stream); +} + +/* + * Get a specific kind of help on a command list. + * + * LIST is the list. + * CMDTYPE is the prefix to use in the title string. + * CLASS is the class with which to list the nodes of this list (see + * documentation for help_cmd_list below), As usual, ALL_COMMANDS for + * everything, ALL_CLASSES for just classes, and non-negative for only things + * in a specific class. + * and STREAM is the output stream on which to print things. + * If you call this routine with a class >= 0, it recurses. + */ +void +help_list (list, cmdtype, class, stream) + struct cmd_list_element *list; + char *cmdtype; + enum command_class class; + FILE *stream; +{ + int len; + char *cmdtype1, *cmdtype2; + + /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */ + len = strlen (cmdtype); + cmdtype1 = (char *) alloca (len + 1); + cmdtype1[0] = 0; + cmdtype2 = (char *) alloca (len + 4); + cmdtype2[0] = 0; + if (len) + { + cmdtype1[0] = ' '; + strncpy (cmdtype1 + 1, cmdtype, len - 1); + cmdtype1[len] = 0; + strncpy (cmdtype2, cmdtype, len - 1); + strcpy (cmdtype2 + len - 1, " sub"); + } + + if (class == all_classes) + fprintf_filtered (stream, "List of classes of %scommands:\n\n", cmdtype2); + else + fprintf_filtered (stream, "List of %scommands:\n\n", cmdtype2); + + help_cmd_list (list, class, cmdtype, (int)class >= 0, stream); + + if (class == all_classes) + fprintf_filtered (stream, "\n\ +Type \"help%s\" followed by a class name for a list of commands in that class.", + cmdtype1); + + fprintf_filtered (stream, "\n\ +Type \"help%s\" followed by %scommand name for full documentation.\n\ +Command name abbreviations are allowed if unambiguous.\n", + cmdtype1, cmdtype2); +} + +/* Print only the first line of STR on STREAM. */ +static void +print_doc_line (stream, str) + FILE *stream; + char *str; +{ + static char *line_buffer = 0; + static int line_size; + register char *p; + + if (!line_buffer) + { + line_size = 80; + line_buffer = (char *) xmalloc (line_size); + } + + p = str; + while (*p && *p != '\n' && *p != '.' && *p != ',') + p++; + if (p - str > line_size - 1) + { + line_size = p - str + 1; + free (line_buffer); + line_buffer = (char *) xmalloc (line_size); + } + strncpy (line_buffer, str, p - str); + line_buffer[p - str] = '\0'; + if (islower (line_buffer[0])) + line_buffer[0] = toupper (line_buffer[0]); + fputs_filtered (line_buffer, stream); +} + +/* + * Implement a help command on command list LIST. + * RECURSE should be non-zero if this should be done recursively on + * all sublists of LIST. + * PREFIX is the prefix to print before each command name. + * STREAM is the stream upon which the output should be written. + * CLASS should be: + * A non-negative class number to list only commands in that + * class. + * ALL_COMMANDS to list all commands in list. + * ALL_CLASSES to list all classes in list. + * + * Note that RECURSE will be active on *all* sublists, not just the + * ones seclected by the criteria above (ie. the selection mechanism + * is at the low level, not the high-level). + */ +void +help_cmd_list (list, class, prefix, recurse, stream) + struct cmd_list_element *list; + enum command_class class; + char *prefix; + int recurse; + FILE *stream; +{ + register struct cmd_list_element *c; + + for (c = list; c; c = c->next) + { + if (c->abbrev_flag == 0 && + (class == all_commands + || (class == all_classes && c->function == 0) + || (class == c->class && c->function != 0))) + { + fprintf_filtered (stream, "%s%s -- ", prefix, c->name); + print_doc_line (stream, c->doc); + fputs_filtered ("\n", stream); + } + if (recurse + && c->prefixlist != 0 + && c->abbrev_flag == 0) + help_cmd_list (*c->prefixlist, class, c->prefixname, 1, stream); + } +} + +/* This routine takes a line of TEXT and a CLIST in which to + start the lookup. When it returns it will have incremented the text + pointer past the section of text it matched, set *RESULT_LIST to + the list in which the last word was matched, and will return the + cmd list element which the text matches. It will return 0 if no + match at all was possible. It will return -1 if ambigous matches are + possible; in this case *RESULT_LIST will be set to the list in which + there are ambiguous choices (and text will be set to the ambiguous + text string). + + It does no error reporting whatsoever; control will always return + to the superior routine. + + In the case of an ambiguous return (-1), *RESULT_LIST will be set to + point at the prefix_command (ie. the best match) *or* (special + case) will be 0 if no prefix command was ever found. For example, + in the case of "info a", "info" matches without ambiguity, but "a" + could be "args" or "address", so *RESULT_LIST is set to + the cmd_list_element for "info". So in this case + result list should not be interpeted as a pointer to the beginning + of a list; it simply points to a specific command. + + If RESULT_LIST is NULL, don't set *RESULT_LIST (but don't otherwise + affect the operation). + + This routine does *not* modify the text pointed to by TEXT. + + If IGNORE_HELP_CLASSES is nonzero, ignore any command list + elements which are actually help classes rather than commands (i.e. + the function field of the struct cmd_list_element is 0). */ + +struct cmd_list_element * +lookup_cmd_1 (text, clist, result_list, ignore_help_classes) + char **text; + struct cmd_list_element *clist, **result_list; + int ignore_help_classes; +{ + char *p, *command; + int len, tmp, nfound; + struct cmd_list_element *found, *c; + + while (**text == ' ' || **text == '\t') + (*text)++; + + /* Treating underscores as part of command words is important + so that "set args_foo()" doesn't get interpreted as + "set args _foo()". */ + for (p = *text; + *p && (isalnum(*p) || *p == '-' || *p == '_'); + p++) + ; + + /* If nothing but whitespace, return 0. */ + if (p == *text) + return 0; + + len = p - *text; + + /* *text and p now bracket the first command word to lookup (and + it's length is len). We copy this into a local temporary, + converting to lower case as we go. */ + + command = (char *) alloca (len + 1); + for (tmp = 0; tmp < len; tmp++) + { + char x = (*text)[tmp]; + command[tmp] = (x >= 'A' && x <= 'Z') ? x - 'A' + 'a' : x; + } + command[len] = '\0'; + + /* Look it up. */ + found = 0; + nfound = 0; + for (c = clist; c; c = c->next) + if (!strncmp (command, c->name, len) + && (!ignore_help_classes || c->function)) + { + found = c; + nfound++; + if (c->name[len] == '\0') + { + nfound = 1; + break; + } + } + + /* If nothing matches, we have a simple failure. */ + if (nfound == 0) + return 0; + + if (nfound > 1) + { + if (result_list != NULL) + /* Will be modified in calling routine + if we know what the prefix command is. */ + *result_list = 0; + return (struct cmd_list_element *) -1; /* Ambiguous. */ + } + + /* We've matched something on this list. Move text pointer forward. */ + + *text = p; + if (found->prefixlist) + { + c = lookup_cmd_1 (text, *found->prefixlist, result_list, + ignore_help_classes); + if (!c) + { + /* Didn't find anything; this is as far as we got. */ + if (result_list != NULL) + *result_list = clist; + return found; + } + else if (c == (struct cmd_list_element *) -1) + { + /* We've gotten this far properley, but the next step + is ambiguous. We need to set the result list to the best + we've found (if an inferior hasn't already set it). */ + if (result_list != NULL) + if (!*result_list) + /* This used to say *result_list = *found->prefixlist + If that was correct, need to modify the documentation + at the top of this function to clarify what is supposed + to be going on. */ + *result_list = found; + return c; + } + else + { + /* We matched! */ + return c; + } + } + else + { + if (result_list != NULL) + *result_list = clist; + return found; + } +} + +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. + + If INGNORE_HELP_CLASSES is nonzero, ignore any command list + elements which are actually help classes rather than commands (i.e. + the function field of the struct cmd_list_element is 0). */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown, ignore_help_classes) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; + int ignore_help_classes; +{ + struct cmd_list_element *last_list = 0; + struct cmd_list_element *c = + lookup_cmd_1 (line, list, &last_list, ignore_help_classes); + char *ptr = (*line) + strlen (*line) - 1; + + /* Clear off trailing whitespace. */ + while (ptr >= *line && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; + + if (!c) + { + if (!allow_unknown) + { + if (!*line) + error ("Lack of needed %scommand", cmdtype); + else + { + char *p = *line, *q; + + while (isalnum(*p) || *p == '-') + p++; + + q = (char *) alloca (p - *line + 1); + strncpy (q, *line, p - *line); + q[p-*line] = '\0'; + + error ("Undefined %scommand: \"%s\".", cmdtype, q); + } + } + else + return 0; + } + else if (c == (struct cmd_list_element *) -1) + { + /* Ambigous. Local values should be off prefixlist or called + values. */ + int local_allow_unknown = (last_list ? last_list->allow_unknown : + allow_unknown); + char *local_cmdtype = last_list ? last_list->prefixname : cmdtype; + struct cmd_list_element *local_list = + (last_list ? *(last_list->prefixlist) : list); + + if (local_allow_unknown < 0) + { + if (last_list) + return last_list; /* Found something. */ + else + return 0; /* Found nothing. */ + } + else + { + /* Report as error. */ + int amb_len; + char ambbuf[100]; + + for (amb_len = 0; + ((*line)[amb_len] && (*line)[amb_len] != ' ' + && (*line)[amb_len] != '\t'); + amb_len++) + ; + + ambbuf[0] = 0; + for (c = local_list; c; c = c->next) + if (!strncmp (*line, c->name, amb_len)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < (int)sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", local_cmdtype, + *line, ambbuf); + return 0; /* lint */ + } + } + else + { + /* We've got something. It may still not be what the caller + wants (if this command *needs* a subcommand). */ + while (**line == ' ' || **line == '\t') + (*line)++; + + if (c->prefixlist && **line && !c->allow_unknown) + error ("Undefined %scommand: \"%s\".", c->prefixname, *line); + + /* Seems to be what he wants. Return it. */ + return c; + } + return 0; +} + +#if 0 +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; +{ + register char *p; + register struct cmd_list_element *c, *found; + int nfound; + char ambbuf[100]; + char *processed_cmd; + int i, cmd_len; + + /* Skip leading whitespace. */ + + while (**line == ' ' || **line == '\t') + (*line)++; + + /* Clear out trailing whitespace. */ + + p = *line + strlen (*line); + while (p != *line && (p[-1] == ' ' || p[-1] == '\t')) + p--; + *p = 0; + + /* Find end of command name. */ + + p = *line; + while (*p == '-' + || (*p >= 'a' && *p <= 'z') + || (*p >= 'A' && *p <= 'Z') + || (*p >= '0' && *p <= '9')) + p++; + + /* Look up the command name. + If exact match, keep that. + Otherwise, take command abbreviated, if unique. Note that (in my + opinion) a null string does *not* indicate ambiguity; simply the + end of the argument. */ + + if (p == *line) + { + if (!allow_unknown) + error ("Lack of needed %scommand", cmdtype); + return 0; + } + + /* Copy over to a local buffer, converting to lowercase on the way. + This is in case the command being parsed is a subcommand which + doesn't match anything, and that's ok. We want the original + untouched for the routine of the original command. */ + + processed_cmd = (char *) alloca (p - *line + 1); + for (cmd_len = 0; cmd_len < p - *line; cmd_len++) + { + char x = (*line)[cmd_len]; + if (x >= 'A' && x <= 'Z') + processed_cmd[cmd_len] = x - 'A' + 'a'; + else + processed_cmd[cmd_len] = x; + } + processed_cmd[cmd_len] = '\0'; + + /* Check all possibilities in the current command list. */ + found = 0; + nfound = 0; + for (c = list; c; c = c->next) + { + if (!strncmp (processed_cmd, c->name, cmd_len)) + { + found = c; + nfound++; + if (c->name[cmd_len] == 0) + { + nfound = 1; + break; + } + } + } + + /* Report error for undefined command name. */ + + if (nfound != 1) + { + if (nfound > 1 && allow_unknown >= 0) + { + ambbuf[0] = 0; + for (c = list; c; c = c->next) + if (!strncmp (processed_cmd, c->name, cmd_len)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", cmdtype, + processed_cmd, ambbuf); + } + else if (!allow_unknown) + error ("Undefined %scommand: \"%s\".", cmdtype, processed_cmd); + return 0; + } + + /* Skip whitespace before the argument. */ + + while (*p == ' ' || *p == '\t') p++; + *line = p; + + if (found->prefixlist && *p) + { + c = lookup_cmd (line, *found->prefixlist, found->prefixname, + found->allow_unknown); + if (c) + return c; + } + + return found; +} +#endif + +/* Helper function for SYMBOL_COMPLETION_FUNCTION. */ + +/* Return a vector of char pointers which point to the different + possible completions in LIST of TEXT. */ + +char ** +complete_on_cmdlist (list, text) + struct cmd_list_element *list; + char *text; +{ + struct cmd_list_element *ptr; + char **matchlist; + int sizeof_matchlist; + int matches; + int textlen = strlen (text); + + sizeof_matchlist = 10; + matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *)); + matches = 0; + + for (ptr = list; ptr; ptr = ptr->next) + if (!strncmp (ptr->name, text, textlen) + && !ptr->abbrev_flag + && (ptr->function + || ptr->prefixlist)) + { + if (matches == sizeof_matchlist) + { + sizeof_matchlist *= 2; + matchlist = (char **) xrealloc ((char *)matchlist, + (sizeof_matchlist + * sizeof (char *))); + } + + matchlist[matches] = (char *) + xmalloc (strlen (ptr->name) + 1); + strcpy (matchlist[matches++], ptr->name); + } + + if (matches == 0) + { + free (matchlist); + matchlist = 0; + } + else + { + matchlist = (char **) xrealloc ((char *)matchlist, ((matches + 1) + * sizeof (char *))); + matchlist[matches] = (char *) 0; + } + + return matchlist; +} + +static int +parse_binary_operation (arg) + char *arg; +{ + int length; + + if (!arg || !*arg) + return 1; + + length = strlen (arg); + + while (arg[length - 1] == ' ' || arg[length - 1] == '\t') + length--; + + if (!strncmp (arg, "on", length) + || !strncmp (arg, "1", length) + || !strncmp (arg, "yes", length)) + return 1; + else + if (!strncmp (arg, "off", length) + || !strncmp (arg, "0", length) + || !strncmp (arg, "no", length)) + return 0; + else + { + error ("\"on\" or \"off\" expected."); + return 0; + } +} + +/* Do a "set" or "show" command. ARG is NULL if no argument, or the text + of the argument, and FROM_TTY is nonzero if this command is being entered + directly by the user (i.e. these are just like any other + command). C is the command list element for the command. */ +void +do_setshow_command (arg, from_tty, c) + char *arg; + int from_tty; + struct cmd_list_element *c; +{ + if (c->type == set_cmd) + { + switch (c->var_type) + { + case var_string: + { + char *new; + char *p; + char *q; + int ch; + + if (arg == NULL) + arg = ""; + new = (char *) xmalloc (strlen (arg) + 2); + p = arg; q = new; + while (ch = *p++) + { + if (ch == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + break; + ch = parse_escape (&p); + if (ch == 0) + break; /* C loses */ + else if (ch > 0) + *q++ = ch; + } + else + *q++ = ch; + } + if (*(p - 1) != '\\') + *q++ = ' '; + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **) c->var = new; + } + break; + case var_string_noescape: + if (arg == NULL) + arg = ""; + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **) c->var = savestring (arg, strlen (arg)); + break; + case var_filename: + if (arg == NULL) + error_no_arg ("filename to set it to."); + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **)c->var = tilde_expand (arg); + break; + case var_boolean: + *(int *) c->var = parse_binary_operation (arg); + break; + case var_uinteger: + if (arg == NULL) + error_no_arg ("integer to set it to."); + *(int *) c->var = parse_and_eval_address (arg); + if (*(int *) c->var == 0) + *(int *) c->var = UINT_MAX; + break; + case var_zinteger: + if (arg == NULL) + error_no_arg ("integer to set it to."); + *(int *) c->var = parse_and_eval_address (arg); + break; + default: + error ("gdb internal error: bad var_type in do_setshow_command"); + } + } + else if (c->type == show_cmd) + { + /* Print doc minus "show" at start. */ + print_doc_line (stdout, c->doc + 5); + + fputs_filtered (" is ", stdout); + wrap_here (" "); + switch (c->var_type) + { + case var_string: + { + unsigned char *p; + fputs_filtered ("\"", stdout); + for (p = *(unsigned char **) c->var; *p != '\0'; p++) + printchar (*p, stdout, '"'); + fputs_filtered ("\"", stdout); + } + break; + case var_string_noescape: + case var_filename: + fputs_filtered ("\"", stdout); + fputs_filtered (*(char **) c->var, stdout); + fputs_filtered ("\"", stdout); + break; + case var_boolean: + fputs_filtered (*(int *) c->var ? "on" : "off", stdout); + break; + case var_uinteger: + if (*(unsigned int *) c->var == UINT_MAX) { + fputs_filtered ("unlimited", stdout); + break; + } + /* else fall through */ + case var_zinteger: + fprintf_filtered (stdout, "%d", *(unsigned int *) c->var); + break; + default: + error ("gdb internal error: bad var_type in do_setshow_command"); + } + fputs_filtered (".\n", stdout); + } + else + error ("gdb internal error: bad cmd_type in do_setshow_command"); + (*c->function) (NULL, from_tty, c); +} + +/* Show all the settings in a list of show commands. */ + +void +cmd_show_list (list, from_tty, prefix) + struct cmd_list_element *list; + int from_tty; + char *prefix; +{ + for (; list != NULL; list = list->next) { + /* If we find a prefix, run its list, prefixing our output by its + prefix (with "show " skipped). */ + if (list->prefixlist && !list->abbrev_flag) + cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5); + if (list->type == show_cmd) + { + fputs_filtered (prefix, stdout); + fputs_filtered (list->name, stdout); + fputs_filtered (": ", stdout); + do_setshow_command ((char *)NULL, from_tty, list); + } + } +} + +static void +shell_escape (arg, from_tty) + char *arg; + int from_tty; +{ + int rc, status, pid; + char *p, *user_shell; + extern char *rindex (); + + if ((user_shell = (char *) getenv ("SHELL")) == NULL) + user_shell = "/bin/sh"; + + /* Get the name of the shell for arg0 */ + if ((p = rindex (user_shell, '/')) == NULL) + p = user_shell; + else + p++; /* Get past '/' */ + + if ((pid = fork()) == 0) + { + if (!arg) + execl (user_shell, p, 0); + else + execl (user_shell, p, "-c", arg, 0); + + fprintf (stderr, "Exec of shell failed\n"); + exit (0); + } + + if (pid != -1) + while ((rc = wait (&status)) != pid && rc != -1) + ; + else + error ("Fork failed"); +} + +static void +make_command (arg, from_tty) + char *arg; + int from_tty; +{ + char *p; + + if (arg == 0) + p = "make"; + else + { + p = xmalloc (sizeof("make ") + strlen(arg)); + strcpy (p, "make "); + strcpy (p + sizeof("make ")-1, arg); + } + + shell_escape (p, from_tty); +} + +void +_initialize_command () +{ + add_com ("shell", class_support, shell_escape, + "Execute the rest of the line as a shell command. \n\ +With no arguments, run an inferior shell."); + + add_com ("make", class_support, make_command, + "Run the ``make'' program using the rest of the line as arguments."); +} diff --git a/gdb/config.gdb b/gdb/config.gdb new file mode 100755 index 00000000000..917d94e870d --- /dev/null +++ b/gdb/config.gdb @@ -0,0 +1,185 @@ +#!/bin/sh + +# Shell script to do machine-dependent things in +# preparation for compiling gdb. +# +# Usage: config.gdb machine +# +# 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 +host= +target= +list_hosts= +list_targets= +srcdir= + +for arg in $*; do + case $arg in + -srcdir=*|+srcdir=*) + srcdir=`echo $arg | sed 's/[+-]srcdir=//'` + ;; + -host|+host) + list_hosts=true + ;; + -target|+target) + list_targets=true + ;; + -host=*|+host=*) + if [ "$host" = "" ]; then + host=`echo $arg | sed 's/[+-]host=//'` + else + echo Error: Attempt to specify host machine twice + bad=true + fi + ;; + -target=*|+target=*) + if [ "$target" = "" ]; then + target=`echo $arg | sed 's/[+-]target=//'` + else + echo Error: Attempt to specify target machine twice + bad=true + fi + ;; + *) + if [ "$host" = "" ]; then + host=$arg + else + if [ "$target" = "" ]; then + target=$arg + else + echo Error: More arguments than host and target machine names + bad=true + fi + fi + ;; + esac +done + +if [ "$target" = "" ]; then target=$host; fi +if [ "$host" = "" ]; then bad=true; fi + +# Find the source files, if location was not specified +if [ "$srcdir" = "" ]; then + srcdirdefaulted=true + srcdir=. + if [ ! -r main.c ]; then + srcdir=.. + fi +fi +if [ ! -r ${srcdir}/main.c ]; then + if [ "$srcdirdefaulted" != "true" ]; then + echo "$progname: Can't find debugger sources in \`${srcdir}'." 1>&2 + else + echo "$progname: Can't find debugger sources in \`.' or \`..'." 1>&2 + fi + exit 1 +fi + +if [ "$list_hosts" = "true" ]; then + cd $srcdir/xconfig + for i in * ; do +# The {} in ${i} are required or else /bin/sh in sony newsos 3.2 removes +# the quote after it. + awk <$i "NR == 1 { lastchar = substr(\"${i}\", length(\"${i}\"), 1) +if (lastchar != \"~\" && lastchar != \"#\") \ +printf \"%-12s %s\n\", \"${i}\", substr(\$0,2) }" + done +fi + +if [ "$list_targets" = "true" ]; then + cd $srcdir/tconfig + for i in * ; do + awk <$i "NR == 1 { lastchar = substr(\"${i}\", length(\"${i}\"), 1) +if (lastchar != \"~\" && lastchar != \"#\") \ +printf \"%-12s %s\n\", \"${i}\", substr(\$0,2) }" + done +fi + +if [ "$list_hosts" = "true" -o "$list_targets" = "true" ]; then + exit 0 +fi + +if [ "$host" != "" -a ! -f $srcdir/xconfig/$host ]; then + echo "No such host $host" + bad=true +fi + +if [ "$target" != "" -a ! -f $srcdir/tconfig/$target ]; then + echo "No such target $target" + bad=true +fi + +if [ "$bad" = "true" ] ; then + echo "Usage: " + echo " $progname [+srcdir=\`dir'] machine" + echo " For normal usage" + echo " $progname [+srcdir=\`dir'] \`host' \`target'" + echo " $progname [+srcdir=\`dir'] +host=\`host' +target=\`target'" + echo " If you are doing remote debugging between machines of two" + echo " different types (cross-debugging). \`host' is the type of" + echo " machine on which GDB will be running. \`target' is the" + echo " machine that the program you are debugging will be" + echo " running on." + echo " $progname +host" + echo " Print a list of valid host machine types." + echo " $progname +target" + echo " Print a list of valid target machine types." + echo + echo " +srcdir=\`dir' means that the sources are in \`dir'. For" + echo " example, \`cd /obj/hp300; config.gdb +srcdir=/src/gdb hp300'" + echo " If +srcdir is not specified, sources can either be in \`.'" + echo " or \`..'." + echo + + if [ -r config.status ] + then + cat config.status + fi + exit 1 +fi + +rm -f tm.h xm.h + +cat $srcdir/xconfig/$host $srcdir/tconfig/$target | awk '$1 == "#msg" { + print substr($0,6)}' +paramfile=${srcdir}/`awk ' + $1 == "TM_FILE=" { print $2 }' <$srcdir/tconfig/$target` +if [ "$paramfile" != "${srcdir}/" ] ; then + # Make a symlink if possible, otherwise try a hard link + ln -s $paramfile tm.h 2>/dev/null || ln $paramfile tm.h +fi + +paramfile=${srcdir}/`awk ' + $1 == "XM_FILE=" { print $2 }' <$srcdir/xconfig/$host` +if [ "$paramfile" != "${srcdir}/" ] ; then + # Make a symlink if possible, otherwise try a hard link + ln -s $paramfile xm.h 2>/dev/null || ln $paramfile xm.h +fi + +rm -f config.status + +case ${srcdir} in + .) + ;; + *) + echo "srcdir=${srcdir}" >./Makefile.srcdir + grep -s "source ${srcdir}/.gdbinit" .gdbinit 2>/dev/null || \ + echo "source ${srcdir}/.gdbinit" >> .gdbinit + if [ ! -d readline ]; then + mkdir readline + # This could be a symlink, but getting the name right (because + # srcdir can be either relative or absolute) would be hairy. + cp ${srcdir}/readline/Makefile readline + fi +esac + +make "srcdir=${srcdir}" \ + "M_MAKEFILE=$srcdir/tconfig/$target $srcdir/xconfig/$host" \ + -f $srcdir/Makefile.dist Makefile + +echo "GDB is now set up for host machine $host and target machine $target." \ + | tee config.status +exit 0 diff --git a/gdb/config.status b/gdb/config.status new file mode 100755 index 00000000000..ec871762a22 --- /dev/null +++ b/gdb/config.status @@ -0,0 +1 @@ +GDB is now set up for host machine none and target machine none. diff --git a/gdb/config/3b1.mh b/gdb/config/3b1.mh new file mode 100644 index 00000000000..76fc51dd8eb --- /dev/null +++ b/gdb/config/3b1.mh @@ -0,0 +1,27 @@ +# AT&T 3b1/Unix pc +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# I don't think cc has been tried. -traditional for +# (not sure whether necessary). +CC= gcc -traditional +# GCC runs out of virtual memory. +PINSN_CC= cc + +XDEPFILES= infptrace.o coredep.o +XM_FILE= xm-3b1.h diff --git a/gdb/config/3b1.mt b/gdb/config/3b1.mt new file mode 100644 index 00000000000..8a73b460281 --- /dev/null +++ b/gdb/config/3b1.mt @@ -0,0 +1,21 @@ +# AT&T 3b1/Unix pc +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o m68k-pinsn.o +TM_FILE= tm-3b1.h diff --git a/gdb/config/altos.mh b/gdb/config/altos.mh new file mode 100644 index 00000000000..03f93bf3180 --- /dev/null +++ b/gdb/config/altos.mh @@ -0,0 +1,24 @@ +# Altos 3068 (68k, System V release 2) +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o altos-xdep.o +XM_FILE= xm-altos.h +REGEX=regex.o +REGEX1=regex.o +SYSV_DEFINE=-DSYSV diff --git a/gdb/config/altos.mt b/gdb/config/altos.mt new file mode 100644 index 00000000000..5d4389386c0 --- /dev/null +++ b/gdb/config/altos.mt @@ -0,0 +1,21 @@ +# Altos 3068 (68k, System V release 2) +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= m68k-pinsn.o exec.o +TM_FILE= tm-altos.h diff --git a/gdb/config/altosgas.mh b/gdb/config/altosgas.mh new file mode 100644 index 00000000000..2ade4471a07 --- /dev/null +++ b/gdb/config/altosgas.mh @@ -0,0 +1,27 @@ +# Altos 3068 (68k, System V release 2), using COFF encapsulation +# Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +#msg Use of the coff encapsulation features require the GNU binutils utilities +#msg To be ahead of their System V counterparts in your path. + +XDEPFILES= infptrace.o altos-xdep.o +XM_FILE= xm-altos.h +REGEX=regex.o +REGEX1=regex.o +SYSV_DEFINE=-DSYSV diff --git a/gdb/config/altosgas.mt b/gdb/config/altosgas.mt new file mode 100644 index 00000000000..3c502fc14b0 --- /dev/null +++ b/gdb/config/altosgas.mt @@ -0,0 +1,24 @@ +# Altos 3068 (68k, System V release 2), using COFF encapsulation +# Copyright (C) 1989-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +#msg Use of the coff encapsulation features require the GNU binutils utilities +#msg To be ahead of their System V counterparts in your path. + +TDEPFILES= m68k-pinsn.o exec.o +TM_FILE= tm-altosgas.h diff --git a/gdb/config/am29k b/gdb/config/am29k new file mode 100755 index 00000000000..8a9b4758a36 --- /dev/null +++ b/gdb/config/am29k @@ -0,0 +1,23 @@ +# AMD 29000 on EB29K board over a serial line. +# Copyright (C) 1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o am29k-pinsn.o remote-eb.o am29k-tdep.o +TM_FILE= tm-29k.h +# The following is for ../include/a.out.encap.h +TM_CFLAGS = -DCOFF_ENCAPSULATE -DTARGET=TARGET_AM29K diff --git a/gdb/config/arm.mh b/gdb/config/arm.mh new file mode 100644 index 00000000000..8dc057a0be9 --- /dev/null +++ b/gdb/config/arm.mh @@ -0,0 +1,21 @@ +# Acorn RISC machine running RISCiX (4.3bsd) +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o arm-xdep.o arm-convert.o +XM_FILE= xm-arm.h diff --git a/gdb/config/arm.mt b/gdb/config/arm.mt new file mode 100644 index 00000000000..d26c862a7e6 --- /dev/null +++ b/gdb/config/arm.mt @@ -0,0 +1,21 @@ +# Acorn RISC machine running RISCiX (4.3bsd) +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= arm-tdep.o arm-pinsn.o +TM_FILE= tm-arm.h diff --git a/gdb/config/bigmips.mh b/gdb/config/bigmips.mh new file mode 100644 index 00000000000..1b1cd48691f --- /dev/null +++ b/gdb/config/bigmips.mh @@ -0,0 +1,21 @@ +# Big-endian MIPS machine such as Sony News +# Copyright (C) 1989-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o mips-xdep.o coredep.o +XM_FILE= xm-bigmips.h diff --git a/gdb/config/bigmips.mt b/gdb/config/bigmips.mt new file mode 100644 index 00000000000..0e594d86ea4 --- /dev/null +++ b/gdb/config/bigmips.mt @@ -0,0 +1,21 @@ +# Big-endian MIPS machine such as Sony News +# Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= mips-pinsn.o mips-tdep.o mipsread.o exec.o +TM_FILE= tm-bigmips.h diff --git a/gdb/config/convex.mh b/gdb/config/convex.mh new file mode 100644 index 00000000000..b681f2881a7 --- /dev/null +++ b/gdb/config/convex.mh @@ -0,0 +1,21 @@ +# Convex Unix (4bsd) +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= convex-xdep.o +XM_FILE= xm-convex.h diff --git a/gdb/config/convex.mt b/gdb/config/convex.mt new file mode 100644 index 00000000000..f7938a242ec --- /dev/null +++ b/gdb/config/convex.mt @@ -0,0 +1,21 @@ +# Convex Unix (4bsd) +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= convex-tdep.o convex-pinsn.o +TM_FILE= tm-convex.h diff --git a/gdb/config/hp300bsd.mh b/gdb/config/hp300bsd.mh new file mode 100644 index 00000000000..ae3bb82b52d --- /dev/null +++ b/gdb/config/hp300bsd.mh @@ -0,0 +1,21 @@ +# Hewlett-Packard 9000 series 300, running BSD +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o +XM_FILE= xm-hp300bsd.h diff --git a/gdb/config/hp300bsd.mt b/gdb/config/hp300bsd.mt new file mode 100644 index 00000000000..ea03374da9e --- /dev/null +++ b/gdb/config/hp300bsd.mt @@ -0,0 +1,21 @@ +# Hewlett-Packard 9000 series 300, running BSD +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o m68k-pinsn.o +TM_FILE= tm-hp300bsd.h diff --git a/gdb/config/hp300hpux.mh b/gdb/config/hp300hpux.mh new file mode 100644 index 00000000000..3488ef05435 --- /dev/null +++ b/gdb/config/hp300hpux.mh @@ -0,0 +1,33 @@ +# Hewlett-Packard 9000 series 300, running HPUX +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The following is true because gcc uses a different .o file format +# than the native HPUX compiler +#msg If you compile GDB with GCC on HPUX, you must make sure +#msg that the `nm' used in `munch' is GNU nm +#msg + +# The headers in the directory hp-include override system headers +# and tell GDB to use BSD executable file format (hence -Ihp-include) +XDEPFILES= infptrace.o hp300hpux-xdep.o +XM_FILE= xm-hp300hpux.h +SYSV_DEFINE=-DSYSV +REGEX=regex.o +REGEX1=regex.o +ALLOCA=alloca.o diff --git a/gdb/config/hp300hpux.mt b/gdb/config/hp300hpux.mt new file mode 100644 index 00000000000..cee6ba7a138 --- /dev/null +++ b/gdb/config/hp300hpux.mt @@ -0,0 +1,28 @@ +# Hewlett-Packard 9000 series 300, running HPUX +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +#msg Note that GDB only can read symbols from programs that were +#msg compiled with GCC +#msg + +# The headers in the directory hp-include override system headers +# and tell GDB to use BSD executable file format (hence -Ihp-include) +TM_CFLAGS=-Ihp-include +TDEPFILES= exec.o m68k-pinsn.o +TM_FILE= tm-hp300hpux.h diff --git a/gdb/config/i386v-g.mh b/gdb/config/i386v-g.mh new file mode 100644 index 00000000000..a14a85e281f --- /dev/null +++ b/gdb/config/i386v-g.mh @@ -0,0 +1,25 @@ +# Intel 386 running System V, using COFF encapsulation +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o i386-xdep.o +XM_FILE= xm-i386v.h +XM_CLIBS= -lPW +SYSV_DEFINE=-DSYSV +REGEX=regex.o +REGEX1=regex.o diff --git a/gdb/config/i386v-g.mt b/gdb/config/i386v-g.mt new file mode 100644 index 00000000000..b93b9ceeaec --- /dev/null +++ b/gdb/config/i386v-g.mt @@ -0,0 +1,25 @@ +# Intel 386 running System V, using COFF encapsulation +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +#msg Use of the COFF encapsulation features requires the GNU binary utilities +#msg to be ahead of their System V counterparts in your path. +#msg + +TDEPFILES= exec.o i386-tdep.o i386-pinsn.o +TM_FILE= tm-i386v-g.h diff --git a/gdb/config/i386v.mh b/gdb/config/i386v.mh new file mode 100644 index 00000000000..c65cd3704cc --- /dev/null +++ b/gdb/config/i386v.mh @@ -0,0 +1,25 @@ +# Intel 386 running System V +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o i386-xdep.o +XM_FILE= xm-i386v.h +XM_CLIBS= -lPW +SYSV_DEFINE=-DSYSV +REGEX=regex.o +REGEX1=regex.o diff --git a/gdb/config/i386v.mt b/gdb/config/i386v.mt new file mode 100644 index 00000000000..14d9b59b9c7 --- /dev/null +++ b/gdb/config/i386v.mt @@ -0,0 +1,21 @@ +# Intel 386 running System V +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o i386-tdep.o i386-pinsn.o +TM_FILE= tm-i386v.h diff --git a/gdb/config/i386v32-g.mh b/gdb/config/i386v32-g.mh new file mode 100644 index 00000000000..4dfb1a478da --- /dev/null +++ b/gdb/config/i386v32-g.mh @@ -0,0 +1,25 @@ +# Intel 386 running System V release 2, using COFF encapsulation +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o i386-xdep.o +XM_FILE= xm-i386v32.h +XM_CLIBS= -lPW +SYSV_DEFINE=-DSYSV +REGEX=regex.o +REGEX1=regex.o diff --git a/gdb/config/i386v32-g.mt b/gdb/config/i386v32-g.mt new file mode 100644 index 00000000000..243255103bb --- /dev/null +++ b/gdb/config/i386v32-g.mt @@ -0,0 +1,24 @@ +# Intel 386 running System V release 2, using COFF encapsulation +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +#msg Use of the COFF encapsulation features requires the GNU binary utilities +#msg to be ahead of their System V counterparts in your path. + +TDEPFILES= exec.o i386-tdep.o i386-pinsn.o +TM_FILE= tm-i386v-g.h diff --git a/gdb/config/i386v32.mh b/gdb/config/i386v32.mh new file mode 100644 index 00000000000..c184745f28c --- /dev/null +++ b/gdb/config/i386v32.mh @@ -0,0 +1,25 @@ +# Intel 386 running System V release 2 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o i386-xdep.o +XM_FILE= xm-i386v32.h +XM_CLIBS= -lPW +SYSV_DEFINE=-DSYSV +REGEX=regex.o +REGEX1=regex.o diff --git a/gdb/config/i386v32.mt b/gdb/config/i386v32.mt new file mode 100644 index 00000000000..5cca19dc3f5 --- /dev/null +++ b/gdb/config/i386v32.mt @@ -0,0 +1,21 @@ +# Intel 386 running System V release 2 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o i386-tdep.o i386-pinsn.o +TM_FILE= tm-i386v.h diff --git a/gdb/config/i960.mt b/gdb/config/i960.mt new file mode 100644 index 00000000000..d92b73e4a8c --- /dev/null +++ b/gdb/config/i960.mt @@ -0,0 +1,23 @@ +# Intel 80960, under NINDY or under VxWorks, selected at runtime. +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +#msg +#msg You must specify either "nindy960" or "vxworks960"; there is no +#msg generic i960 target any more. +#msg diff --git a/gdb/config/isi.mh b/gdb/config/isi.mh new file mode 100644 index 00000000000..1ae1c7ae650 --- /dev/null +++ b/gdb/config/isi.mh @@ -0,0 +1,21 @@ +# ISI Optimum V (3.05) under 4.3bsd. +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o +XM_FILE= xm-isi.h diff --git a/gdb/config/isi.mt b/gdb/config/isi.mt new file mode 100644 index 00000000000..aab33e101a7 --- /dev/null +++ b/gdb/config/isi.mt @@ -0,0 +1,21 @@ +# ISI Optimum V (3.05) under 4.3bsd. +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o m68k-pinsn.o +TM_FILE= tm-isi.h diff --git a/gdb/config/littlemips.mh b/gdb/config/littlemips.mh new file mode 100644 index 00000000000..2d4298cc8e5 --- /dev/null +++ b/gdb/config/littlemips.mh @@ -0,0 +1,21 @@ +# Little-endian MIPS machine such as DECstation. +# Copyright (C) 1989-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o mips-xdep.o coredep.o +XM_FILE= xm-mips.h diff --git a/gdb/config/littlemips.mt b/gdb/config/littlemips.mt new file mode 100644 index 00000000000..709bc57b3cb --- /dev/null +++ b/gdb/config/littlemips.mt @@ -0,0 +1,21 @@ +# Little-endian MIPS machine such as DECstation. +# Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= mips-pinsn.o mips-tdep.o mipsread.o exec.o +TM_FILE= tm-mips.h diff --git a/gdb/config/m88k.mh b/gdb/config/m88k.mh new file mode 100644 index 00000000000..a703d1a80ed --- /dev/null +++ b/gdb/config/m88k.mh @@ -0,0 +1,21 @@ +# Motorola 88000 running DGUX +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= +XM_FILE= xm-88k.h diff --git a/gdb/config/m88k.mt b/gdb/config/m88k.mt new file mode 100644 index 00000000000..f3b67dcc50b --- /dev/null +++ b/gdb/config/m88k.mt @@ -0,0 +1,23 @@ +# Motorola 88000 running DGUX +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= tdesc.o +TM_CLIBS= tdesc/libdc.o +TM_CDEPS= tdesc/libdc.o +TM_FILE= tm-88k.h diff --git a/gdb/config/merlin.mh b/gdb/config/merlin.mh new file mode 100644 index 00000000000..ecb8cf90895 --- /dev/null +++ b/gdb/config/merlin.mh @@ -0,0 +1,24 @@ +# Merlin running utek 2.1 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o +XM_FILE= xm-merlin.h +# See SHELL_FILE in m-merlin.h for a explanation of this. +M_INSTALL=cp /bin/sh /usr/local/lib/gdb-sh; \ +chmod ogu+rw /usr/local/lib/gdb-sh diff --git a/gdb/config/merlin.mt b/gdb/config/merlin.mt new file mode 100644 index 00000000000..1ed8caa2163 --- /dev/null +++ b/gdb/config/merlin.mt @@ -0,0 +1,21 @@ +# Merlin running utek 2.1 +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o ns32k-pinsn.o +TM_FILE= tm-merlin.h diff --git a/gdb/config/mh-vax b/gdb/config/mh-vax new file mode 100755 index 00000000000..8dbb707b550 --- /dev/null +++ b/gdb/config/mh-vax @@ -0,0 +1,28 @@ +# DEC VAX running BSD or Ultrix +# Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The following types of /bin/cc failures have been observed: +# 1. Something in readline.c which I have never seen +# 2. ``"values.c", line 816: compiler error: schain botch'' +#msg /bin/cc has been known to fail on VAXen running BSD4.3 +#msg If this occurs, use gcc +#msg (but see comments in Makefile.dist about compiling with gcc). + +XDEPFILES= infptrace.o coredep.o +XM_FILE= xm-vax.h diff --git a/gdb/config/news.mh b/gdb/config/news.mh new file mode 100644 index 00000000000..1bb7765c199 --- /dev/null +++ b/gdb/config/news.mh @@ -0,0 +1,21 @@ +# Sony news series 700/800/900 (68020) running NewsOS version 3. +# Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o news-xdep.o +XM_FILE= xm-news.h diff --git a/gdb/config/news.mt b/gdb/config/news.mt new file mode 100644 index 00000000000..c26465ab88b --- /dev/null +++ b/gdb/config/news.mt @@ -0,0 +1,21 @@ +# Sony news series 700/800/900 (68020) running NewsOS version 3. +# Copyright (C) 1989-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= m68k-pinsn.o exec.o +TM_FILE= tm-news.h diff --git a/gdb/config/news1000.mh b/gdb/config/news1000.mh new file mode 100644 index 00000000000..940aaee1bdb --- /dev/null +++ b/gdb/config/news1000.mh @@ -0,0 +1,21 @@ +# Sony news series 1000 (68030) running NewsOS version 3. +# Copyright (C) 1989, 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o news-xdep.o +XM_FILE= xm-news1000.h diff --git a/gdb/config/news1000.mt b/gdb/config/news1000.mt new file mode 100644 index 00000000000..d390504d871 --- /dev/null +++ b/gdb/config/news1000.mt @@ -0,0 +1,21 @@ +# Sony news series 1000 (68030) running NewsOS version 3. +# Copyright (C) 1989-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= m68k-pinsn.o exec.o +TM_FILE= tm-news.h diff --git a/gdb/config/nindy960.mt b/gdb/config/nindy960.mt new file mode 100644 index 00000000000..f7dc6f7a751 --- /dev/null +++ b/gdb/config/nindy960.mt @@ -0,0 +1,22 @@ +# Intel 80960, in an embedded system under the NINDY monitor +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o i960-pinsn.o i960-tdep.o nindy-tdep.o remote-nindy.o nindy.o Onindy.o ttybreak.o ttyflush.o +TM_FILE= tm-nindy960.h +TM_CFLAGS= diff --git a/gdb/config/none.mh b/gdb/config/none.mh new file mode 100644 index 00000000000..74e70486604 --- /dev/null +++ b/gdb/config/none.mh @@ -0,0 +1,21 @@ +# Target config file for "no target". This can be used to build you +# a Makefile that only runs administrative commands like 'clean', +# 'gdb.tar.Z', etc. +# +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/gdb/config/none.mt b/gdb/config/none.mt new file mode 100644 index 00000000000..c6b5db982bb --- /dev/null +++ b/gdb/config/none.mt @@ -0,0 +1,3 @@ +# "no target". +# This can be used to build you a Makefile that only runs administrative +# commands like 'clean', 'gdb.tar.Z', etc. diff --git a/gdb/config/np1.mh b/gdb/config/np1.mh new file mode 100644 index 00000000000..fcf88f25abc --- /dev/null +++ b/gdb/config/np1.mh @@ -0,0 +1,21 @@ +# Gould NP1 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o gould-xdep.o +XM_FILE= xm-np1.h diff --git a/gdb/config/np1.mt b/gdb/config/np1.mt new file mode 100644 index 00000000000..4fafd7bafda --- /dev/null +++ b/gdb/config/np1.mt @@ -0,0 +1,21 @@ +# Gould NP1 +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o gould-pinsn.o +TM_FILE= tm-np1.h diff --git a/gdb/config/pn.mh b/gdb/config/pn.mh new file mode 100644 index 00000000000..7e8f807ea4d --- /dev/null +++ b/gdb/config/pn.mh @@ -0,0 +1,21 @@ +# Gould Powernode +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o coredep.o +XM_FILE= xm-pn.h diff --git a/gdb/config/pn.mt b/gdb/config/pn.mt new file mode 100644 index 00000000000..ad26b9cf3c4 --- /dev/null +++ b/gdb/config/pn.mt @@ -0,0 +1,21 @@ +# Gould Powernode +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o gould-pinsn.o +TM_FILE= tm-pn.h diff --git a/gdb/config/pyramid.mh b/gdb/config/pyramid.mh new file mode 100644 index 00000000000..59561ec2cba --- /dev/null +++ b/gdb/config/pyramid.mh @@ -0,0 +1,25 @@ +# Pyramidax under OSx 4.0 (4.2bsd). +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +#msg If you don't compile GDB with GCC, you'll need to add +#msg ALLOCA=alloca.o and ALLOCA1=alloca.o to the Makefile. +#msg + +XDEPFILES= pyr-xdep.o infptrace.o +XM_FILE= xm-pyr.h diff --git a/gdb/config/pyramid.mt b/gdb/config/pyramid.mt new file mode 100644 index 00000000000..d62e88eed80 --- /dev/null +++ b/gdb/config/pyramid.mt @@ -0,0 +1,25 @@ +# Pyramid under OSx 4.0 (4.2bsd). +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +#msg Note that GDB on Pyramids only works with GCC, +#msg at least for some programs. +#msg + +TDEPFILES= pyr-pinsn.o pyr-tdep.o exec.o +TM_FILE= tm-pyr.h diff --git a/gdb/config/sun2os3.mh b/gdb/config/sun2os3.mh new file mode 100644 index 00000000000..87f8130c0fa --- /dev/null +++ b/gdb/config/sun2os3.mh @@ -0,0 +1,21 @@ +# Sun 2, running SunOS 3 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o sun3-xdep.o +XM_FILE= xm-sun2.h diff --git a/gdb/config/sun2os3.mt b/gdb/config/sun2os3.mt new file mode 100644 index 00000000000..99dc7f72390 --- /dev/null +++ b/gdb/config/sun2os3.mt @@ -0,0 +1,26 @@ +# Sun 2, running SunOS 3 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The system-supplied assembler re-orders the symbols so that gdb +# can't find "gcc_compiled.". +#msg If you compile your program with GCC, use the GNU assembler. +#msg + +TDEPFILES= exec.o m68k-pinsn.o m68k-tdep.o +TM_FILE= tm-sun2.h diff --git a/gdb/config/sun2os4.mh b/gdb/config/sun2os4.mh new file mode 100644 index 00000000000..f525cf6be81 --- /dev/null +++ b/gdb/config/sun2os4.mh @@ -0,0 +1,21 @@ +# Sun 2, running SunOS 4 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o sun3-xdep.o +XM_FILE= xm-sun2.h diff --git a/gdb/config/sun2os4.mt b/gdb/config/sun2os4.mt new file mode 100644 index 00000000000..d70dd81705b --- /dev/null +++ b/gdb/config/sun2os4.mt @@ -0,0 +1,26 @@ +# Sun 2, running SunOS 4 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The system-supplied assembler re-orders the symbols so that gdb +# can't find "gcc_compiled.". +#msg If you compile your program with GCC, use the GNU assembler. +#msg + +TDEPFILES= exec.o m68k-pinsn.o solib.o m68k-tdep.o +TM_FILE= tm-sun2os4.h diff --git a/gdb/config/sun3.mh b/gdb/config/sun3.mh new file mode 100644 index 00000000000..6a91b49eeed --- /dev/null +++ b/gdb/config/sun3.mh @@ -0,0 +1,26 @@ +# Sun 3, running SunOS 4 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The system-supplied assembler re-orders the symbols so that gdb +# can't find "gcc_compiled.". +#msg If you compile your program with GCC, use the GNU assembler. +#msg + +XDEPFILES= infptrace.o sun3-xdep.o +XM_FILE= xm-sun3os4.h diff --git a/gdb/config/sun3.mt b/gdb/config/sun3.mt new file mode 100644 index 00000000000..ae6e35188ec --- /dev/null +++ b/gdb/config/sun3.mt @@ -0,0 +1,21 @@ +# Sun 3, running SunOS 4, as a target system +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o m68k-pinsn.o solib.o m68k-tdep.o +TM_FILE= tm-sun3os4.h diff --git a/gdb/config/sun386.mh b/gdb/config/sun386.mh new file mode 100644 index 00000000000..a2cb4311b1a --- /dev/null +++ b/gdb/config/sun386.mh @@ -0,0 +1,21 @@ +# Sun 386i +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o sun386-xdep.o +XM_FILE= xm-sun386.h diff --git a/gdb/config/sun386.mt b/gdb/config/sun386.mt new file mode 100644 index 00000000000..1a0bca56cf3 --- /dev/null +++ b/gdb/config/sun386.mt @@ -0,0 +1,21 @@ +# Sun 386i target configuration file. +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o i386-pinsn.o solib.o +TM_FILE= tm-sun386.h diff --git a/gdb/config/sun3os3.mh b/gdb/config/sun3os3.mh new file mode 100644 index 00000000000..440855243e7 --- /dev/null +++ b/gdb/config/sun3os3.mh @@ -0,0 +1,21 @@ +# Sun 3, running SunOS 3 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o sun3-xdep.o +XM_FILE= xm-sun3.h diff --git a/gdb/config/sun3os3.mt b/gdb/config/sun3os3.mt new file mode 100644 index 00000000000..3eea3bf2692 --- /dev/null +++ b/gdb/config/sun3os3.mt @@ -0,0 +1,26 @@ +# Sun 3, running SunOS 3 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The system-supplied assembler re-orders the symbols so that gdb +# can't find "gcc_compiled.". +#msg If you compile your program with GCC, use the GNU assembler. +#msg + +TDEPFILES= exec.o m68k-pinsn.o m68k-tdep.o +TM_FILE= tm-sun3.h diff --git a/gdb/config/sun3os4.mh b/gdb/config/sun3os4.mh new file mode 100644 index 00000000000..6a91b49eeed --- /dev/null +++ b/gdb/config/sun3os4.mh @@ -0,0 +1,26 @@ +# Sun 3, running SunOS 4 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The system-supplied assembler re-orders the symbols so that gdb +# can't find "gcc_compiled.". +#msg If you compile your program with GCC, use the GNU assembler. +#msg + +XDEPFILES= infptrace.o sun3-xdep.o +XM_FILE= xm-sun3os4.h diff --git a/gdb/config/sun3os4.mt b/gdb/config/sun3os4.mt new file mode 100644 index 00000000000..ae6e35188ec --- /dev/null +++ b/gdb/config/sun3os4.mt @@ -0,0 +1,21 @@ +# Sun 3, running SunOS 4, as a target system +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o m68k-pinsn.o solib.o m68k-tdep.o +TM_FILE= tm-sun3os4.h diff --git a/gdb/config/sun4.mh b/gdb/config/sun4.mh new file mode 100644 index 00000000000..80542718b9a --- /dev/null +++ b/gdb/config/sun4.mh @@ -0,0 +1,21 @@ +# Sun 4 or Sparcstation, running SunOS 4 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o sparc-xdep.o +XM_FILE= xm-sun4os4.h diff --git a/gdb/config/sun4.mt b/gdb/config/sun4.mt new file mode 100644 index 00000000000..030872d9bc6 --- /dev/null +++ b/gdb/config/sun4.mt @@ -0,0 +1,26 @@ +# Sun 4 or Sparcstation, running SunOS 4 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The system-supplied assembler re-orders the symbols so that gdb +# can't find "gcc_compiled.". +#msg If you compile your program with GCC, use the GNU assembler. +#msg + +TDEPFILES= exec.o sparc-tdep.o sparc-pinsn.o solib.o +TM_FILE= tm-sun4os4.h diff --git a/gdb/config/sun4os3.mh b/gdb/config/sun4os3.mh new file mode 100644 index 00000000000..fdb0ddd8a6a --- /dev/null +++ b/gdb/config/sun4os3.mh @@ -0,0 +1,21 @@ +# Sun 4 or Sparcstation, running SunOS 3 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o sparc-xdep.o +XM_FILE= xm-sparc.h diff --git a/gdb/config/sun4os3.mt b/gdb/config/sun4os3.mt new file mode 100644 index 00000000000..b90a65cf0e2 --- /dev/null +++ b/gdb/config/sun4os3.mt @@ -0,0 +1,26 @@ +# Sun 4 or Sparcstation, running SunOS 3 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The system-supplied assembler re-orders the symbols so that gdb +# can't find "gcc_compiled.". +#msg If you compile your program with GCC, use the GNU assembler. +#msg + +TDEPFILES= exec.o sparc-tdep.o sparc-pinsn.o +TM_FILE= tm-sparc.h diff --git a/gdb/config/sun4os4.mh b/gdb/config/sun4os4.mh new file mode 100644 index 00000000000..80542718b9a --- /dev/null +++ b/gdb/config/sun4os4.mh @@ -0,0 +1,21 @@ +# Sun 4 or Sparcstation, running SunOS 4 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o sparc-xdep.o +XM_FILE= xm-sun4os4.h diff --git a/gdb/config/sun4os4.mt b/gdb/config/sun4os4.mt new file mode 100644 index 00000000000..030872d9bc6 --- /dev/null +++ b/gdb/config/sun4os4.mt @@ -0,0 +1,26 @@ +# Sun 4 or Sparcstation, running SunOS 4 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The system-supplied assembler re-orders the symbols so that gdb +# can't find "gcc_compiled.". +#msg If you compile your program with GCC, use the GNU assembler. +#msg + +TDEPFILES= exec.o sparc-tdep.o sparc-pinsn.o solib.o +TM_FILE= tm-sun4os4.h diff --git a/gdb/config/symmetry.mh b/gdb/config/symmetry.mh new file mode 100644 index 00000000000..514c527f01b --- /dev/null +++ b/gdb/config/symmetry.mh @@ -0,0 +1,21 @@ +# Sequent Symmetry running Dynix 3.0, with Weitek 1167 or i387. +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o symmetry-xdep.o +XM_FILE= xm-symmetry.h diff --git a/gdb/config/symmetry.mt b/gdb/config/symmetry.mt new file mode 100644 index 00000000000..4f2f37b0a7c --- /dev/null +++ b/gdb/config/symmetry.mt @@ -0,0 +1,21 @@ +# Sequent Symmetry running Dynix 3.0, with Weitek 1167 or i387. +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= symmetry-tdep.o i386-pinsn.o +TM_FILE= tm-symmetry.h diff --git a/gdb/config/umax.mh b/gdb/config/umax.mh new file mode 100644 index 00000000000..34e74d540f1 --- /dev/null +++ b/gdb/config/umax.mh @@ -0,0 +1,21 @@ +# Encore running umax 4.2 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +XDEPFILES= infptrace.o umax-xdep.o +XM_FILE= xm-umax.h diff --git a/gdb/config/umax.mt b/gdb/config/umax.mt new file mode 100644 index 00000000000..994da6de912 --- /dev/null +++ b/gdb/config/umax.mt @@ -0,0 +1,21 @@ +# Encore running umax 4.2 +# Copyright (C) 1990 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o ns32k-pinsn.o +TM_FILE= tm-umax.h diff --git a/gdb/config/vax.mt b/gdb/config/vax.mt new file mode 100644 index 00000000000..a8e749af190 --- /dev/null +++ b/gdb/config/vax.mt @@ -0,0 +1,21 @@ +# DEC VAX running BSD or Ultrix +# Copyright (C) 1989-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= vax-pinsn.o exec.o +TM_FILE= tm-vax.h diff --git a/gdb/config/vxworks68.mt b/gdb/config/vxworks68.mt new file mode 100644 index 00000000000..1514c0e2a56 --- /dev/null +++ b/gdb/config/vxworks68.mt @@ -0,0 +1,21 @@ +# VxWorks running on a 68000, as a target system +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o m68k-pinsn.o m68k-tdep.o remote-vx.o xdr_ld.o xdr_ptrace.o xdr_rdb.o xdr_regs.o +TM_FILE= tm-vxworks68.h diff --git a/gdb/config/vxworks960.mt b/gdb/config/vxworks960.mt new file mode 100644 index 00000000000..1cc95e0555d --- /dev/null +++ b/gdb/config/vxworks960.mt @@ -0,0 +1,23 @@ +# VxWorks running on an Intel 960, as a target system +# Copyright (C) 1990-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +TDEPFILES= exec.o i960-pinsn.o i960-tdep.o remote-vx.o xdr_ld.o xdr_ptrace.o xdr_rdb.o xdr_regs.o +TM_FILE= tm-vxworks960.h +# Define this for the vx-share routines, which don't see param.h. +TM_CFLAGS= -DI80960 diff --git a/gdb/convex-opcode.h b/gdb/convex-opcode.h new file mode 100755 index 00000000000..523c8744c28 --- /dev/null +++ b/gdb/convex-opcode.h @@ -0,0 +1,1677 @@ +/* Include information for instruction dissasembly on the Convex. + Copyright (C) 1989, Free Software Foundation. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define xxx 0 +#define rrr 1 +#define rr 2 +#define rxr 3 +#define r 4 +#define nops 5 +#define nr 6 +#define pcrel 7 +#define lr 8 +#define rxl 9 +#define rlr 10 +#define rrl 11 +#define iml 12 +#define imr 13 +#define a1r 14 +#define a1l 15 +#define a2r 16 +#define a2l 17 +#define a3 18 +#define a4 19 +#define a5 20 +#define V 1 +#define S 2 +#define VM 3 +#define A 4 +#define VL 5 +#define VS 6 +#define VLS 7 +#define PSW 8 +/* Prevent an error during "make depend". */ +#if !defined (PC) +#define PC 9 +#endif +#define ITR 10 +#define VV 11 +#define ITSR 12 +#define TOC 13 +#define CIR 14 +#define TTR 15 +#define VMU 16 +#define VML 17 +#define ICR 18 +#define TCPU 19 +#define CPUID 20 +#define TID 21 +char *op[] = { + "", + "v0\0v1\0v2\0v3\0v4\0v5\0v6\0v7", + "s0\0s1\0s2\0s3\0s4\0s5\0s6\0s7", + "vm", + "sp\0a1\0a2\0a3\0a4\0a5\0ap\0fp", + "vl", + "vs", + "vls", + "psw", + "pc", + "itr", + "vv", + "itsr", + "toc", + "cir", + "ttr", + "vmu", + "vml", + "icr", + "tcpu", + "cpuid", + "tid", +}; +struct formstr format0[] = { + {0,0,rrr,V,S,S}, /* mov */ + {0,0,rrr,S,S,V}, /* mov */ + {1,1,rrr,V,V,V}, /* merg.t */ + {2,1,rrr,V,V,V}, /* mask.t */ + {1,2,rrr,V,S,V}, /* merg.f */ + {2,2,rrr,V,S,V}, /* mask.f */ + {1,1,rrr,V,S,V}, /* merg.t */ + {2,1,rrr,V,S,V}, /* mask.t */ + {3,3,rrr,V,V,V}, /* mul.s */ + {3,4,rrr,V,V,V}, /* mul.d */ + {4,3,rrr,V,V,V}, /* div.s */ + {4,4,rrr,V,V,V}, /* div.d */ + {3,3,rrr,V,S,V}, /* mul.s */ + {3,4,rrr,V,S,V}, /* mul.d */ + {4,3,rrr,V,S,V}, /* div.s */ + {4,4,rrr,V,S,V}, /* div.d */ + {5,0,rrr,V,V,V}, /* and */ + {6,0,rrr,V,V,V}, /* or */ + {7,0,rrr,V,V,V}, /* xor */ + {8,0,rrr,V,V,V}, /* shf */ + {5,0,rrr,V,S,V}, /* and */ + {6,0,rrr,V,S,V}, /* or */ + {7,0,rrr,V,S,V}, /* xor */ + {8,0,rrr,V,S,V}, /* shf */ + {9,3,rrr,V,V,V}, /* add.s */ + {9,4,rrr,V,V,V}, /* add.d */ + {10,3,rrr,V,V,V}, /* sub.s */ + {10,4,rrr,V,V,V}, /* sub.d */ + {9,3,rrr,V,S,V}, /* add.s */ + {9,4,rrr,V,S,V}, /* add.d */ + {10,3,rrr,V,S,V}, /* sub.s */ + {10,4,rrr,V,S,V}, /* sub.d */ + {9,5,rrr,V,V,V}, /* add.b */ + {9,6,rrr,V,V,V}, /* add.h */ + {9,7,rrr,V,V,V}, /* add.w */ + {9,8,rrr,V,V,V}, /* add.l */ + {9,5,rrr,V,S,V}, /* add.b */ + {9,6,rrr,V,S,V}, /* add.h */ + {9,7,rrr,V,S,V}, /* add.w */ + {9,8,rrr,V,S,V}, /* add.l */ + {10,5,rrr,V,V,V}, /* sub.b */ + {10,6,rrr,V,V,V}, /* sub.h */ + {10,7,rrr,V,V,V}, /* sub.w */ + {10,8,rrr,V,V,V}, /* sub.l */ + {10,5,rrr,V,S,V}, /* sub.b */ + {10,6,rrr,V,S,V}, /* sub.h */ + {10,7,rrr,V,S,V}, /* sub.w */ + {10,8,rrr,V,S,V}, /* sub.l */ + {3,5,rrr,V,V,V}, /* mul.b */ + {3,6,rrr,V,V,V}, /* mul.h */ + {3,7,rrr,V,V,V}, /* mul.w */ + {3,8,rrr,V,V,V}, /* mul.l */ + {3,5,rrr,V,S,V}, /* mul.b */ + {3,6,rrr,V,S,V}, /* mul.h */ + {3,7,rrr,V,S,V}, /* mul.w */ + {3,8,rrr,V,S,V}, /* mul.l */ + {4,5,rrr,V,V,V}, /* div.b */ + {4,6,rrr,V,V,V}, /* div.h */ + {4,7,rrr,V,V,V}, /* div.w */ + {4,8,rrr,V,V,V}, /* div.l */ + {4,5,rrr,V,S,V}, /* div.b */ + {4,6,rrr,V,S,V}, /* div.h */ + {4,7,rrr,V,S,V}, /* div.w */ + {4,8,rrr,V,S,V}, /* div.l */ +}; +struct formstr format1[] = { + {11,0,xxx,0,0,0}, /* exit */ + {12,0,a3,0,0,0}, /* jmp */ + {13,2,a3,0,0,0}, /* jmpi.f */ + {13,1,a3,0,0,0}, /* jmpi.t */ + {14,2,a3,0,0,0}, /* jmpa.f */ + {14,1,a3,0,0,0}, /* jmpa.t */ + {15,2,a3,0,0,0}, /* jmps.f */ + {15,1,a3,0,0,0}, /* jmps.t */ + {16,0,a3,0,0,0}, /* tac */ + {17,0,a1r,A,0,0}, /* ldea */ + {18,8,a1l,VLS,0,0}, /* ld.l */ + {18,9,a1l,VM,0,0}, /* ld.x */ + {19,0,a3,0,0,0}, /* tas */ + {20,0,a3,0,0,0}, /* pshea */ + {21,8,a2l,VLS,0,0}, /* st.l */ + {21,9,a2l,VM,0,0}, /* st.x */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {22,0,a3,0,0,0}, /* call */ + {23,0,a3,0,0,0}, /* calls */ + {24,0,a3,0,0,0}, /* callq */ + {25,0,a1r,A,0,0}, /* pfork */ + {26,5,a2r,S,0,0}, /* ste.b */ + {26,6,a2r,S,0,0}, /* ste.h */ + {26,7,a2r,S,0,0}, /* ste.w */ + {26,8,a2r,S,0,0}, /* ste.l */ + {18,5,a1r,A,0,0}, /* ld.b */ + {18,6,a1r,A,0,0}, /* ld.h */ + {18,7,a1r,A,0,0}, /* ld.w */ + {27,7,a1r,A,0,0}, /* incr.w */ + {21,5,a2r,A,0,0}, /* st.b */ + {21,6,a2r,A,0,0}, /* st.h */ + {21,7,a2r,A,0,0}, /* st.w */ + {27,8,a1r,S,0,0}, /* incr.l */ + {18,5,a1r,S,0,0}, /* ld.b */ + {18,6,a1r,S,0,0}, /* ld.h */ + {18,7,a1r,S,0,0}, /* ld.w */ + {18,8,a1r,S,0,0}, /* ld.l */ + {21,5,a2r,S,0,0}, /* st.b */ + {21,6,a2r,S,0,0}, /* st.h */ + {21,7,a2r,S,0,0}, /* st.w */ + {21,8,a2r,S,0,0}, /* st.l */ + {18,5,a1r,V,0,0}, /* ld.b */ + {18,6,a1r,V,0,0}, /* ld.h */ + {18,7,a1r,V,0,0}, /* ld.w */ + {18,8,a1r,V,0,0}, /* ld.l */ + {21,5,a2r,V,0,0}, /* st.b */ + {21,6,a2r,V,0,0}, /* st.h */ + {21,7,a2r,V,0,0}, /* st.w */ + {21,8,a2r,V,0,0}, /* st.l */ +}; +struct formstr format2[] = { + {28,5,rr,A,A,0}, /* cvtw.b */ + {28,6,rr,A,A,0}, /* cvtw.h */ + {29,7,rr,A,A,0}, /* cvtb.w */ + {30,7,rr,A,A,0}, /* cvth.w */ + {28,5,rr,S,S,0}, /* cvtw.b */ + {28,6,rr,S,S,0}, /* cvtw.h */ + {29,7,rr,S,S,0}, /* cvtb.w */ + {30,7,rr,S,S,0}, /* cvth.w */ + {28,3,rr,S,S,0}, /* cvtw.s */ + {31,7,rr,S,S,0}, /* cvts.w */ + {32,3,rr,S,S,0}, /* cvtd.s */ + {31,4,rr,S,S,0}, /* cvts.d */ + {31,8,rr,S,S,0}, /* cvts.l */ + {32,8,rr,S,S,0}, /* cvtd.l */ + {33,3,rr,S,S,0}, /* cvtl.s */ + {33,4,rr,S,S,0}, /* cvtl.d */ + {34,0,rr,A,A,0}, /* ldpa */ + {8,0,nr,A,0,0}, /* shf */ + {18,6,nr,A,0,0}, /* ld.h */ + {18,7,nr,A,0,0}, /* ld.w */ + {33,7,rr,S,S,0}, /* cvtl.w */ + {28,8,rr,S,S,0}, /* cvtw.l */ + {35,1,rr,S,S,0}, /* plc.t */ + {36,0,rr,S,S,0}, /* tzc */ + {37,6,rr,A,A,0}, /* eq.h */ + {37,7,rr,A,A,0}, /* eq.w */ + {37,6,nr,A,0,0}, /* eq.h */ + {37,7,nr,A,0,0}, /* eq.w */ + {37,5,rr,S,S,0}, /* eq.b */ + {37,6,rr,S,S,0}, /* eq.h */ + {37,7,rr,S,S,0}, /* eq.w */ + {37,8,rr,S,S,0}, /* eq.l */ + {38,6,rr,A,A,0}, /* leu.h */ + {38,7,rr,A,A,0}, /* leu.w */ + {38,6,nr,A,0,0}, /* leu.h */ + {38,7,nr,A,0,0}, /* leu.w */ + {38,5,rr,S,S,0}, /* leu.b */ + {38,6,rr,S,S,0}, /* leu.h */ + {38,7,rr,S,S,0}, /* leu.w */ + {38,8,rr,S,S,0}, /* leu.l */ + {39,6,rr,A,A,0}, /* ltu.h */ + {39,7,rr,A,A,0}, /* ltu.w */ + {39,6,nr,A,0,0}, /* ltu.h */ + {39,7,nr,A,0,0}, /* ltu.w */ + {39,5,rr,S,S,0}, /* ltu.b */ + {39,6,rr,S,S,0}, /* ltu.h */ + {39,7,rr,S,S,0}, /* ltu.w */ + {39,8,rr,S,S,0}, /* ltu.l */ + {40,6,rr,A,A,0}, /* le.h */ + {40,7,rr,A,A,0}, /* le.w */ + {40,6,nr,A,0,0}, /* le.h */ + {40,7,nr,A,0,0}, /* le.w */ + {40,5,rr,S,S,0}, /* le.b */ + {40,6,rr,S,S,0}, /* le.h */ + {40,7,rr,S,S,0}, /* le.w */ + {40,8,rr,S,S,0}, /* le.l */ + {41,6,rr,A,A,0}, /* lt.h */ + {41,7,rr,A,A,0}, /* lt.w */ + {41,6,nr,A,0,0}, /* lt.h */ + {41,7,nr,A,0,0}, /* lt.w */ + {41,5,rr,S,S,0}, /* lt.b */ + {41,6,rr,S,S,0}, /* lt.h */ + {41,7,rr,S,S,0}, /* lt.w */ + {41,8,rr,S,S,0}, /* lt.l */ + {9,7,rr,S,A,0}, /* add.w */ + {8,0,rr,A,A,0}, /* shf */ + {0,0,rr,A,A,0}, /* mov */ + {0,0,rr,S,A,0}, /* mov */ + {0,7,rr,S,S,0}, /* mov.w */ + {8,0,rr,S,S,0}, /* shf */ + {0,0,rr,S,S,0}, /* mov */ + {0,0,rr,A,S,0}, /* mov */ + {5,0,rr,A,A,0}, /* and */ + {6,0,rr,A,A,0}, /* or */ + {7,0,rr,A,A,0}, /* xor */ + {42,0,rr,A,A,0}, /* not */ + {5,0,rr,S,S,0}, /* and */ + {6,0,rr,S,S,0}, /* or */ + {7,0,rr,S,S,0}, /* xor */ + {42,0,rr,S,S,0}, /* not */ + {40,3,rr,S,S,0}, /* le.s */ + {40,4,rr,S,S,0}, /* le.d */ + {41,3,rr,S,S,0}, /* lt.s */ + {41,4,rr,S,S,0}, /* lt.d */ + {9,3,rr,S,S,0}, /* add.s */ + {9,4,rr,S,S,0}, /* add.d */ + {10,3,rr,S,S,0}, /* sub.s */ + {10,4,rr,S,S,0}, /* sub.d */ + {37,3,rr,S,S,0}, /* eq.s */ + {37,4,rr,S,S,0}, /* eq.d */ + {43,6,rr,A,A,0}, /* neg.h */ + {43,7,rr,A,A,0}, /* neg.w */ + {3,3,rr,S,S,0}, /* mul.s */ + {3,4,rr,S,S,0}, /* mul.d */ + {4,3,rr,S,S,0}, /* div.s */ + {4,4,rr,S,S,0}, /* div.d */ + {9,6,rr,A,A,0}, /* add.h */ + {9,7,rr,A,A,0}, /* add.w */ + {9,6,nr,A,0,0}, /* add.h */ + {9,7,nr,A,0,0}, /* add.w */ + {9,5,rr,S,S,0}, /* add.b */ + {9,6,rr,S,S,0}, /* add.h */ + {9,7,rr,S,S,0}, /* add.w */ + {9,8,rr,S,S,0}, /* add.l */ + {10,6,rr,A,A,0}, /* sub.h */ + {10,7,rr,A,A,0}, /* sub.w */ + {10,6,nr,A,0,0}, /* sub.h */ + {10,7,nr,A,0,0}, /* sub.w */ + {10,5,rr,S,S,0}, /* sub.b */ + {10,6,rr,S,S,0}, /* sub.h */ + {10,7,rr,S,S,0}, /* sub.w */ + {10,8,rr,S,S,0}, /* sub.l */ + {3,6,rr,A,A,0}, /* mul.h */ + {3,7,rr,A,A,0}, /* mul.w */ + {3,6,nr,A,0,0}, /* mul.h */ + {3,7,nr,A,0,0}, /* mul.w */ + {3,5,rr,S,S,0}, /* mul.b */ + {3,6,rr,S,S,0}, /* mul.h */ + {3,7,rr,S,S,0}, /* mul.w */ + {3,8,rr,S,S,0}, /* mul.l */ + {4,6,rr,A,A,0}, /* div.h */ + {4,7,rr,A,A,0}, /* div.w */ + {4,6,nr,A,0,0}, /* div.h */ + {4,7,nr,A,0,0}, /* div.w */ + {4,5,rr,S,S,0}, /* div.b */ + {4,6,rr,S,S,0}, /* div.h */ + {4,7,rr,S,S,0}, /* div.w */ + {4,8,rr,S,S,0}, /* div.l */ +}; +struct formstr format3[] = { + {32,3,rr,V,V,0}, /* cvtd.s */ + {31,4,rr,V,V,0}, /* cvts.d */ + {33,4,rr,V,V,0}, /* cvtl.d */ + {32,8,rr,V,V,0}, /* cvtd.l */ + {0,0,rrl,S,S,VM}, /* mov */ + {0,0,rlr,S,VM,S}, /* mov */ + {0,0,0,0,0,0}, + {44,0,rr,S,S,0}, /* lop */ + {36,0,rr,V,V,0}, /* tzc */ + {44,0,rr,V,V,0}, /* lop */ + {0,0,0,0,0,0}, + {42,0,rr,V,V,0}, /* not */ + {8,0,rr,S,V,0}, /* shf */ + {35,1,rr,V,V,0}, /* plc.t */ + {45,2,rr,V,V,0}, /* cprs.f */ + {45,1,rr,V,V,0}, /* cprs.t */ + {37,3,rr,V,V,0}, /* eq.s */ + {37,4,rr,V,V,0}, /* eq.d */ + {43,3,rr,V,V,0}, /* neg.s */ + {43,4,rr,V,V,0}, /* neg.d */ + {37,3,rr,S,V,0}, /* eq.s */ + {37,4,rr,S,V,0}, /* eq.d */ + {43,3,rr,S,S,0}, /* neg.s */ + {43,4,rr,S,S,0}, /* neg.d */ + {40,3,rr,V,V,0}, /* le.s */ + {40,4,rr,V,V,0}, /* le.d */ + {41,3,rr,V,V,0}, /* lt.s */ + {41,4,rr,V,V,0}, /* lt.d */ + {40,3,rr,S,V,0}, /* le.s */ + {40,4,rr,S,V,0}, /* le.d */ + {41,3,rr,S,V,0}, /* lt.s */ + {41,4,rr,S,V,0}, /* lt.d */ + {37,5,rr,V,V,0}, /* eq.b */ + {37,6,rr,V,V,0}, /* eq.h */ + {37,7,rr,V,V,0}, /* eq.w */ + {37,8,rr,V,V,0}, /* eq.l */ + {37,5,rr,S,V,0}, /* eq.b */ + {37,6,rr,S,V,0}, /* eq.h */ + {37,7,rr,S,V,0}, /* eq.w */ + {37,8,rr,S,V,0}, /* eq.l */ + {40,5,rr,V,V,0}, /* le.b */ + {40,6,rr,V,V,0}, /* le.h */ + {40,7,rr,V,V,0}, /* le.w */ + {40,8,rr,V,V,0}, /* le.l */ + {40,5,rr,S,V,0}, /* le.b */ + {40,6,rr,S,V,0}, /* le.h */ + {40,7,rr,S,V,0}, /* le.w */ + {40,8,rr,S,V,0}, /* le.l */ + {41,5,rr,V,V,0}, /* lt.b */ + {41,6,rr,V,V,0}, /* lt.h */ + {41,7,rr,V,V,0}, /* lt.w */ + {41,8,rr,V,V,0}, /* lt.l */ + {41,5,rr,S,V,0}, /* lt.b */ + {41,6,rr,S,V,0}, /* lt.h */ + {41,7,rr,S,V,0}, /* lt.w */ + {41,8,rr,S,V,0}, /* lt.l */ + {43,5,rr,V,V,0}, /* neg.b */ + {43,6,rr,V,V,0}, /* neg.h */ + {43,7,rr,V,V,0}, /* neg.w */ + {43,8,rr,V,V,0}, /* neg.l */ + {43,5,rr,S,S,0}, /* neg.b */ + {43,6,rr,S,S,0}, /* neg.h */ + {43,7,rr,S,S,0}, /* neg.w */ + {43,8,rr,S,S,0}, /* neg.l */ +}; +struct formstr format4[] = { + {46,0,nops,0,0,0}, /* nop */ + {47,0,pcrel,0,0,0}, /* br */ + {48,2,pcrel,0,0,0}, /* bri.f */ + {48,1,pcrel,0,0,0}, /* bri.t */ + {49,2,pcrel,0,0,0}, /* bra.f */ + {49,1,pcrel,0,0,0}, /* bra.t */ + {50,2,pcrel,0,0,0}, /* brs.f */ + {50,1,pcrel,0,0,0}, /* brs.t */ +}; +struct formstr format5[] = { + {51,5,rr,V,V,0}, /* ldvi.b */ + {51,6,rr,V,V,0}, /* ldvi.h */ + {51,7,rr,V,V,0}, /* ldvi.w */ + {51,8,rr,V,V,0}, /* ldvi.l */ + {28,3,rr,V,V,0}, /* cvtw.s */ + {31,7,rr,V,V,0}, /* cvts.w */ + {28,8,rr,V,V,0}, /* cvtw.l */ + {33,7,rr,V,V,0}, /* cvtl.w */ + {52,5,rxr,V,V,0}, /* stvi.b */ + {52,6,rxr,V,V,0}, /* stvi.h */ + {52,7,rxr,V,V,0}, /* stvi.w */ + {52,8,rxr,V,V,0}, /* stvi.l */ + {52,5,rxr,S,V,0}, /* stvi.b */ + {52,6,rxr,S,V,0}, /* stvi.h */ + {52,7,rxr,S,V,0}, /* stvi.w */ + {52,8,rxr,S,V,0}, /* stvi.l */ +}; +struct formstr format6[] = { + {53,0,r,A,0,0}, /* ldsdr */ + {54,0,r,A,0,0}, /* ldkdr */ + {55,3,r,S,0,0}, /* ln.s */ + {55,4,r,S,0,0}, /* ln.d */ + {56,0,nops,0,0,0}, /* patu */ + {57,0,r,A,0,0}, /* pate */ + {58,0,nops,0,0,0}, /* pich */ + {59,0,nops,0,0,0}, /* plch */ + {0,0,lr,PSW,A,0}, /* mov */ + {0,0,rxl,A,PSW,0}, /* mov */ + {0,0,lr,PC,A,0}, /* mov */ + {60,0,r,S,0,0}, /* idle */ + {0,0,lr,ITR,S,0}, /* mov */ + {0,0,rxl,S,ITR,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,rxl,S,ITSR,0}, /* mov */ + {61,0,nops,0,0,0}, /* rtnq */ + {62,0,nops,0,0,0}, /* cfork */ + {63,0,nops,0,0,0}, /* rtn */ + {64,0,nops,0,0,0}, /* wfork */ + {65,0,nops,0,0,0}, /* join */ + {66,0,nops,0,0,0}, /* rtnc */ + {67,3,r,S,0,0}, /* exp.s */ + {67,4,r,S,0,0}, /* exp.d */ + {68,3,r,S,0,0}, /* sin.s */ + {68,4,r,S,0,0}, /* sin.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {69,3,r,S,0,0}, /* cos.s */ + {69,4,r,S,0,0}, /* cos.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {70,7,r,A,0,0}, /* psh.w */ + {0,0,0,0,0,0}, + {71,7,r,A,0,0}, /* pop.w */ + {0,0,0,0,0,0}, + {70,7,r,S,0,0}, /* psh.w */ + {70,8,r,S,0,0}, /* psh.l */ + {71,7,r,S,0,0}, /* pop.w */ + {71,8,r,S,0,0}, /* pop.l */ + {72,0,nops,0,0,0}, /* eni */ + {73,0,nops,0,0,0}, /* dsi */ + {74,0,nops,0,0,0}, /* bkpt */ + {75,0,nops,0,0,0}, /* msync */ + {76,0,r,S,0,0}, /* mski */ + {77,0,r,S,0,0}, /* xmti */ + {0,0,rxl,S,VV,0}, /* mov */ + {78,0,nops,0,0,0}, /* tstvv */ + {0,0,lr,VS,A,0}, /* mov */ + {0,0,rxl,A,VS,0}, /* mov */ + {0,0,lr,VL,A,0}, /* mov */ + {0,0,rxl,A,VL,0}, /* mov */ + {0,7,lr,VS,S,0}, /* mov.w */ + {0,7,rxl,S,VS,0}, /* mov.w */ + {0,7,lr,VL,S,0}, /* mov.w */ + {0,7,rxl,S,VL,0}, /* mov.w */ + {79,0,r,A,0,0}, /* diag */ + {80,0,nops,0,0,0}, /* pbkpt */ + {81,3,r,S,0,0}, /* sqrt.s */ + {81,4,r,S,0,0}, /* sqrt.d */ + {82,0,nops,0,0,0}, /* casr */ + {0,0,0,0,0,0}, + {83,3,r,S,0,0}, /* atan.s */ + {83,4,r,S,0,0}, /* atan.d */ +}; +struct formstr format7[] = { + {84,5,r,V,0,0}, /* sum.b */ + {84,6,r,V,0,0}, /* sum.h */ + {84,7,r,V,0,0}, /* sum.w */ + {84,8,r,V,0,0}, /* sum.l */ + {85,0,r,V,0,0}, /* all */ + {86,0,r,V,0,0}, /* any */ + {87,0,r,V,0,0}, /* parity */ + {0,0,0,0,0,0}, + {88,5,r,V,0,0}, /* max.b */ + {88,6,r,V,0,0}, /* max.h */ + {88,7,r,V,0,0}, /* max.w */ + {88,8,r,V,0,0}, /* max.l */ + {89,5,r,V,0,0}, /* min.b */ + {89,6,r,V,0,0}, /* min.h */ + {89,7,r,V,0,0}, /* min.w */ + {89,8,r,V,0,0}, /* min.l */ + {84,3,r,V,0,0}, /* sum.s */ + {84,4,r,V,0,0}, /* sum.d */ + {90,3,r,V,0,0}, /* prod.s */ + {90,4,r,V,0,0}, /* prod.d */ + {88,3,r,V,0,0}, /* max.s */ + {88,4,r,V,0,0}, /* max.d */ + {89,3,r,V,0,0}, /* min.s */ + {89,4,r,V,0,0}, /* min.d */ + {90,5,r,V,0,0}, /* prod.b */ + {90,6,r,V,0,0}, /* prod.h */ + {90,7,r,V,0,0}, /* prod.w */ + {90,8,r,V,0,0}, /* prod.l */ + {35,2,lr,VM,S,0}, /* plc.f */ + {35,1,lr,VM,S,0}, /* plc.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr formatx[] = { + {0,0,0,0,0,0}, +}; +struct formstr format1a[] = { + {91,0,imr,A,0,0}, /* halt */ + {92,0,a4,0,0,0}, /* sysc */ + {18,6,imr,A,0,0}, /* ld.h */ + {18,7,imr,A,0,0}, /* ld.w */ + {5,0,imr,A,0,0}, /* and */ + {6,0,imr,A,0,0}, /* or */ + {7,0,imr,A,0,0}, /* xor */ + {8,0,imr,A,0,0}, /* shf */ + {9,6,imr,A,0,0}, /* add.h */ + {9,7,imr,A,0,0}, /* add.w */ + {10,6,imr,A,0,0}, /* sub.h */ + {10,7,imr,A,0,0}, /* sub.w */ + {3,6,imr,A,0,0}, /* mul.h */ + {3,7,imr,A,0,0}, /* mul.w */ + {4,6,imr,A,0,0}, /* div.h */ + {4,7,imr,A,0,0}, /* div.w */ + {18,7,iml,VL,0,0}, /* ld.w */ + {18,7,iml,VS,0,0}, /* ld.w */ + {0,0,0,0,0,0}, + {8,7,imr,S,0,0}, /* shf.w */ + {93,0,a5,0,0,0}, /* trap */ + {0,0,0,0,0,0}, + {37,6,imr,A,0,0}, /* eq.h */ + {37,7,imr,A,0,0}, /* eq.w */ + {38,6,imr,A,0,0}, /* leu.h */ + {38,7,imr,A,0,0}, /* leu.w */ + {39,6,imr,A,0,0}, /* ltu.h */ + {39,7,imr,A,0,0}, /* ltu.w */ + {40,6,imr,A,0,0}, /* le.h */ + {40,7,imr,A,0,0}, /* le.w */ + {41,6,imr,A,0,0}, /* lt.h */ + {41,7,imr,A,0,0}, /* lt.w */ +}; +struct formstr format1b[] = { + {18,4,imr,S,0,0}, /* ld.d */ + {18,10,imr,S,0,0}, /* ld.u */ + {18,8,imr,S,0,0}, /* ld.l */ + {18,7,imr,S,0,0}, /* ld.w */ + {5,0,imr,S,0,0}, /* and */ + {6,0,imr,S,0,0}, /* or */ + {7,0,imr,S,0,0}, /* xor */ + {8,0,imr,S,0,0}, /* shf */ + {9,6,imr,S,0,0}, /* add.h */ + {9,7,imr,S,0,0}, /* add.w */ + {10,6,imr,S,0,0}, /* sub.h */ + {10,7,imr,S,0,0}, /* sub.w */ + {3,6,imr,S,0,0}, /* mul.h */ + {3,7,imr,S,0,0}, /* mul.w */ + {4,6,imr,S,0,0}, /* div.h */ + {4,7,imr,S,0,0}, /* div.w */ + {9,3,imr,S,0,0}, /* add.s */ + {10,3,imr,S,0,0}, /* sub.s */ + {3,3,imr,S,0,0}, /* mul.s */ + {4,3,imr,S,0,0}, /* div.s */ + {40,3,imr,S,0,0}, /* le.s */ + {41,3,imr,S,0,0}, /* lt.s */ + {37,6,imr,S,0,0}, /* eq.h */ + {37,7,imr,S,0,0}, /* eq.w */ + {38,6,imr,S,0,0}, /* leu.h */ + {38,7,imr,S,0,0}, /* leu.w */ + {39,6,imr,S,0,0}, /* ltu.h */ + {39,7,imr,S,0,0}, /* ltu.w */ + {40,6,imr,S,0,0}, /* le.h */ + {40,7,imr,S,0,0}, /* le.w */ + {41,6,imr,S,0,0}, /* lt.h */ + {41,7,imr,S,0,0}, /* lt.w */ +}; +struct formstr e0_format0[] = { + {10,3,rrr,S,V,V}, /* sub.s */ + {10,4,rrr,S,V,V}, /* sub.d */ + {4,3,rrr,S,V,V}, /* div.s */ + {4,4,rrr,S,V,V}, /* div.d */ + {10,11,rrr,S,V,V}, /* sub.s.f */ + {10,12,rrr,S,V,V}, /* sub.d.f */ + {4,11,rrr,S,V,V}, /* div.s.f */ + {4,12,rrr,S,V,V}, /* div.d.f */ + {3,11,rrr,V,V,V}, /* mul.s.f */ + {3,12,rrr,V,V,V}, /* mul.d.f */ + {4,11,rrr,V,V,V}, /* div.s.f */ + {4,12,rrr,V,V,V}, /* div.d.f */ + {3,11,rrr,V,S,V}, /* mul.s.f */ + {3,12,rrr,V,S,V}, /* mul.d.f */ + {4,11,rrr,V,S,V}, /* div.s.f */ + {4,12,rrr,V,S,V}, /* div.d.f */ + {5,2,rrr,V,V,V}, /* and.f */ + {6,2,rrr,V,V,V}, /* or.f */ + {7,2,rrr,V,V,V}, /* xor.f */ + {8,2,rrr,V,V,V}, /* shf.f */ + {5,2,rrr,V,S,V}, /* and.f */ + {6,2,rrr,V,S,V}, /* or.f */ + {7,2,rrr,V,S,V}, /* xor.f */ + {8,2,rrr,V,S,V}, /* shf.f */ + {9,11,rrr,V,V,V}, /* add.s.f */ + {9,12,rrr,V,V,V}, /* add.d.f */ + {10,11,rrr,V,V,V}, /* sub.s.f */ + {10,12,rrr,V,V,V}, /* sub.d.f */ + {9,11,rrr,V,S,V}, /* add.s.f */ + {9,12,rrr,V,S,V}, /* add.d.f */ + {10,11,rrr,V,S,V}, /* sub.s.f */ + {10,12,rrr,V,S,V}, /* sub.d.f */ + {9,13,rrr,V,V,V}, /* add.b.f */ + {9,14,rrr,V,V,V}, /* add.h.f */ + {9,15,rrr,V,V,V}, /* add.w.f */ + {9,16,rrr,V,V,V}, /* add.l.f */ + {9,13,rrr,V,S,V}, /* add.b.f */ + {9,14,rrr,V,S,V}, /* add.h.f */ + {9,15,rrr,V,S,V}, /* add.w.f */ + {9,16,rrr,V,S,V}, /* add.l.f */ + {10,13,rrr,V,V,V}, /* sub.b.f */ + {10,14,rrr,V,V,V}, /* sub.h.f */ + {10,15,rrr,V,V,V}, /* sub.w.f */ + {10,16,rrr,V,V,V}, /* sub.l.f */ + {10,13,rrr,V,S,V}, /* sub.b.f */ + {10,14,rrr,V,S,V}, /* sub.h.f */ + {10,15,rrr,V,S,V}, /* sub.w.f */ + {10,16,rrr,V,S,V}, /* sub.l.f */ + {3,13,rrr,V,V,V}, /* mul.b.f */ + {3,14,rrr,V,V,V}, /* mul.h.f */ + {3,15,rrr,V,V,V}, /* mul.w.f */ + {3,16,rrr,V,V,V}, /* mul.l.f */ + {3,13,rrr,V,S,V}, /* mul.b.f */ + {3,14,rrr,V,S,V}, /* mul.h.f */ + {3,15,rrr,V,S,V}, /* mul.w.f */ + {3,16,rrr,V,S,V}, /* mul.l.f */ + {4,13,rrr,V,V,V}, /* div.b.f */ + {4,14,rrr,V,V,V}, /* div.h.f */ + {4,15,rrr,V,V,V}, /* div.w.f */ + {4,16,rrr,V,V,V}, /* div.l.f */ + {4,13,rrr,V,S,V}, /* div.b.f */ + {4,14,rrr,V,S,V}, /* div.h.f */ + {4,15,rrr,V,S,V}, /* div.w.f */ + {4,16,rrr,V,S,V}, /* div.l.f */ +}; +struct formstr e0_format1[] = { + {0,0,0,0,0,0}, + {94,0,a3,0,0,0}, /* tst */ + {95,0,a3,0,0,0}, /* lck */ + {96,0,a3,0,0,0}, /* ulk */ + {17,0,a1r,S,0,0}, /* ldea */ + {97,0,a1r,A,0,0}, /* spawn */ + {98,0,a1r,A,0,0}, /* ldcmr */ + {99,0,a2r,A,0,0}, /* stcmr */ + {100,0,a1r,A,0,0}, /* popr */ + {101,0,a2r,A,0,0}, /* pshr */ + {102,7,a1r,A,0,0}, /* rcvr.w */ + {103,7,a2r,A,0,0}, /* matm.w */ + {104,7,a2r,A,0,0}, /* sndr.w */ + {104,8,a2r,S,0,0}, /* sndr.l */ + {102,8,a1r,S,0,0}, /* rcvr.l */ + {103,8,a2r,S,0,0}, /* matm.l */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {105,7,a2r,A,0,0}, /* putr.w */ + {105,8,a2r,S,0,0}, /* putr.l */ + {106,7,a1r,A,0,0}, /* getr.w */ + {106,8,a1r,S,0,0}, /* getr.l */ + {26,13,a2r,S,0,0}, /* ste.b.f */ + {26,14,a2r,S,0,0}, /* ste.h.f */ + {26,15,a2r,S,0,0}, /* ste.w.f */ + {26,16,a2r,S,0,0}, /* ste.l.f */ + {107,7,a2r,A,0,0}, /* matr.w */ + {108,7,a2r,A,0,0}, /* mat.w */ + {109,7,a1r,A,0,0}, /* get.w */ + {110,7,a1r,A,0,0}, /* rcv.w */ + {0,0,0,0,0,0}, + {111,7,a1r,A,0,0}, /* inc.w */ + {112,7,a2r,A,0,0}, /* put.w */ + {113,7,a2r,A,0,0}, /* snd.w */ + {107,8,a2r,S,0,0}, /* matr.l */ + {108,8,a2r,S,0,0}, /* mat.l */ + {109,8,a1r,S,0,0}, /* get.l */ + {110,8,a1r,S,0,0}, /* rcv.l */ + {0,0,0,0,0,0}, + {111,8,a1r,S,0,0}, /* inc.l */ + {112,8,a2r,S,0,0}, /* put.l */ + {113,8,a2r,S,0,0}, /* snd.l */ + {18,13,a1r,V,0,0}, /* ld.b.f */ + {18,14,a1r,V,0,0}, /* ld.h.f */ + {18,15,a1r,V,0,0}, /* ld.w.f */ + {18,16,a1r,V,0,0}, /* ld.l.f */ + {21,13,a2r,V,0,0}, /* st.b.f */ + {21,14,a2r,V,0,0}, /* st.h.f */ + {21,15,a2r,V,0,0}, /* st.w.f */ + {21,16,a2r,V,0,0}, /* st.l.f */ +}; +struct formstr e0_format2[] = { + {28,5,rr,V,V,0}, /* cvtw.b */ + {28,6,rr,V,V,0}, /* cvtw.h */ + {29,7,rr,V,V,0}, /* cvtb.w */ + {30,7,rr,V,V,0}, /* cvth.w */ + {28,13,rr,V,V,0}, /* cvtw.b.f */ + {28,14,rr,V,V,0}, /* cvtw.h.f */ + {29,15,rr,V,V,0}, /* cvtb.w.f */ + {30,15,rr,V,V,0}, /* cvth.w.f */ + {31,8,rr,V,V,0}, /* cvts.l */ + {32,7,rr,V,V,0}, /* cvtd.w */ + {33,3,rr,V,V,0}, /* cvtl.s */ + {28,4,rr,V,V,0}, /* cvtw.d */ + {31,16,rr,V,V,0}, /* cvts.l.f */ + {32,15,rr,V,V,0}, /* cvtd.w.f */ + {33,11,rr,V,V,0}, /* cvtl.s.f */ + {28,12,rr,V,V,0}, /* cvtw.d.f */ + {114,0,rr,S,S,0}, /* enal */ + {8,7,rr,S,S,0}, /* shf.w */ + {115,0,rr,S,S,0}, /* enag */ + {0,0,0,0,0,0}, + {28,4,rr,S,S,0}, /* cvtw.d */ + {32,7,rr,S,S,0}, /* cvtd.w */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,3,rr,S,S,0}, /* frint.s */ + {116,4,rr,S,S,0}, /* frint.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,3,rr,V,V,0}, /* frint.s */ + {116,4,rr,V,V,0}, /* frint.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,11,rr,V,V,0}, /* frint.s.f */ + {116,12,rr,V,V,0}, /* frint.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,3,rr,V,V,0}, /* sqrt.s */ + {81,4,rr,V,V,0}, /* sqrt.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,11,rr,V,V,0}, /* sqrt.s.f */ + {81,12,rr,V,V,0}, /* sqrt.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e0_format3[] = { + {32,11,rr,V,V,0}, /* cvtd.s.f */ + {31,12,rr,V,V,0}, /* cvts.d.f */ + {33,12,rr,V,V,0}, /* cvtl.d.f */ + {32,16,rr,V,V,0}, /* cvtd.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {36,2,rr,V,V,0}, /* tzc.f */ + {44,2,rr,V,V,0}, /* lop.f */ + {117,2,rr,V,V,0}, /* xpnd.f */ + {42,2,rr,V,V,0}, /* not.f */ + {8,2,rr,S,V,0}, /* shf.f */ + {35,17,rr,V,V,0}, /* plc.t.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {37,11,rr,V,V,0}, /* eq.s.f */ + {37,12,rr,V,V,0}, /* eq.d.f */ + {43,11,rr,V,V,0}, /* neg.s.f */ + {43,12,rr,V,V,0}, /* neg.d.f */ + {37,11,rr,S,V,0}, /* eq.s.f */ + {37,12,rr,S,V,0}, /* eq.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {40,11,rr,V,V,0}, /* le.s.f */ + {40,12,rr,V,V,0}, /* le.d.f */ + {41,11,rr,V,V,0}, /* lt.s.f */ + {41,12,rr,V,V,0}, /* lt.d.f */ + {40,11,rr,S,V,0}, /* le.s.f */ + {40,12,rr,S,V,0}, /* le.d.f */ + {41,11,rr,S,V,0}, /* lt.s.f */ + {41,12,rr,S,V,0}, /* lt.d.f */ + {37,13,rr,V,V,0}, /* eq.b.f */ + {37,14,rr,V,V,0}, /* eq.h.f */ + {37,15,rr,V,V,0}, /* eq.w.f */ + {37,16,rr,V,V,0}, /* eq.l.f */ + {37,13,rr,S,V,0}, /* eq.b.f */ + {37,14,rr,S,V,0}, /* eq.h.f */ + {37,15,rr,S,V,0}, /* eq.w.f */ + {37,16,rr,S,V,0}, /* eq.l.f */ + {40,13,rr,V,V,0}, /* le.b.f */ + {40,14,rr,V,V,0}, /* le.h.f */ + {40,15,rr,V,V,0}, /* le.w.f */ + {40,16,rr,V,V,0}, /* le.l.f */ + {40,13,rr,S,V,0}, /* le.b.f */ + {40,14,rr,S,V,0}, /* le.h.f */ + {40,15,rr,S,V,0}, /* le.w.f */ + {40,16,rr,S,V,0}, /* le.l.f */ + {41,13,rr,V,V,0}, /* lt.b.f */ + {41,14,rr,V,V,0}, /* lt.h.f */ + {41,15,rr,V,V,0}, /* lt.w.f */ + {41,16,rr,V,V,0}, /* lt.l.f */ + {41,13,rr,S,V,0}, /* lt.b.f */ + {41,14,rr,S,V,0}, /* lt.h.f */ + {41,15,rr,S,V,0}, /* lt.w.f */ + {41,16,rr,S,V,0}, /* lt.l.f */ + {43,13,rr,V,V,0}, /* neg.b.f */ + {43,14,rr,V,V,0}, /* neg.h.f */ + {43,15,rr,V,V,0}, /* neg.w.f */ + {43,16,rr,V,V,0}, /* neg.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e0_format4[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e0_format5[] = { + {51,13,rr,V,V,0}, /* ldvi.b.f */ + {51,14,rr,V,V,0}, /* ldvi.h.f */ + {51,15,rr,V,V,0}, /* ldvi.w.f */ + {51,16,rr,V,V,0}, /* ldvi.l.f */ + {28,11,rr,V,V,0}, /* cvtw.s.f */ + {31,15,rr,V,V,0}, /* cvts.w.f */ + {28,16,rr,V,V,0}, /* cvtw.l.f */ + {33,15,rr,V,V,0}, /* cvtl.w.f */ + {52,13,rxr,V,V,0}, /* stvi.b.f */ + {52,14,rxr,V,V,0}, /* stvi.h.f */ + {52,15,rxr,V,V,0}, /* stvi.w.f */ + {52,16,rxr,V,V,0}, /* stvi.l.f */ + {52,13,rxr,S,V,0}, /* stvi.b.f */ + {52,14,rxr,S,V,0}, /* stvi.h.f */ + {52,15,rxr,S,V,0}, /* stvi.w.f */ + {52,16,rxr,S,V,0}, /* stvi.l.f */ +}; +struct formstr e0_format6[] = { + {0,0,rxl,S,CIR,0}, /* mov */ + {0,0,lr,CIR,S,0}, /* mov */ + {0,0,lr,TOC,S,0}, /* mov */ + {0,0,lr,CPUID,S,0}, /* mov */ + {0,0,rxl,S,TTR,0}, /* mov */ + {0,0,lr,TTR,S,0}, /* mov */ + {118,0,nops,0,0,0}, /* ctrsl */ + {119,0,nops,0,0,0}, /* ctrsg */ + {0,0,rxl,S,VMU,0}, /* mov */ + {0,0,lr,VMU,S,0}, /* mov */ + {0,0,rxl,S,VML,0}, /* mov */ + {0,0,lr,VML,S,0}, /* mov */ + {0,0,rxl,S,ICR,0}, /* mov */ + {0,0,lr,ICR,S,0}, /* mov */ + {0,0,rxl,S,TCPU,0}, /* mov */ + {0,0,lr,TCPU,S,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {120,0,nops,0,0,0}, /* stop */ + {0,0,0,0,0,0}, + {0,0,rxl,S,TID,0}, /* mov */ + {0,0,lr,TID,S,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e0_format7[] = { + {84,13,r,V,0,0}, /* sum.b.f */ + {84,14,r,V,0,0}, /* sum.h.f */ + {84,15,r,V,0,0}, /* sum.w.f */ + {84,16,r,V,0,0}, /* sum.l.f */ + {85,2,r,V,0,0}, /* all.f */ + {86,2,r,V,0,0}, /* any.f */ + {87,2,r,V,0,0}, /* parity.f */ + {0,0,0,0,0,0}, + {88,13,r,V,0,0}, /* max.b.f */ + {88,14,r,V,0,0}, /* max.h.f */ + {88,15,r,V,0,0}, /* max.w.f */ + {88,16,r,V,0,0}, /* max.l.f */ + {89,13,r,V,0,0}, /* min.b.f */ + {89,14,r,V,0,0}, /* min.h.f */ + {89,15,r,V,0,0}, /* min.w.f */ + {89,16,r,V,0,0}, /* min.l.f */ + {84,11,r,V,0,0}, /* sum.s.f */ + {84,12,r,V,0,0}, /* sum.d.f */ + {90,11,r,V,0,0}, /* prod.s.f */ + {90,12,r,V,0,0}, /* prod.d.f */ + {88,11,r,V,0,0}, /* max.s.f */ + {88,12,r,V,0,0}, /* max.d.f */ + {89,11,r,V,0,0}, /* min.s.f */ + {89,12,r,V,0,0}, /* min.d.f */ + {90,13,r,V,0,0}, /* prod.b.f */ + {90,14,r,V,0,0}, /* prod.h.f */ + {90,15,r,V,0,0}, /* prod.w.f */ + {90,16,r,V,0,0}, /* prod.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format0[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {10,18,rrr,S,V,V}, /* sub.s.t */ + {10,19,rrr,S,V,V}, /* sub.d.t */ + {4,18,rrr,S,V,V}, /* div.s.t */ + {4,19,rrr,S,V,V}, /* div.d.t */ + {3,18,rrr,V,V,V}, /* mul.s.t */ + {3,19,rrr,V,V,V}, /* mul.d.t */ + {4,18,rrr,V,V,V}, /* div.s.t */ + {4,19,rrr,V,V,V}, /* div.d.t */ + {3,18,rrr,V,S,V}, /* mul.s.t */ + {3,19,rrr,V,S,V}, /* mul.d.t */ + {4,18,rrr,V,S,V}, /* div.s.t */ + {4,19,rrr,V,S,V}, /* div.d.t */ + {5,1,rrr,V,V,V}, /* and.t */ + {6,1,rrr,V,V,V}, /* or.t */ + {7,1,rrr,V,V,V}, /* xor.t */ + {8,1,rrr,V,V,V}, /* shf.t */ + {5,1,rrr,V,S,V}, /* and.t */ + {6,1,rrr,V,S,V}, /* or.t */ + {7,1,rrr,V,S,V}, /* xor.t */ + {8,1,rrr,V,S,V}, /* shf.t */ + {9,18,rrr,V,V,V}, /* add.s.t */ + {9,19,rrr,V,V,V}, /* add.d.t */ + {10,18,rrr,V,V,V}, /* sub.s.t */ + {10,19,rrr,V,V,V}, /* sub.d.t */ + {9,18,rrr,V,S,V}, /* add.s.t */ + {9,19,rrr,V,S,V}, /* add.d.t */ + {10,18,rrr,V,S,V}, /* sub.s.t */ + {10,19,rrr,V,S,V}, /* sub.d.t */ + {9,20,rrr,V,V,V}, /* add.b.t */ + {9,21,rrr,V,V,V}, /* add.h.t */ + {9,22,rrr,V,V,V}, /* add.w.t */ + {9,23,rrr,V,V,V}, /* add.l.t */ + {9,20,rrr,V,S,V}, /* add.b.t */ + {9,21,rrr,V,S,V}, /* add.h.t */ + {9,22,rrr,V,S,V}, /* add.w.t */ + {9,23,rrr,V,S,V}, /* add.l.t */ + {10,20,rrr,V,V,V}, /* sub.b.t */ + {10,21,rrr,V,V,V}, /* sub.h.t */ + {10,22,rrr,V,V,V}, /* sub.w.t */ + {10,23,rrr,V,V,V}, /* sub.l.t */ + {10,20,rrr,V,S,V}, /* sub.b.t */ + {10,21,rrr,V,S,V}, /* sub.h.t */ + {10,22,rrr,V,S,V}, /* sub.w.t */ + {10,23,rrr,V,S,V}, /* sub.l.t */ + {3,20,rrr,V,V,V}, /* mul.b.t */ + {3,21,rrr,V,V,V}, /* mul.h.t */ + {3,22,rrr,V,V,V}, /* mul.w.t */ + {3,23,rrr,V,V,V}, /* mul.l.t */ + {3,20,rrr,V,S,V}, /* mul.b.t */ + {3,21,rrr,V,S,V}, /* mul.h.t */ + {3,22,rrr,V,S,V}, /* mul.w.t */ + {3,23,rrr,V,S,V}, /* mul.l.t */ + {4,20,rrr,V,V,V}, /* div.b.t */ + {4,21,rrr,V,V,V}, /* div.h.t */ + {4,22,rrr,V,V,V}, /* div.w.t */ + {4,23,rrr,V,V,V}, /* div.l.t */ + {4,20,rrr,V,S,V}, /* div.b.t */ + {4,21,rrr,V,S,V}, /* div.h.t */ + {4,22,rrr,V,S,V}, /* div.w.t */ + {4,23,rrr,V,S,V}, /* div.l.t */ +}; +struct formstr e1_format1[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {26,20,a2r,S,0,0}, /* ste.b.t */ + {26,21,a2r,S,0,0}, /* ste.h.t */ + {26,22,a2r,S,0,0}, /* ste.w.t */ + {26,23,a2r,S,0,0}, /* ste.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {18,20,a1r,V,0,0}, /* ld.b.t */ + {18,21,a1r,V,0,0}, /* ld.h.t */ + {18,22,a1r,V,0,0}, /* ld.w.t */ + {18,23,a1r,V,0,0}, /* ld.l.t */ + {21,20,a2r,V,0,0}, /* st.b.t */ + {21,21,a2r,V,0,0}, /* st.h.t */ + {21,22,a2r,V,0,0}, /* st.w.t */ + {21,23,a2r,V,0,0}, /* st.l.t */ +}; +struct formstr e1_format2[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {28,20,rr,V,V,0}, /* cvtw.b.t */ + {28,21,rr,V,V,0}, /* cvtw.h.t */ + {29,22,rr,V,V,0}, /* cvtb.w.t */ + {30,22,rr,V,V,0}, /* cvth.w.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {31,23,rr,V,V,0}, /* cvts.l.t */ + {32,22,rr,V,V,0}, /* cvtd.w.t */ + {33,18,rr,V,V,0}, /* cvtl.s.t */ + {28,19,rr,V,V,0}, /* cvtw.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,18,rr,V,V,0}, /* frint.s.t */ + {116,19,rr,V,V,0}, /* frint.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,18,rr,V,V,0}, /* sqrt.s.t */ + {81,19,rr,V,V,0}, /* sqrt.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format3[] = { + {32,18,rr,V,V,0}, /* cvtd.s.t */ + {31,19,rr,V,V,0}, /* cvts.d.t */ + {33,19,rr,V,V,0}, /* cvtl.d.t */ + {32,23,rr,V,V,0}, /* cvtd.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {36,1,rr,V,V,0}, /* tzc.t */ + {44,1,rr,V,V,0}, /* lop.t */ + {117,1,rr,V,V,0}, /* xpnd.t */ + {42,1,rr,V,V,0}, /* not.t */ + {8,1,rr,S,V,0}, /* shf.t */ + {35,24,rr,V,V,0}, /* plc.t.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {37,18,rr,V,V,0}, /* eq.s.t */ + {37,19,rr,V,V,0}, /* eq.d.t */ + {43,18,rr,V,V,0}, /* neg.s.t */ + {43,19,rr,V,V,0}, /* neg.d.t */ + {37,18,rr,S,V,0}, /* eq.s.t */ + {37,19,rr,S,V,0}, /* eq.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {40,18,rr,V,V,0}, /* le.s.t */ + {40,19,rr,V,V,0}, /* le.d.t */ + {41,18,rr,V,V,0}, /* lt.s.t */ + {41,19,rr,V,V,0}, /* lt.d.t */ + {40,18,rr,S,V,0}, /* le.s.t */ + {40,19,rr,S,V,0}, /* le.d.t */ + {41,18,rr,S,V,0}, /* lt.s.t */ + {41,19,rr,S,V,0}, /* lt.d.t */ + {37,20,rr,V,V,0}, /* eq.b.t */ + {37,21,rr,V,V,0}, /* eq.h.t */ + {37,22,rr,V,V,0}, /* eq.w.t */ + {37,23,rr,V,V,0}, /* eq.l.t */ + {37,20,rr,S,V,0}, /* eq.b.t */ + {37,21,rr,S,V,0}, /* eq.h.t */ + {37,22,rr,S,V,0}, /* eq.w.t */ + {37,23,rr,S,V,0}, /* eq.l.t */ + {40,20,rr,V,V,0}, /* le.b.t */ + {40,21,rr,V,V,0}, /* le.h.t */ + {40,22,rr,V,V,0}, /* le.w.t */ + {40,23,rr,V,V,0}, /* le.l.t */ + {40,20,rr,S,V,0}, /* le.b.t */ + {40,21,rr,S,V,0}, /* le.h.t */ + {40,22,rr,S,V,0}, /* le.w.t */ + {40,23,rr,S,V,0}, /* le.l.t */ + {41,20,rr,V,V,0}, /* lt.b.t */ + {41,21,rr,V,V,0}, /* lt.h.t */ + {41,22,rr,V,V,0}, /* lt.w.t */ + {41,23,rr,V,V,0}, /* lt.l.t */ + {41,20,rr,S,V,0}, /* lt.b.t */ + {41,21,rr,S,V,0}, /* lt.h.t */ + {41,22,rr,S,V,0}, /* lt.w.t */ + {41,23,rr,S,V,0}, /* lt.l.t */ + {43,20,rr,V,V,0}, /* neg.b.t */ + {43,21,rr,V,V,0}, /* neg.h.t */ + {43,22,rr,V,V,0}, /* neg.w.t */ + {43,23,rr,V,V,0}, /* neg.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format4[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format5[] = { + {51,20,rr,V,V,0}, /* ldvi.b.t */ + {51,21,rr,V,V,0}, /* ldvi.h.t */ + {51,22,rr,V,V,0}, /* ldvi.w.t */ + {51,23,rr,V,V,0}, /* ldvi.l.t */ + {28,18,rr,V,V,0}, /* cvtw.s.t */ + {31,22,rr,V,V,0}, /* cvts.w.t */ + {28,23,rr,V,V,0}, /* cvtw.l.t */ + {33,22,rr,V,V,0}, /* cvtl.w.t */ + {52,20,rxr,V,V,0}, /* stvi.b.t */ + {52,21,rxr,V,V,0}, /* stvi.h.t */ + {52,22,rxr,V,V,0}, /* stvi.w.t */ + {52,23,rxr,V,V,0}, /* stvi.l.t */ + {52,20,rxr,S,V,0}, /* stvi.b.t */ + {52,21,rxr,S,V,0}, /* stvi.h.t */ + {52,22,rxr,S,V,0}, /* stvi.w.t */ + {52,23,rxr,S,V,0}, /* stvi.l.t */ +}; +struct formstr e1_format6[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +struct formstr e1_format7[] = { + {84,20,r,V,0,0}, /* sum.b.t */ + {84,21,r,V,0,0}, /* sum.h.t */ + {84,22,r,V,0,0}, /* sum.w.t */ + {84,23,r,V,0,0}, /* sum.l.t */ + {85,1,r,V,0,0}, /* all.t */ + {86,1,r,V,0,0}, /* any.t */ + {87,1,r,V,0,0}, /* parity.t */ + {0,0,0,0,0,0}, + {88,20,r,V,0,0}, /* max.b.t */ + {88,21,r,V,0,0}, /* max.h.t */ + {88,22,r,V,0,0}, /* max.w.t */ + {88,23,r,V,0,0}, /* max.l.t */ + {89,20,r,V,0,0}, /* min.b.t */ + {89,21,r,V,0,0}, /* min.h.t */ + {89,22,r,V,0,0}, /* min.w.t */ + {89,23,r,V,0,0}, /* min.l.t */ + {84,18,r,V,0,0}, /* sum.s.t */ + {84,19,r,V,0,0}, /* sum.d.t */ + {90,18,r,V,0,0}, /* prod.s.t */ + {90,19,r,V,0,0}, /* prod.d.t */ + {88,18,r,V,0,0}, /* max.s.t */ + {88,19,r,V,0,0}, /* max.d.t */ + {89,18,r,V,0,0}, /* min.s.t */ + {89,19,r,V,0,0}, /* min.d.t */ + {90,20,r,V,0,0}, /* prod.b.t */ + {90,21,r,V,0,0}, /* prod.h.t */ + {90,22,r,V,0,0}, /* prod.w.t */ + {90,23,r,V,0,0}, /* prod.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; +char *lop[] = { + "mov", /* 0 */ + "merg", /* 1 */ + "mask", /* 2 */ + "mul", /* 3 */ + "div", /* 4 */ + "and", /* 5 */ + "or", /* 6 */ + "xor", /* 7 */ + "shf", /* 8 */ + "add", /* 9 */ + "sub", /* 10 */ + "exit", /* 11 */ + "jmp", /* 12 */ + "jmpi", /* 13 */ + "jmpa", /* 14 */ + "jmps", /* 15 */ + "tac", /* 16 */ + "ldea", /* 17 */ + "ld", /* 18 */ + "tas", /* 19 */ + "pshea", /* 20 */ + "st", /* 21 */ + "call", /* 22 */ + "calls", /* 23 */ + "callq", /* 24 */ + "pfork", /* 25 */ + "ste", /* 26 */ + "incr", /* 27 */ + "cvtw", /* 28 */ + "cvtb", /* 29 */ + "cvth", /* 30 */ + "cvts", /* 31 */ + "cvtd", /* 32 */ + "cvtl", /* 33 */ + "ldpa", /* 34 */ + "plc", /* 35 */ + "tzc", /* 36 */ + "eq", /* 37 */ + "leu", /* 38 */ + "ltu", /* 39 */ + "le", /* 40 */ + "lt", /* 41 */ + "not", /* 42 */ + "neg", /* 43 */ + "lop", /* 44 */ + "cprs", /* 45 */ + "nop", /* 46 */ + "br", /* 47 */ + "bri", /* 48 */ + "bra", /* 49 */ + "brs", /* 50 */ + "ldvi", /* 51 */ + "stvi", /* 52 */ + "ldsdr", /* 53 */ + "ldkdr", /* 54 */ + "ln", /* 55 */ + "patu", /* 56 */ + "pate", /* 57 */ + "pich", /* 58 */ + "plch", /* 59 */ + "idle", /* 60 */ + "rtnq", /* 61 */ + "cfork", /* 62 */ + "rtn", /* 63 */ + "wfork", /* 64 */ + "join", /* 65 */ + "rtnc", /* 66 */ + "exp", /* 67 */ + "sin", /* 68 */ + "cos", /* 69 */ + "psh", /* 70 */ + "pop", /* 71 */ + "eni", /* 72 */ + "dsi", /* 73 */ + "bkpt", /* 74 */ + "msync", /* 75 */ + "mski", /* 76 */ + "xmti", /* 77 */ + "tstvv", /* 78 */ + "diag", /* 79 */ + "pbkpt", /* 80 */ + "sqrt", /* 81 */ + "casr", /* 82 */ + "atan", /* 83 */ + "sum", /* 84 */ + "all", /* 85 */ + "any", /* 86 */ + "parity", /* 87 */ + "max", /* 88 */ + "min", /* 89 */ + "prod", /* 90 */ + "halt", /* 91 */ + "sysc", /* 92 */ + "trap", /* 93 */ + "tst", /* 94 */ + "lck", /* 95 */ + "ulk", /* 96 */ + "spawn", /* 97 */ + "ldcmr", /* 98 */ + "stcmr", /* 99 */ + "popr", /* 100 */ + "pshr", /* 101 */ + "rcvr", /* 102 */ + "matm", /* 103 */ + "sndr", /* 104 */ + "putr", /* 105 */ + "getr", /* 106 */ + "matr", /* 107 */ + "mat", /* 108 */ + "get", /* 109 */ + "rcv", /* 110 */ + "inc", /* 111 */ + "put", /* 112 */ + "snd", /* 113 */ + "enal", /* 114 */ + "enag", /* 115 */ + "frint", /* 116 */ + "xpnd", /* 117 */ + "ctrsl", /* 118 */ + "ctrsg", /* 119 */ + "stop", /* 120 */ +}; +char *rop[] = { + "", /* 0 */ + ".t", /* 1 */ + ".f", /* 2 */ + ".s", /* 3 */ + ".d", /* 4 */ + ".b", /* 5 */ + ".h", /* 6 */ + ".w", /* 7 */ + ".l", /* 8 */ + ".x", /* 9 */ + ".u", /* 10 */ + ".s.f", /* 11 */ + ".d.f", /* 12 */ + ".b.f", /* 13 */ + ".h.f", /* 14 */ + ".w.f", /* 15 */ + ".l.f", /* 16 */ + ".t.f", /* 17 */ + ".s.t", /* 18 */ + ".d.t", /* 19 */ + ".b.t", /* 20 */ + ".h.t", /* 21 */ + ".w.t", /* 22 */ + ".l.t", /* 23 */ + ".t.t", /* 24 */ +}; diff --git a/gdb/convex-pinsn.c b/gdb/convex-pinsn.c new file mode 100644 index 00000000000..a283d294052 --- /dev/null +++ b/gdb/convex-pinsn.c @@ -0,0 +1,314 @@ +/* Print Convex instructions for GDB, the GNU debugger. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" + +/* reg (fmt_field, inst_field) -- + the {first,second,third} operand of instruction as fmt_field = [ijk] + gets the value of the field from the [ijk] position of the instruction */ + +#define reg(a,b) ((char (*)[3])(op[fmt->a]))[inst.f0.b] + +/* lit (fmt_field) -- field [ijk] is a literal (PSW, VL, eg) */ + +#define lit(i) op[fmt->i] + +/* aj[j] -- name for A register j */ + +#define aj ((char (*)[3])(op[A])) + +union inst { + struct { + unsigned : 7; + unsigned i : 3; + unsigned j : 3; + unsigned k : 3; + unsigned : 16; + unsigned : 32; + } f0; + struct { + unsigned : 8; + unsigned indir : 1; + unsigned len : 1; + unsigned j : 3; + unsigned k : 3; + unsigned : 16; + unsigned : 32; + } f1; + unsigned char byte[8]; + unsigned short half[4]; + char signed_byte[8]; + short signed_half[4]; +}; + +struct opform { + int mask; /* opcode mask */ + int shift; /* opcode align */ + struct formstr *formstr[3]; /* ST, E0, E1 */ +}; + +struct formstr { + unsigned lop:8, rop:5; /* opcode */ + unsigned fmt:5; /* inst format */ + unsigned i:5, j:5, k:2; /* operand formats */ +}; + +#include "convex-opcode.h" + +unsigned char formdecode [] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,7,8, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +struct opform opdecode[] = { + 0x7e00, 9, format0, e0_format0, e1_format0, + 0x3f00, 8, format1, e0_format1, e1_format1, + 0x1fc0, 6, format2, e0_format2, e1_format2, + 0x0fc0, 6, format3, e0_format3, e1_format3, + 0x0700, 8, format4, e0_format4, e1_format4, + 0x03c0, 6, format5, e0_format5, e1_format5, + 0x01f8, 3, format6, e0_format6, e1_format6, + 0x00f8, 3, format7, e0_format7, e1_format7, + 0x0000, 0, formatx, formatx, formatx, + 0x0f80, 7, formatx, formatx, formatx, + 0x0f80, 7, formatx, formatx, formatx, +}; + +/* Print the 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; +{ + union inst inst; + struct formstr *fmt; + register int format, op1, pfx; + int l; + + read_memory (memaddr, &inst, sizeof inst); + + /* Remove and note prefix, if present */ + + pfx = inst.half[0]; + if ((pfx & 0xfff0) == 0x7ef0) + { + pfx = ((pfx >> 3) & 1) + 1; + *(long long *) &inst = *(long long *) &inst.half[1]; + } + else pfx = 0; + + /* Split opcode into format.op1 and look up in appropriate table */ + + format = formdecode[inst.byte[0]]; + op1 = (inst.half[0] & opdecode[format].mask) >> opdecode[format].shift; + if (format == 9) + { + if (pfx) + fmt = formatx; + else if (inst.f1.j == 0) + fmt = &format1a[op1]; + else if (inst.f1.j == 1) + fmt = &format1b[op1]; + else + fmt = formatx; + } + else + fmt = &opdecode[format].formstr[pfx][op1]; + + /* Print it */ + + if (fmt->fmt == xxx) + { + /* noninstruction */ + fprintf (stream, "0x%04x", pfx ? pfx : inst.half[0]); + return 2; + } + + if (pfx) + pfx = 2; + + fprintf (stream, "%s%s%s", lop[fmt->lop], rop[fmt->rop], + &" "[strlen(lop[fmt->lop]) + strlen(rop[fmt->rop])]); + + switch (fmt->fmt) + { + case rrr: /* three register */ + fprintf (stream, "%s,%s,%s", reg(i,i), reg(j,j), reg(k,k)); + return pfx + 2; + + case rr: /* two register */ + fprintf (stream, "%s,%s", reg(i,j), reg(j,k)); + return pfx + 2; + + case rxr: /* two register, reversed i and j fields */ + fprintf (stream, "%s,%s", reg(i,k), reg(j,j)); + return pfx + 2; + + case r: /* one register */ + fprintf (stream, "%s", reg(i,k)); + return pfx + 2; + + case nops: /* no operands */ + return pfx + 2; + + case nr: /* short immediate, one register */ + fprintf (stream, "#%d,%s", inst.f0.j, reg(i,k)); + return pfx + 2; + + case pcrel: /* pc relative */ + print_address (memaddr + 2 * inst.signed_byte[1], stream); + return pfx + 2; + + case lr: /* literal, one register */ + fprintf (stream, "%s,%s", lit(i), reg(j,k)); + return pfx + 2; + + case rxl: /* one register, literal */ + fprintf (stream, "%s,%s", reg(i,k), lit(j)); + return pfx + 2; + + case rlr: /* register, literal, register */ + fprintf (stream, "%s,%s,%s", reg(i,j), lit(j), reg(k,k)); + return pfx + 2; + + case rrl: /* register, register, literal */ + fprintf (stream, "%s,%s,%s", reg(i,j), reg(j,k), lit(k)); + return pfx + 2; + + case iml: /* immediate, literal */ + if (inst.f1.len) + { + fprintf (stream, "#%#x,%s", + (inst.signed_half[1] << 16) + inst.half[2], lit(i)); + return pfx + 6; + } + else + { + fprintf (stream, "#%d,%s", inst.signed_half[1], lit(i)); + return pfx + 4; + } + + case imr: /* immediate, register */ + if (inst.f1.len) + { + fprintf (stream, "#%#x,%s", + (inst.signed_half[1] << 16) + inst.half[2], reg(i,k)); + return pfx + 6; + } + else + { + fprintf (stream, "#%d,%s", inst.signed_half[1], reg(i,k)); + return pfx + 4; + } + + case a1r: /* memory, register */ + l = print_effa (inst, stream); + fprintf (stream, ",%s", reg(i,k)); + return pfx + l; + + case a1l: /* memory, literal */ + l = print_effa (inst, stream); + fprintf (stream, ",%s", lit(i)); + return pfx + l; + + case a2r: /* register, memory */ + fprintf (stream, "%s,", reg(i,k)); + return pfx + print_effa (inst, stream); + + case a2l: /* literal, memory */ + fprintf (stream, "%s,", lit(i)); + return pfx + print_effa (inst, stream); + + case a3: /* memory */ + return pfx + print_effa (inst, stream); + + case a4: /* system call */ + l = 29; goto a4a5; + case a5: /* trap */ + l = 27; + a4a5: + if (inst.f1.len) + { + unsigned int m = (inst.signed_half[1] << 16) + inst.half[2]; + fprintf (stream, "#%d,#%d", m >> l, m & (-1 >> (32-l))); + return pfx + 6; + } + else + { + unsigned int m = inst.signed_half[1]; + fprintf (stream, "#%d,#%d", m >> l, m & (-1 >> (32-l))); + return pfx + 4; + } + } +} + + +/* print effective address @nnn(aj), return instruction length */ + +int print_effa (inst, stream) + union inst inst; + FILE *stream; +{ + int n, l; + + if (inst.f1.len) + { + n = (inst.signed_half[1] << 16) + inst.half[2]; + l = 6; + } + else + { + n = inst.signed_half[1]; + l = 4; + } + + if (inst.f1.indir) + printf ("@"); + + if (!inst.f1.j) + { + print_address (n, stream); + return l; + } + + fprintf (stream, (n & 0xf0000000) == 0x80000000 ? "%#x(%s)" : "%d(%s)", + n, aj[inst.f1.j]); + + return l; +} diff --git a/gdb/convex-tdep.c b/gdb/convex-tdep.c new file mode 100644 index 00000000000..c206e1ed78c --- /dev/null +++ b/gdb/convex-tdep.c @@ -0,0 +1,934 @@ +/* Convex stuff for GDB. + Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "command.h" +#include "symtab.h" +#include "value.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + +#include +#include + +#include "gdbcore.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gdbcmd.h" + +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + int n; + struct stat st_exec; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + data_start = 0; + data_end = 0; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close (execchan); + execchan = -1; + + n_exec = 0; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + + if (myread (execchan, &filehdr, sizeof filehdr) < 0) + perror_with_name (filename); + + if (! IS_SOFF_MAGIC (filehdr.h_magic)) + error ("%s: not an executable file.", filename); + + if (myread (execchan, &opthdr, filehdr.h_opthdr) <= 0) + perror_with_name (filename); + + /* Read through the section headers. + For text, data, etc, record an entry in the exec file map. + Record text_start and text_end. */ + + lseek (execchan, (long) filehdr.h_scnptr, 0); + + for (n = 0; n < filehdr.h_nscns; n++) + { + if (myread (execchan, &scnhdr, sizeof scnhdr) < 0) + perror_with_name (filename); + + if ((scnhdr.s_flags & S_TYPMASK) >= S_TEXT + && (scnhdr.s_flags & S_TYPMASK) <= S_COMON) + { + exec_map[n_exec].mem_addr = scnhdr.s_vaddr; + exec_map[n_exec].mem_end = scnhdr.s_vaddr + scnhdr.s_size; + exec_map[n_exec].file_addr = scnhdr.s_scnptr; + exec_map[n_exec].type = scnhdr.s_flags & S_TYPMASK; + n_exec++; + + if ((scnhdr.s_flags & S_TYPMASK) == S_TEXT) + { + text_start = scnhdr.s_vaddr; + text_end = scnhdr.s_vaddr + scnhdr.s_size; + } + } + } + + fstat (execchan, &st_exec); + exec_mtime = st_exec.st_mtime; + + validate_files (); + } + else if (from_tty) + printf_filtered ("No exec file now.\n"); + + /* Tell display code (if any) about the changed file name. */ + if (exec_file_display_hook) + (*exec_file_display_hook) (filename); +} + +/* Read data from SOFF exec or core file. + Return 0 on success, EIO if address out of bounds. */ + +int +xfer_core_file (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + register int n; + 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. */ + + i = len; + + for (n = 0; n < n_core; n++) + { + if (memaddr >= core_map[n].mem_addr && memaddr < core_map[n].mem_end + && (core_map[n].thread == -1 + || core_map[n].thread == inferior_thread)) + { + i = min (len, core_map[n].mem_end - memaddr); + fileptr = core_map[n].file_addr + memaddr - core_map[n].mem_addr; + if (core_map[n].file_addr) + { + xferfile = &corefile; + xferchan = corechan; + } + break; + } + else if (core_map[n].mem_addr >= memaddr + && core_map[n].mem_addr < memaddr + i) + i = core_map[n].mem_addr - memaddr; + } + + if (!xferfile) + for (n = 0; n < n_exec; n++) + { + if (memaddr >= exec_map[n].mem_addr + && memaddr < exec_map[n].mem_end) + { + i = min (len, exec_map[n].mem_end - memaddr); + fileptr = exec_map[n].file_addr + memaddr + - exec_map[n].mem_addr; + if (exec_map[n].file_addr) + { + xferfile = &execfile; + xferchan = execchan; + } + break; + } + else if (exec_map[n].mem_addr >= memaddr + && exec_map[n].mem_addr < memaddr + i) + i = exec_map[n].mem_addr - memaddr; + } + + /* Now we know which file to use. + Set up its pointer and transfer the data. */ + if (xferfile) + { + if (*xferfile == 0) + if (xferfile == &execfile) + error ("No program file to examine."); + else + error ("No core dump file or running program to examine."); + val = lseek (xferchan, fileptr, 0); + if (val < 0) + perror_with_name (*xferfile); + val = myread (xferchan, myaddr, i); + if (val < 0) + perror_with_name (*xferfile); + } + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. */ + else + { + bzero (myaddr, i); + returnval = EIO; + } + + memaddr += i; + myaddr += i; + len -= i; + } + return returnval; +} + + +/* Here from info files command to print an address map. */ + +print_maps () +{ + struct pmap ptrs[200]; + int n; + + /* ID strings for core and executable file sections */ + + static char *idstr[] = + { + "0", "text", "data", "tdata", "bss", "tbss", + "common", "ttext", "ctx", "tctx", "10", "11", "12", + }; + + for (n = 0; n < n_core; n++) + { + core_map[n].which = 0; + ptrs[n] = core_map[n]; + } + for (n = 0; n < n_exec; n++) + { + exec_map[n].which = 1; + ptrs[n_core+n] = exec_map[n]; + } + + qsort (ptrs, n_core + n_exec, sizeof *ptrs, ptr_cmp); + + for (n = 0; n < n_core + n_exec; n++) + { + struct pmap *p = &ptrs[n]; + if (n > 0) + { + if (p->mem_addr < ptrs[n-1].mem_end) + p->mem_addr = ptrs[n-1].mem_end; + if (p->mem_addr >= p->mem_end) + continue; + } + printf_filtered ("%08x .. %08x %-6s %s\n", + p->mem_addr, p->mem_end, idstr[p->type], + p->which ? execfile : corefile); + } +} + +/* Compare routine to put file sections in order. + Sort into increasing order on address, and put core file sections + before exec file sections if both files contain the same addresses. */ + +static ptr_cmp (a, b) + struct pmap *a, *b; +{ + if (a->mem_addr != b->mem_addr) return a->mem_addr - b->mem_addr; + return a->which - b->which; +} + +/* Trapped internal variables are used to handle special registers. + A trapped i.v. calls a hook here every time it is dereferenced, + to provide a new value for the variable, and it calls a hook here + when a new value is assigned, to do something with the value. + + The vector registers are $vl, $vs, $vm, $vN, $VN (N in 0..7). + The communication registers are $cN, $CN (N in 0..63). + They not handled as regular registers because it's expensive to + read them, and their size varies, and they have too many names. */ + + +/* Return 1 if NAME is a trapped internal variable, else 0. */ + +int +is_trapped_internalvar (name) + char *name; +{ + if ((name[0] == 'c' || name[0] == 'C') + && name[1] >= '0' && name[1] <= '9' + && (name[2] == '\0' + || (name[2] >= '0' && name[2] <= '9' + && name[3] == '\0' && name[1] != '0')) + && atoi (&name[1]) < 64) return 1; + + if ((name[0] == 'v' || name[0] == 'V') + && (((name[1] & -8) == '0' && name[2] == '\0') + || !strcmp (name, "vl") + || !strcmp (name, "vs") + || !strcmp (name, "vm"))) + return 1; + else return 0; +} + +/* Return the value of trapped internal variable VAR */ + +value +value_of_trapped_internalvar (var) + struct internalvar *var; +{ + char *name = var->name; + value val; + struct type *type; + long len = *read_vector_register (VL_REGNUM); + if (len <= 0 || len > 128) len = 128; + + if (!strcmp (name, "vl")) + { + val = value_from_long (builtin_type_int, + (LONGEST) *read_vector_register_1 (VL_REGNUM)); + } + else if (!strcmp (name, "vs")) + { + val = value_from_long (builtin_type_int, + (LONGEST) *read_vector_register_1 (VS_REGNUM)); + } + else if (!strcmp (name, "vm")) + { + long vm[4]; + long i, *p; + bcopy (read_vector_register_1 (VM_REGNUM), vm, sizeof vm); + type = vector_type (builtin_type_int, len); + val = allocate_value (type); + p = (long *) VALUE_CONTENTS (val); + for (i = 0; i < len; i++) + *p++ = !! (vm[3 - (i >> 5)] & (1 << (i & 037))); + } + else if (name[0] == 'V') + { + type = vector_type (builtin_type_long_long, len); + val = allocate_value (type); + bcopy (read_vector_register_1 (name[1] - '0'), + VALUE_CONTENTS (val), TYPE_LENGTH (type)); + } + else if (name[0] == 'v') + { + long *p1, *p2; + type = vector_type (builtin_type_long, len); + val = allocate_value (type); + p1 = read_vector_register_1 (name[1] - '0'); + p2 = (long *) VALUE_CONTENTS (val); + while (--len >= 0) {p1++; *p2++ = *p1++;} + } + + else if (name[0] == 'c') + val = value_from_long (builtin_type_int, + read_comm_register (atoi (&name[1]))); + else if (name[0] == 'C') + val = value_from_long (builtin_type_long_long, + read_comm_register (atoi (&name[1]))); + + VALUE_LVAL (val) = lval_internalvar; + VALUE_INTERNALVAR (val) = var; + return val; +} + +/* Construct the type for a vector register's value -- + array[LENGTH] of ELEMENT_TYPE. */ + +static struct type * +vector_type (element_type, length) + struct type *element_type; + long length; +{ + struct type *type = (struct type *) xmalloc (sizeof (struct type)); + bzero (type, sizeof type); + TYPE_CODE (type) = TYPE_CODE_ARRAY; + TYPE_TARGET_TYPE (type) = element_type; + TYPE_LENGTH (type) = length * TYPE_LENGTH (TYPE_TARGET_TYPE (type)); + return type; +} + +/* Handle a new value assigned to a trapped internal variable */ + +void +set_trapped_internalvar (var, val, bitpos, bitsize, offset) + struct internalvar *var; + value val; + int bitpos, bitsize, offset; +{ + char *name = var->name; + long long newval = value_as_long (val); + + if (!strcmp (name, "vl")) + write_vector_register (VL_REGNUM, 0, newval); + else if (!strcmp (name, "vs")) + write_vector_register (VS_REGNUM, 0, newval); + else if (name[0] == 'c' || name[0] == 'C') + write_comm_register (atoi (&name[1]), newval); + else if (!strcmp (name, "vm")) + error ("can't assign to $vm"); + else + { + offset /= bitsize / 8; + write_vector_register (name[1] - '0', offset, newval); + } +} + +/* Print an integer value when no format was specified. gdb normally + prints these values in decimal, but the the leading 0x80000000 of + pointers produces intolerable 10-digit negative numbers. + If it looks like an address, print it in hex instead. */ + +decout (stream, type, val) + FILE *stream; + struct type *type; + LONGEST val; +{ + long lv = val; + + switch (output_radix) + { + case 0: + if ((lv == val || (unsigned) lv == val) + && ((lv & 0xf0000000) == 0x80000000 + || ((lv & 0xf0000000) == 0xf0000000 && lv < STACK_END_ADDR))) + { + fprintf_filtered (stream, "%#x", lv); + return; + } + + case 10: + fprintf_filtered (stream, TYPE_UNSIGNED (type) ? "%llu" : "%lld", val); + return; + + case 8: + if (TYPE_LENGTH (type) <= sizeof lv) + fprintf_filtered (stream, "%#o", lv); + else + fprintf_filtered (stream, "%#llo", val); + return; + + case 16: + if (TYPE_LENGTH (type) <= sizeof lv) + fprintf_filtered (stream, "%#x", lv); + else + fprintf_filtered (stream, "%#llx", val); + return; + } +} + +/* Change the default output radix to 10 or 16, or set it to 0 (heuristic). + This command is mostly obsolete now that the print command allows + formats to apply to aggregates, but is still handy occasionally. */ + +static void +set_base_command (arg) + char *arg; +{ + int new_radix; + + if (!arg) + output_radix = 0; + else + { + new_radix = atoi (arg); + if (new_radix != 10 && new_radix != 16 && new_radix != 8) + error ("base must be 8, 10 or 16, or null"); + else output_radix = new_radix; + } +} + +/* Turn pipelining on or off in the inferior. */ + +static void +set_pipelining_command (arg) + char *arg; +{ + if (!arg) + { + sequential = !sequential; + printf_filtered ("%s\n", sequential ? "off" : "on"); + } + else if (!strcmp (arg, "on")) + sequential = 0; + else if (!strcmp (arg, "off")) + sequential = 1; + else error ("valid args are `on', to allow instructions to overlap, or\n\ +`off', to prevent it and thereby pinpoint exceptions."); +} + +/* Enable, disable, or force parallel execution in the inferior. */ + +static void +set_parallel_command (arg) + char *arg; +{ + struct rlimit rl; + int prevparallel = parallel; + + if (!strncmp (arg, "fixed", strlen (arg))) + parallel = 2; + else if (!strcmp (arg, "on")) + parallel = 1; + else if (!strcmp (arg, "off")) + parallel = 0; + else error ("valid args are `on', to allow multiple threads, or\n\ +`fixed', to force multiple threads, or\n\ +`off', to run with one thread only."); + + if ((prevparallel == 0) != (parallel == 0) && inferior_pid) + printf_filtered ("will take effect at next run.\n"); + + getrlimit (RLIMIT_CONCUR, &rl); + rl.rlim_cur = parallel ? rl.rlim_max : 1; + setrlimit (RLIMIT_CONCUR, &rl); + + if (inferior_pid) + set_fixed_scheduling (inferior_pid, parallel == 2); +} + +/* Add a new name for an existing command. */ + +static void +alias_command (arg) + char *arg; +{ + static char *aliaserr = "usage is `alias NEW OLD', no args allowed"; + char *newname = arg; + struct cmd_list_element *new, *old; + + if (!arg) + error_no_arg ("newname oldname"); + + new = lookup_cmd (&arg, cmdlist, "", -1); + if (new && !strncmp (newname, new->name, strlen (new->name))) + { + newname = new->name; + if (!(*arg == '-' + || (*arg >= 'a' && *arg <= 'z') + || (*arg >= 'A' && *arg <= 'Z') + || (*arg >= '0' && *arg <= '9'))) + error (aliaserr); + } + else + { + arg = newname; + while (*arg == '-' + || (*arg >= 'a' && *arg <= 'z') + || (*arg >= 'A' && *arg <= 'Z') + || (*arg >= '0' && *arg <= '9')) + arg++; + if (*arg != ' ' && *arg != '\t') + error (aliaserr); + *arg = '\0'; + arg++; + } + + old = lookup_cmd (&arg, cmdlist, "", 0); + + if (*arg != '\0') + error (aliaserr); + + if (new && !strncmp (newname, new->name, strlen (new->name))) + { + char *tem; + if (new->class == (int) class_user || new->class == (int) class_alias) + tem = "Redefine command \"%s\"? "; + else + tem = "Really redefine built-in command \"%s\"? "; + if (!query (tem, new->name)) + error ("Command \"%s\" not redefined.", new->name); + } + + add_com (newname, class_alias, old->function, old->doc); +} + + + +/* Print the current thread number, and any threads with signals in the + queue. */ + +thread_info () +{ + struct threadpid *p; + + if (have_inferior_p ()) + { + ps.pi_buffer = (char *) &comm_registers; + ps.pi_nbytes = sizeof comm_registers; + ps.pi_offset = 0; + ps.pi_thread = inferior_thread; + ioctl (inferior_fd, PIXRDCREGS, &ps); + } + + printf_filtered ("Current thread %d stopped with signal %d.%d (%s).\n", + inferior_thread, stop_signal, stop_sigcode, + subsig_name (stop_signal, stop_sigcode)); + + for (p = signal_stack; p->pid; p--) + printf_filtered ("Thread %d stopped with signal %d.%d (%s).\n", + p->thread, p->signo, p->subsig, + subsig_name (p->signo, p->subsig)); + + if (iscrlbit (comm_registers.crctl.lbits.cc, 64+13)) + printf_filtered ("New thread start pc %#x\n", + (long) (comm_registers.crreg.pcpsw >> 32)); +} + +/* Return string describing a signal.subcode number */ + +static char * +subsig_name (signo, subcode) + int signo, subcode; +{ + static char *subsig4[] = { + "error exit", "privileged instruction", "unknown", + "unknown", "undefined opcode", + 0}; + static char *subsig5[] = {0, + "breakpoint", "single step", "fork trap", "exec trap", "pfork trap", + "join trap", "idle trap", "last thread", "wfork trap", + "process breakpoint", "trap instruction", + 0}; + static char *subsig8[] = {0, + "int overflow", "int divide check", "float overflow", + "float divide check", "float underflow", "reserved operand", + "sqrt error", "exp error", "ln error", "sin error", "cos error", + 0}; + static char *subsig10[] = {0, + "invalid inward ring address", "invalid outward ring call", + "invalid inward ring return", "invalid syscall gate", + "invalid rtn frame length", "invalid comm reg address", + "invalid trap gate", + 0}; + static char *subsig11[] = {0, + "read access denied", "write access denied", "execute access denied", + "segment descriptor fault", "page table fault", "data reference fault", + "i/o access denied", "levt pte invalid", + 0}; + + static char **subsig_list[] = + {0, 0, 0, 0, subsig4, subsig5, 0, 0, subsig8, 0, subsig10, subsig11, 0}; + + int i; + char *p = signo < NSIG ? sys_siglist[signo] : "unknown"; + + if (signo >= (sizeof subsig_list / sizeof *subsig_list) + || !subsig_list[signo]) + return p; + for (i = 1; subsig_list[signo][i]; i++) + if (i == subcode) + return subsig_list[signo][subcode]; + return p; +} + + +/* Print a compact display of thread status, essentially x/i $pc + for all active threads. */ + +static void +threadstat () +{ + int t; + + for (t = 0; t < n_threads; t++) + if (thread_state[t] == PI_TALIVE) + { + printf_filtered ("%d%c %08x%c %d.%d ", t, + (t == inferior_thread ? '*' : ' '), thread_pc[t], + (thread_is_in_kernel[t] ? '#' : ' '), + thread_signal[t], thread_sigcode[t]); + print_insn (thread_pc[t], stdout); + printf_filtered ("\n"); + } +} + +/* Change the current thread to ARG. */ + +set_thread_command (arg) + char *arg; +{ + int thread; + + if (!arg) + { + threadstat (); + return; + } + + thread = parse_and_eval_address (arg); + + if (thread < 0 || thread > n_threads || thread_state[thread] != PI_TALIVE) + error ("no such thread."); + + select_thread (thread); + + stop_pc = read_pc (); + flush_cached_frames (); + set_current_frame (create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + print_sel_frame (1); +} + +/* Here on CONT command; gdb's dispatch address is changed to come here. + Set global variable ALL_CONTINUE to tell resume() that it should + start up all threads, and that a thread switch will not blow gdb's + mind. */ + +static void +convex_cont_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + all_continue = 1; + cont_command (proc_count_exp, from_tty); +} + +/* Here on 1CONT command. Resume only the current thread. */ + +one_cont_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + cont_command (proc_count_exp, from_tty); +} + +/* Print the contents and lock bits of all communication registers, + or just register ARG if ARG is a communication register, + or the 3-word resource structure in memory at address ARG. */ + +comm_registers_info (arg) + char *arg; +{ + int i, regnum; + + if (arg) + { + if (sscanf (arg, "0x%x", ®num) == 1 + || sscanf (arg, "%d", ®num) == 1) + { + if (regnum > 0) + regnum &= ~0x8000; + } + else if (sscanf (arg, "$c%d", ®num) == 1) + ; + else if (sscanf (arg, "$C%d", ®num) == 1) + ; + else + regnum = parse_and_eval_address (arg); + + if (regnum >= 64) + error ("%s: invalid register name.", arg); + + /* if we got a (user) address, examine the resource struct there */ + + if (regnum < 0) + { + static int buf[3]; + read_memory (regnum, buf, sizeof buf); + printf_filtered ("%08x %08x%08x%s\n", regnum, buf[1], buf[2], + buf[0] & 0xff ? " locked" : ""); + return; + } + } + + ps.pi_buffer = (char *) &comm_registers; + ps.pi_nbytes = sizeof comm_registers; + ps.pi_offset = 0; + ps.pi_thread = inferior_thread; + ioctl (inferior_fd, PIXRDCREGS, &ps); + + for (i = 0; i < 64; i++) + if (!arg || i == regnum) + printf_filtered ("%2d 0x8%03x %016llx%s\n", i, i, + comm_registers.crreg.r4[i], + (iscrlbit (comm_registers.crctl.lbits.cc, i) + ? " locked" : "")); +} + +/* Print the psw */ + +static void +psw_info (arg) + char *arg; +{ + struct pswbit + { + int bit; + int pos; + char *text; + }; + + static struct pswbit pswbit[] = + { + { 0x80000000, -1, "A carry" }, + { 0x40000000, -1, "A integer overflow" }, + { 0x20000000, -1, "A zero divide" }, + { 0x10000000, -1, "Integer overflow enable" }, + { 0x08000000, -1, "Trace" }, + { 0x06000000, 25, "Frame length" }, + { 0x01000000, -1, "Sequential" }, + { 0x00800000, -1, "S carry" }, + { 0x00400000, -1, "S integer overflow" }, + { 0x00200000, -1, "S zero divide" }, + { 0x00100000, -1, "Zero divide enable" }, + { 0x00080000, -1, "Floating underflow" }, + { 0x00040000, -1, "Floating overflow" }, + { 0x00020000, -1, "Floating reserved operand" }, + { 0x00010000, -1, "Floating zero divide" }, + { 0x00008000, -1, "Floating error enable" }, + { 0x00004000, -1, "Floating underflow enable" }, + { 0x00002000, -1, "IEEE" }, + { 0x00001000, -1, "Sequential stores" }, + { 0x00000800, -1, "Intrinsic error" }, + { 0x00000400, -1, "Intrinsic error enable" }, + { 0x00000200, -1, "Trace thread creates" }, + { 0x00000100, -1, "Thread init trap" }, + { 0x000000e0, 5, "Reserved" }, + { 0x0000001f, 0, "Intrinsic error code" }, + {0, 0, 0}, + }; + + long psw; + struct pswbit *p; + + if (arg) + psw = parse_and_eval_address (arg); + else + psw = read_register (PS_REGNUM); + + for (p = pswbit; p->bit; p++) + { + if (p->pos < 0) + printf_filtered ("%08x %s %s\n", p->bit, + (psw & p->bit) ? "yes" : "no ", p->text); + else + printf_filtered ("%08x %3d %s\n", p->bit, + (psw & p->bit) >> p->pos, p->text); + } +} + +_initialize_convex_dep () +{ + add_com ("alias", class_support, alias_command, + "Add a new name for an existing command."); + + add_cmd ("base", class_vars, set_base_command, + "Change the integer output radix to 8, 10 or 16\n\ +or use just `set base' with no args to return to the ad-hoc default,\n\ +which is 16 for integers that look like addresses, 10 otherwise.", + &setlist); + + add_cmd ("pipeline", class_run, set_pipelining_command, + "Enable or disable overlapped execution of instructions.\n\ +With `set pipe off', exceptions are reported with\n\ +$pc pointing at the instruction after the faulting one.\n\ +The default is `set pipe on', which runs faster.", + &setlist); + + add_cmd ("parallel", class_run, set_parallel_command, + "Enable or disable multi-threaded execution of parallel code.\n\ +`set parallel off' means run the program on a single CPU.\n\ +`set parallel fixed' means run the program with all CPUs assigned to it.\n\ +`set parallel on' means run the program on any CPUs that are available.", + &setlist); + + add_com ("1cont", class_run, one_cont_command, + "Continue the program, activating only the current thread.\n\ +Args are the same as the `cont' command."); + + add_com ("thread", class_run, set_thread_command, + "Change the current thread, the one under scrutiny and control.\n\ +With no arg, show the active threads, the current one marked with *."); + + add_info ("threads", thread_info, + "List status of active threads."); + + add_info ("comm-registers", comm_registers_info, + "List communication registers and their contents.\n\ +A communication register name as argument means describe only that register.\n\ +An address as argument means describe the resource structure at that address.\n\ +`Locked' means that the register has been sent to but not yet received from."); + + add_info ("psw", psw_info, + "Display $ps, the processor status word, bit by bit.\n\ +An argument means display that value's interpretation as a psw."); + + add_cmd ("convex", no_class, 0, "Convex-specific commands.\n\ +32-bit registers $pc $ps $sp $ap $fp $a1-5 $s0-7 $v0-7 $vl $vs $vm $c0-63\n\ +64-bit registers $S0-7 $V0-7 $C0-63\n\ +\n\ +info threads display info on stopped threads waiting to signal\n\ +thread display list of active threads\n\ +thread N select thread N (its registers, stack, memory, etc.)\n\ +step, next, etc step selected thread only\n\ +1cont continue selected thread only\n\ +cont continue all threads\n\ +info comm-registers display contents of comm register(s) or a resource struct\n\ +info psw display processor status word $ps\n\ +set base N change integer radix used by `print' without a format\n\ +set pipeline off exceptions are precise, $pc points after the faulting insn\n\ +set pipeline on normal mode, $pc is somewhere ahead of faulting insn\n\ +set parallel off program runs on a single CPU\n\ +set parallel fixed all CPUs are assigned to the program\n\ +set parallel on normal mode, parallel execution on random available CPUs\n\ +", + &cmdlist); + +} diff --git a/gdb/convex-xdep.c b/gdb/convex-xdep.c new file mode 100644 index 00000000000..f9f44a0eab2 --- /dev/null +++ b/gdb/convex-xdep.c @@ -0,0 +1,983 @@ +/* Convex stuff for GDB. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "command.h" +#include "symtab.h" +#include "value.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + +#include +#include +#include "gdbcore.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Per-thread data, read from the inferior at each stop and written + back at each resume. */ + +/* Number of active threads. + Tables are valid for thread numbers less than this. */ + +static int n_threads; + +#define MAXTHREADS 8 + +/* Thread state. The remaining data is valid only if this is PI_TALIVE. */ + +static int thread_state[MAXTHREADS]; + +/* Stop pc, signal, signal subcode */ + +static int thread_pc[MAXTHREADS]; +static int thread_signal[MAXTHREADS]; +static int thread_sigcode[MAXTHREADS]; + +/* Thread registers. + If thread is selected, the regs are in registers[] instead. */ + +static char thread_regs[MAXTHREADS][REGISTER_BYTES]; + +/* 1 if the top frame on the thread's stack was a context frame, + meaning that the kernel is up to something and we should not + touch the thread at all except to resume it. */ + +static char thread_is_in_kernel[MAXTHREADS]; + +/* The currently selected thread's number. */ + +static int inferior_thread; + +/* Inferior process's file handle and a process control block + to feed args to ioctl with. */ + +static int inferior_fd; +static struct pcntl ps; + +/* SOFF file headers for exec or core file. */ + +static FILEHDR filehdr; +static OPTHDR opthdr; +static SCNHDR scnhdr; + +/* Address maps constructed from section headers of exec and core files. + Defines process address -> file address translation. */ + +struct pmap +{ + long mem_addr; /* process start address */ + long mem_end; /* process end+1 address */ + long file_addr; /* file start address */ + long thread; /* -1 shared; 0,1,... thread-local */ + long type; /* S_TEXT S_DATA S_BSS S_TBSS etc */ + long which; /* used to sort map for info files */ +}; + +static int n_exec, n_core; +static struct pmap exec_map[100]; +static struct pmap core_map[100]; + +/* Offsets in the core file of core_context and core_tcontext blocks. */ + +static int context_offset; +static int tcontext_offset[MAXTHREADS]; + +/* Core file control blocks. */ + +static struct core_context_v70 c; +static struct core_tcontext_v70 tc; +static struct user u; +static thread_t th; +static proc_t pr; + +/* The registers of the currently selected thread. */ + +extern char registers[REGISTER_BYTES]; + +/* Vector and communication registers from core dump or from inferior. + These are read on demand, ie, not normally valid. */ + +static struct vecst vector_registers; +static struct creg_ctx comm_registers; + +/* Flag, set on a vanilla CONT command and cleared when the inferior + is continued. */ + +static int all_continue; + +/* Flag, set when the inferior is continued by a vanilla CONT command, + cleared if it is continued for any other purpose. */ + +static int thread_switch_ok; + +/* Stack of signals recieved from threads but not yet delivered to gdb. */ + +struct threadpid +{ + int pid; + int thread; + int signo; + int subsig; + int pc; +}; + +static struct threadpid signal_stack_bot[100]; +static struct threadpid *signal_stack = signal_stack_bot; + +/* How to detect empty stack -- bottom frame is all zero. */ + +#define signal_stack_is_empty() (signal_stack->pid == 0) + +/* Mode controlled by SET PIPE command, controls the psw SEQ bit + which forces each instruction to complete before the next one starts. */ + +static int sequential = 0; + +/* Mode controlled by the SET PARALLEL command. Values are: + 0 concurrency limit 1 thread, dynamic scheduling + 1 no concurrency limit, dynamic scheduling + 2 no concurrency limit, fixed scheduling */ + +static int parallel = 1; + +/* Mode controlled by SET BASE command, output radix for unformatted + integer typeout, as in argument lists, aggregates, and so on. + Zero means guess whether it's an address (hex) or not (decimal). */ + +static int output_radix = 0; + +/* Signal subcode at last thread stop. */ + +static int stop_sigcode; + +/* Hack, see wait() below. */ + +static int exec_trap_timer; + +#include "gdbcmd.h" + +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + +extern int attach_flag; + + + +static struct type *vector_type (); +static long *read_vector_register (); +static long *read_vector_register_1 (); +static void write_vector_register (); +static REGISTER_TYPE read_comm_register (); +static void write_comm_register (); +static void convex_cont_command (); +static void thread_continue (); +static void select_thread (); +static void scan_stack (); +static void set_fixed_scheduling (); +static char *subsig_name (); +static void psw_info (); +static sig_noop (); +static ptr_cmp (); + +extern char *sys_siglist[]; + +/* Execute ptrace. Convex V7 replaced ptrace with pattach. + Allow ptrace (0) as a no-op. */ + +int +call_ptrace (request, pid, procaddr, buf) + int request, pid, procaddr, buf; +{ + if (request == 0) + return; + error ("no ptrace"); +} + +/* Replacement for system execle routine. + Convert it to an equivalent exect, which pattach insists on. */ + +execle (name, argv) + char *name, *argv; +{ + char ***envp = (char ***) &argv; + while (*envp++) ; + + signal (SIGTRAP, sig_noop); + exect (name, &argv, *envp); +} + +/* Stupid handler for stupid trace trap that otherwise causes + startup to stupidly hang. */ + +static sig_noop () +{} + +/* Read registers from inferior into registers[] array. + For convex, they are already there, read in when the inferior stops. */ + +void +fetch_inferior_registers (regno) + int regno; +{ +} + +/* Store our register values back into the inferior. + For Convex, do this only once, right before resuming inferior. */ + +store_inferior_registers (regno) + int regno; +{ +} + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. + On failure (cannot read from inferior, usually because address is out + of bounds) returns the value of errno. */ + +int +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + errno = 0; + while (len > 0) + { + /* little-known undocumented max request size */ + int i = (len < 12288) ? len : 12288; + + lseek (inferior_fd, memaddr, 0); + read (inferior_fd, myaddr, i); + + memaddr += i; + myaddr += i; + len -= i; + } + if (errno) + bzero (myaddr, len); + return errno; +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + Returns errno on failure (cannot write the inferior) */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + errno = 0; + lseek (inferior_fd, memaddr, 0); + write (inferior_fd, myaddr, len); + return errno; +} + +/* Here from create_inferior when the inferior process has been created + and started up. We must do a pattach to grab it for debugging. + + Also, intercept the CONT command by altering its dispatch address. */ + +create_inferior_hook (pid) + int pid; +{ + static char cont[] = "cont"; + static char cont1[] = "c"; + char *linep = cont; + char *linep1 = cont1; + char **line = &linep; + char **line1 = &linep1; + struct cmd_list_element *c; + + c = lookup_cmd (line, cmdlist, "", 0); + c->function = convex_cont_command; + c = lookup_cmd (line1, cmdlist, "", 0); + c->function = convex_cont_command; + + inferior_fd = pattach (pid, O_EXCL); + if (inferior_fd < 0) + perror_with_name ("pattach"); + inferior_thread = 0; + set_fixed_scheduling (pid, parallel == 2); +} + +/* Attach process PID for debugging. */ + +attach (pid) + int pid; +{ + int fd = pattach (pid, O_EXCL); + if (fd < 0) + perror_with_name ("pattach"); + attach_flag = 1; + /* wait for strange kernel reverberations to go away */ + sleep (1); + + setpgrp (pid, pid); + + inferior_fd = fd; + inferior_thread = 0; + 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; +{ + signal_stack = signal_stack_bot; + thread_continue (-1, 0, signal); + ioctl (inferior_fd, PIXDETACH, &ps); + close (inferior_fd); + inferior_fd = 0; + attach_flag = 0; +} + +/* Kill off the inferior process. */ + +kill_inferior () +{ + if (inferior_pid == 0) + return; + ioctl (inferior_fd, PIXTERMINATE, 0); + wait (0); + target_mourn_inferior (); +} + +/* This is used when GDB is exiting. It gives less chance of error.*/ + +kill_inferior_fast () +{ + if (inferior_pid == 0) + return; + ioctl (inferior_fd, PIXTERMINATE, 0); + wait (0); +} + +/* Read vector register REG, and return a pointer to the value. */ + +static long * +read_vector_register (reg) + int reg; +{ + if (have_inferior_p ()) + { + errno = 0; + ps.pi_buffer = (char *) &vector_registers; + ps.pi_nbytes = sizeof vector_registers; + ps.pi_offset = 0; + ps.pi_thread = inferior_thread; + ioctl (inferior_fd, PIXRDVREGS, &ps); + if (errno) + bzero (&vector_registers, sizeof vector_registers); + } + else if (corechan >= 0) + { + lseek (corechan, tcontext_offset[inferior_thread], 0); + if (myread (corechan, &tc, sizeof tc) < 0) + perror_with_name (corefile); + lseek (corechan, tc.core_thread_p, 0); + if (myread (corechan, &th, sizeof th) < 0) + perror_with_name (corefile); + lseek (corechan, tc.core_vregs_p, 0); + if (myread (corechan, &vector_registers, 16*128) < 0) + perror_with_name (corefile); + vector_registers.vm[0] = th.t_vect_ctx.vc_vm[0]; + vector_registers.vm[1] = th.t_vect_ctx.vc_vm[1]; + vector_registers.vls = th.t_vect_ctx.vc_vls; + } + + return read_vector_register_1 (reg); +} + +/* Return a pointer to vector register REG, which must already have been + fetched from the inferior or core file. */ + +static long * +read_vector_register_1 (reg) + int reg; +{ + switch (reg) + { + case VM_REGNUM: + return (long *) vector_registers.vm; + case VS_REGNUM: + return (long *) &vector_registers.vls; + case VL_REGNUM: + return 1 + (long *) &vector_registers.vls; + default: + return (long *) &vector_registers.vr[reg]; + } +} + +/* Write vector register REG, element ELEMENT, new value VAL. + NB: must use read-modify-write on the entire vector state, + since pattach does not do offsetted writes correctly. */ + +static void +write_vector_register (reg, element, val) + int reg, element; + REGISTER_TYPE val; +{ + if (have_inferior_p ()) + { + errno = 0; + ps.pi_thread = inferior_thread; + ps.pi_offset = 0; + ps.pi_buffer = (char *) &vector_registers; + ps.pi_nbytes = sizeof vector_registers; + + ioctl (inferior_fd, PIXRDVREGS, &ps); + + switch (reg) + { + case VL_REGNUM: + vector_registers.vls = + (vector_registers.vls & 0xffffffff00000000LL) + + (unsigned long) val; + break; + + case VS_REGNUM: + vector_registers.vls = + (val << 32) + (unsigned long) vector_registers.vls; + break; + + default: + vector_registers.vr[reg].el[element] = val; + break; + } + + ioctl (inferior_fd, PIXWRVREGS, &ps); + + if (errno) + perror_with_name ("writing vector register"); + } +} + +/* Return the contents of communication register NUM. */ + +static REGISTER_TYPE +read_comm_register (num) + int num; +{ + if (have_inferior_p ()) + { + ps.pi_buffer = (char *) &comm_registers; + ps.pi_nbytes = sizeof comm_registers; + ps.pi_offset = 0; + ps.pi_thread = inferior_thread; + ioctl (inferior_fd, PIXRDCREGS, &ps); + } + return comm_registers.crreg.r4[num]; +} + +/* Store a new value VAL into communication register NUM. + NB: Must use read-modify-write on the whole comm register set + since pattach does not do offsetted writes correctly. */ + +static void +write_comm_register (num, val) + int num; + REGISTER_TYPE val; +{ + if (have_inferior_p ()) + { + ps.pi_buffer = (char *) &comm_registers; + ps.pi_nbytes = sizeof comm_registers; + ps.pi_offset = 0; + ps.pi_thread = inferior_thread; + ioctl (inferior_fd, PIXRDCREGS, &ps); + comm_registers.crreg.r4[num] = val; + ioctl (inferior_fd, PIXWRCREGS, &ps); + } +} + +/* 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 (step || signal) + thread_continue (inferior_thread, step, signal); + else + thread_continue (-1, 0, 0); +} + +/* Maybe resume some threads. + THREAD is which thread to resume, or -1 to resume them all. + STEP and SIGNAL are as in resume. + + Global variable ALL_CONTINUE is set when we are here to do a + `cont' command; otherwise we may be doing `finish' or a call or + something else that will not tolerate an automatic thread switch. + + If there are stopped threads waiting to deliver signals, and + ALL_CONTINUE, do not actually resume anything. gdb will do a wait + and see one of the stopped threads in the queue. */ + +static void +thread_continue (thread, step, signal) + int thread, step, signal; +{ + int n; + + /* If we are to continue all threads, but not for the CONTINUE command, + pay no attention and continue only the selected thread. */ + + if (thread < 0 && ! all_continue) + thread = inferior_thread; + + /* If we are not stepping, we have now executed the continue part + of a CONTINUE command. */ + + if (! step) + all_continue = 0; + + /* Allow wait() to switch threads if this is an all-out continue. */ + + thread_switch_ok = thread < 0; + + /* If there are threads queued up, don't resume. */ + + if (thread_switch_ok && ! signal_stack_is_empty ()) + return; + + /* OK, do it. */ + + for (n = 0; n < n_threads; n++) + if (thread_state[n] == PI_TALIVE) + { + select_thread (n); + + if ((thread < 0 || n == thread) && ! thread_is_in_kernel[n]) + { + /* Blam the trace bits in the stack's saved psws to match + the desired step mode. This is required so that + single-stepping a return doesn't restore a psw with a + clear trace bit and fly away, and conversely, + proceeding through a return in a routine that was + stepped into doesn't cause a phantom break by restoring + a psw with the trace bit set. */ + scan_stack (PSW_T_BIT, step); + scan_stack (PSW_S_BIT, sequential); + } + + ps.pi_buffer = registers; + ps.pi_nbytes = REGISTER_BYTES; + ps.pi_offset = 0; + ps.pi_thread = n; + if (! thread_is_in_kernel[n]) + if (ioctl (inferior_fd, PIXWRREGS, &ps)) + perror_with_name ("PIXWRREGS"); + + if (thread < 0 || n == thread) + { + ps.pi_pc = 1; + ps.pi_signo = signal; + if (ioctl (inferior_fd, step ? PIXSTEP : PIXCONTINUE, &ps) < 0) + perror_with_name ("PIXCONTINUE"); + } + } + + if (ioctl (inferior_fd, PIXRUN, &ps) < 0) + perror_with_name ("PIXRUN"); +} + +/* Replacement for system wait routine. + + The system wait returns with one or more threads stopped by + signals. Put stopped threads on a stack and return them one by + one, so that it appears that wait returns one thread at a time. + + Global variable THREAD_SWITCH_OK is set when gdb can tolerate wait + returning a new thread. If it is false, then only one thread is + running; we will do a real wait, the thread will do something, and + we will return that. */ + +pid_t +wait (w) + union wait *w; +{ + int pid; + + if (!w) + return wait3 (0, 0, 0); + + /* Do a real wait if we were told to, or if there are no queued threads. */ + + if (! thread_switch_ok || signal_stack_is_empty ()) + { + int thread; + + pid = wait3 (w, 0, 0); + + if (!WIFSTOPPED (*w) || pid != inferior_pid) + return pid; + + /* The inferior has done something and stopped. Read in all the + threads' registers, and queue up any signals that happened. */ + + if (ioctl (inferior_fd, PIXGETTHCOUNT, &ps) < 0) + perror_with_name ("PIXGETTHCOUNT"); + + n_threads = ps.pi_othdcnt; + for (thread = 0; thread < n_threads; thread++) + { + ps.pi_thread = thread; + if (ioctl (inferior_fd, PIXGETSUBCODE, &ps) < 0) + perror_with_name ("PIXGETSUBCODE"); + thread_state[thread] = ps.pi_otstate; + + if (ps.pi_otstate == PI_TALIVE) + { + select_thread (thread); + ps.pi_buffer = registers; + ps.pi_nbytes = REGISTER_BYTES; + ps.pi_offset = 0; + ps.pi_thread = thread; + if (ioctl (inferior_fd, PIXRDREGS, &ps) < 0) + perror_with_name ("PIXRDREGS"); + + registers_fetched (); + + thread_pc[thread] = read_pc (); + thread_signal[thread] = ps.pi_osigno; + thread_sigcode[thread] = ps.pi_osigcode; + + /* If the thread's stack has a context frame + on top, something fucked is going on. I do not + know what, but do I know this: the only thing you + can do with such a thread is continue it. */ + + thread_is_in_kernel[thread] = + ((read_register (PS_REGNUM) >> 25) & 3) == 0; + + /* Signals push an extended frame and then fault + with a ridiculous pc. Pop the frame. */ + + if (thread_pc[thread] > STACK_END_ADDR) + { + POP_FRAME; + if (is_break_pc (thread_pc[thread])) + thread_pc[thread] = read_pc () - 2; + else + thread_pc[thread] = read_pc (); + write_register (PC_REGNUM, thread_pc[thread]); + } + + if (ps.pi_osigno || ps.pi_osigcode) + { + signal_stack++; + signal_stack->pid = pid; + signal_stack->thread = thread; + signal_stack->signo = thread_signal[thread]; + signal_stack->subsig = thread_sigcode[thread]; + signal_stack->pc = thread_pc[thread]; + } + + /* The following hackery is caused by a unix 7.1 feature: + the inferior's fixed scheduling mode is cleared when + it execs the shell (since the shell is not a parallel + program). So, note the 5.4 trap we get when + the shell does its exec, then catch the 5.0 trap + that occurs when the debuggee starts, and set fixed + scheduling mode properly. */ + + if (ps.pi_osigno == 5 && ps.pi_osigcode == 4) + exec_trap_timer = 1; + else + exec_trap_timer--; + + if (ps.pi_osigno == 5 && exec_trap_timer == 0) + set_fixed_scheduling (pid, parallel == 2); + } + } + + if (signal_stack_is_empty ()) + error ("no active threads?!"); + } + + /* Select the thread that stopped, and return *w saying why. */ + + select_thread (signal_stack->thread); + + stop_signal = signal_stack->signo; + stop_sigcode = signal_stack->subsig; + + WSETSTOP (*w, signal_stack->signo); + w->w_thread = signal_stack->thread; + return (signal_stack--)->pid; +} + +/* Select thread THREAD -- its registers, stack, per-thread memory. + This is the only routine that may assign to inferior_thread + or thread_regs[]. */ + +static void +select_thread (thread) + int thread; +{ + if (thread == inferior_thread) + return; + + bcopy (registers, thread_regs[inferior_thread], REGISTER_BYTES); + ps.pi_thread = inferior_thread = thread; + if (have_inferior_p ()) + ioctl (inferior_fd, PISETRWTID, &ps); + bcopy (thread_regs[thread], registers, REGISTER_BYTES); +} + +/* Routine to set or clear a psw bit in the psw and also all psws + saved on the stack. Quits when we get to a frame in which the + saved psw is correct. */ + +static void +scan_stack (bit, val) + long bit, val; +{ + long ps = read_register (PS_REGNUM); + long fp; + if (val ? !(ps & bit) : (ps & bit)) + { + ps ^= bit; + write_register (PS_REGNUM, ps); + + fp = read_register (FP_REGNUM); + while (fp & 0x80000000) + { + ps = read_memory_integer (fp + 4, 4); + if (val ? (ps & bit) : !(ps & bit)) + break; + ps ^= bit; + write_memory (fp + 4, &ps, 4); + fp = read_memory_integer (fp + 8, 4); + } + } +} + +/* Set fixed scheduling (alliant mode) of process PID to ARG (0 or 1). */ + +static void +set_fixed_scheduling (pid, arg) + int arg; +{ + struct pattributes pattr; + getpattr (pid, &pattr); + pattr.pattr_pfixed = arg; + setpattr (pid, &pattr); +} + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int n; + + /* 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; + n_core = 0; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + + if (myread (corechan, &filehdr, sizeof filehdr) < 0) + perror_with_name (filename); + + if (!IS_CORE_SOFF_MAGIC (filehdr.h_magic)) + error ("%s: not a core file.\n", filename); + + if (myread (corechan, &opthdr, filehdr.h_opthdr) < 0) + perror_with_name (filename); + + /* Read through the section headers. + For text, data, etc, record an entry in the core file map. + For context and tcontext, record the file address of + the context blocks. */ + + lseek (corechan, (long) filehdr.h_scnptr, 0); + + n_threads = 0; + for (n = 0; n < filehdr.h_nscns; n++) + { + if (myread (corechan, &scnhdr, sizeof scnhdr) < 0) + perror_with_name (filename); + if ((scnhdr.s_flags & S_TYPMASK) >= S_TEXT + && (scnhdr.s_flags & S_TYPMASK) <= S_COMON) + { + core_map[n_core].mem_addr = scnhdr.s_vaddr; + core_map[n_core].mem_end = scnhdr.s_vaddr + scnhdr.s_size; + core_map[n_core].file_addr = scnhdr.s_scnptr; + core_map[n_core].type = scnhdr.s_flags & S_TYPMASK; + if (core_map[n_core].type != S_TBSS + && core_map[n_core].type != S_TDATA + && core_map[n_core].type != S_TTEXT) + core_map[n_core].thread = -1; + else if (n_core == 0 + || core_map[n_core-1].mem_addr != scnhdr.s_vaddr) + core_map[n_core].thread = 0; + else + core_map[n_core].thread = core_map[n_core-1].thread + 1; + n_core++; + } + else if ((scnhdr.s_flags & S_TYPMASK) == S_CONTEXT) + context_offset = scnhdr.s_scnptr; + else if ((scnhdr.s_flags & S_TYPMASK) == S_TCONTEXT) + tcontext_offset[n_threads++] = scnhdr.s_scnptr; + } + + /* Read the context block, struct user, struct proc, + and the comm regs. */ + + lseek (corechan, context_offset, 0); + if (myread (corechan, &c, sizeof c) < 0) + perror_with_name (filename); + lseek (corechan, c.core_user_p, 0); + if (myread (corechan, &u, sizeof u) < 0) + perror_with_name (filename); + lseek (corechan, c.core_proc_p, 0); + if (myread (corechan, &pr, sizeof pr) < 0) + perror_with_name (filename); + comm_registers = pr.p_creg; + + /* Core file apparently is really there. Make it really exist + for xfer_core_file so we can do read_memory on it. */ + + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + corefile = concat (current_directory, "/", filename); + + printf_filtered ("Program %s ", u.u_comm); + + /* Read the thread registers and fill in the thread_xxx[] data. */ + + for (n = 0; n < n_threads; n++) + { + select_thread (n); + + lseek (corechan, tcontext_offset[n], 0); + if (myread (corechan, &tc, sizeof tc) < 0) + perror_with_name (corefile); + lseek (corechan, tc.core_thread_p, 0); + if (myread (corechan, &th, sizeof th) < 0) + perror_with_name (corefile); + + lseek (corechan, tc.core_syscall_context_p, 0); + if (myread (corechan, registers, REGISTER_BYTES) < 0) + perror_with_name (corefile); + + thread_signal[n] = th.t_cursig; + thread_sigcode[n] = th.t_code; + thread_state[n] = th.t_state; + thread_pc[n] = read_pc (); + + if (thread_pc[n] > STACK_END_ADDR) + { + POP_FRAME; + if (is_break_pc (thread_pc[n])) + thread_pc[n] = read_pc () - 2; + else + thread_pc[n] = read_pc (); + write_register (PC_REGNUM, thread_pc[n]); + } + + printf_filtered ("thread %d received signal %d, %s\n", + n, thread_signal[n], + thread_signal[n] < NSIG + ? sys_siglist[thread_signal[n]] + : "(undocumented)"); + } + + /* Select an interesting thread -- also-rans died with SIGKILL, + so find one that didn't. */ + + for (n = 0; n < n_threads; n++) + if (thread_signal[n] != 0 && thread_signal[n] != SIGKILL) + { + select_thread (n); + stop_signal = thread_signal[n]; + stop_sigcode = thread_sigcode[n]; + break; + } + + core_aouthdr.a_magic = 0; + + flush_cached_frames (); + set_current_frame (create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + validate_files (); + + print_sel_frame (1); + } + else if (from_tty) + printf_filtered ("No core file now.\n"); +} diff --git a/gdb/core.c b/gdb/core.c new file mode 100644 index 00000000000..2936e46d5d2 --- /dev/null +++ b/gdb/core.c @@ -0,0 +1,447 @@ +/* Work with core dump and executable files, for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include "defs.h" +#include "param.h" +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "symtab.h" +#include "command.h" +#include "bfd.h" +#include "target.h" +#include "gdbcore.h" + +extern int xfer_memory (); +extern void child_attach (), child_create_inferior (); + +extern int sys_nerr; +extern char *sys_errlist[]; +extern char *sys_siglist[]; + +extern char registers[]; + +/* Hook for `exec_file_command' command to call. */ + +void (*exec_file_display_hook) () = NULL; + +struct section_table *core_sections, *core_sections_end; + +/* Binary file diddling handle for the core file. */ + +bfd *core_bfd = NULL; + +/* Forward decl */ +extern struct target_ops core_ops; + + +/* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + +void +core_close (quitting) + int quitting; +{ + if (core_bfd) { + free (bfd_get_filename (core_bfd)); + bfd_close (core_bfd); + core_bfd = NULL; + } +} + +/* This routine opens and sets up the core file bfd */ + +void +core_open (filename, from_tty) + char *filename; + int from_tty; +{ + char *p; + int siggy; + struct cleanup *old_chain; + char *temp; + bfd *temp_bfd; + int ontop; + + if (!filename) + { + error (core_bfd? + "No core file specified. (Use `detach' to stop debugging a core file.)" + : "No core file specified."); + } + + filename = tilde_expand (filename); + if (filename[0] != '/') { + temp = concat (current_directory, "/", filename); + free (filename); + filename = temp; + } + + old_chain = make_cleanup (free, filename); + temp_bfd = bfd_openr (filename, NULL); + if (temp_bfd == NULL) + { + perror_with_name (filename); + } + + if (!bfd_check_format (temp_bfd, bfd_core)) + { + bfd_close (temp_bfd); + error ("\"%s\" does not appear to be a core dump", filename); + } + + /* Looks semi-reasonable. Toss the old core file and work on the new. */ + + discard_cleanups (old_chain); /* Don't free filename any more */ + unpush_target (&core_ops); + core_bfd = temp_bfd; + old_chain = make_cleanup (core_close, core_bfd); + + validate_files (); + + /* Find the data section */ + if (build_section_table (core_bfd, &core_sections, &core_sections_end)) + error ("Can't find sections in `%s': %s", bfd_get_filename(core_bfd), + bfd_errmsg (bfd_error)); + + ontop = !push_target (&core_ops); + + p = bfd_core_file_failing_command (core_bfd); + if (p) + printf ("Core file invoked as `%s'.\n", p); + + siggy = bfd_core_file_failing_signal (core_bfd); + if (siggy > 0) + printf ("Program terminated with signal %d, %s.\n", siggy, + siggy < NSIG ? sys_siglist[siggy] : "(undocumented)"); + + if (ontop) { + /* Fetch all registers from core file */ + target_fetch_registers (-1); + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + /* FIXME, handle shared library reading here. */ + print_sel_frame (0); /* Print the top frame and source line */ + } else { + printf ( +"Warning: you won't be able to access this core file until you terminate\n\ +your %s; do ``info files''\n", current_target->to_longname); + } + + discard_cleanups (old_chain); +} + +void +core_detach (args, from_tty) + char *args; + int from_tty; +{ + dont_repeat (); + if (args) + error ("Too many arguments"); + pop_target (); + if (from_tty) + printf ("No core file now.\n"); +} + +/* Backward compatability with old way of specifying core files. */ + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + if (!filename) + core_detach (filename, from_tty); + else + core_open (filename, from_tty); +} + + +/* 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 () +{ +#ifdef FIXME + if (exec_bfd) + bfd_tempclose (exec_bfd); +#endif +} + +void +reopen_exec_file () +{ +#ifdef FIXME + if (exec_bfd) + bfd_reopen (exec_bfd); +#endif +} + +/* 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 (exec_bfd && core_bfd) + { + if (core_file_matches_executable_p (core_bfd, exec_bfd)) + printf ("Warning: core file does not match specified executable file.\n"); + else if (bfd_get_mtime(exec_bfd) > bfd_get_mtime(core_bfd)) + 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 (exec_bfd) return bfd_get_filename(exec_bfd); + if (!err) return NULL; + + error ("No executable file specified.\n\ +Use the \"file\" or \"exec-file\" command."); + return NULL; +} + +static void +core_files_info () +{ + struct section_table *p; + + printf ("\tCore file `%s'.\n", bfd_get_filename(core_bfd)); + + for (p = core_sections; p < core_sections_end; p++) + printf("\tcore file from 0x%08x to 0x%08x is %s\n", + p->addr, p->endaddr, + bfd_section_name (core_bfd, p->sec_ptr)); +} + +void +memory_error (status, memaddr) + int status; + CORE_ADDR memaddr; +{ + + if (status == EIO) + { + /* Actually, address between memaddr and memaddr + len + was out of bounds. */ + error ("Cannot access memory: address 0x%x out of bounds.", memaddr); + } + else + { + if (status >= sys_nerr || status < 0) + error ("Error accessing memory address 0x%x: unknown error (%d).", + memaddr, status); + else + error ("Error accessing memory address 0x%x: %s.", + memaddr, sys_errlist[status]); + } +} + +/* Same as target_read_memory, but report an error if can't read. */ +void +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int status; + status = target_read_memory (memaddr, myaddr, len); + if (status != 0) + memory_error (status, memaddr); +} + +/* Same as target_write_memory, but report an error if can't write. */ +void +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int status; + + status = target_write_memory (memaddr, myaddr, len); + if (status != 0) + memory_error (status, memaddr); +} + +/* Read an integer from debugged memory, given address and number of bytes. */ + +long +read_memory_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + char cbuf; + short sbuf; + int ibuf; + long lbuf; + + if (len == sizeof (char)) + { + read_memory (memaddr, &cbuf, len); + return cbuf; + } + if (len == sizeof (short)) + { + read_memory (memaddr, (char *)&sbuf, len); + SWAP_TARGET_AND_HOST (&sbuf, sizeof (short)); + return sbuf; + } + if (len == sizeof (int)) + { + read_memory (memaddr, (char *)&ibuf, len); + SWAP_TARGET_AND_HOST (&ibuf, sizeof (int)); + return ibuf; + } + if (len == sizeof (lbuf)) + { + read_memory (memaddr, (char *)&lbuf, len); + SWAP_TARGET_AND_HOST (&lbuf, sizeof (lbuf)); + return lbuf; + } + error ("Cannot handle integers of %d bytes.", len); + return -1; /* for lint */ +} + +/* Read or write the core file. + + Args are address within core file, address within gdb address-space, + length, and a flag indicating whether to read or write. + + Result is a length: + + 0: We cannot handle this address and length. + > 0: We have handled N bytes starting at this address. + (If N == length, we did it all.) We might be able + to handle more bytes beyond this length, but no + promises. + < 0: We cannot handle this address, but if somebody + else handles (-N) bytes, we can start from there. + + The actual work is done by xfer_memory in exec.c, which we share + in common with exec_xfer_memory(). */ + +static int +core_xfer_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + return xfer_memory (memaddr, myaddr, len, write, + core_bfd, core_sections, core_sections_end); +} + +/* Get the registers out of a core file. This is the machine- + independent part. Fetch_core_registers is the machine-dependent + part, typically implemented in the xm-file for each architecture. */ + +static int +get_core_registers (regno) + int regno; +{ + sec_ptr reg_sec; + unsigned size; + char *the_regs; + + reg_sec = bfd_get_section_by_name (core_bfd, ".reg"); + size = bfd_section_size (core_bfd, reg_sec); + the_regs = alloca (size); + if (bfd_get_section_contents (core_bfd, reg_sec, the_regs, + (unsigned)0, size)) + { + fetch_core_registers (the_regs, size, 0); + } + else + { + fprintf (stderr, "Couldn't fetch registers from core file: %s\n", + bfd_errmsg (bfd_error)); + } + + /* Now do it again for the float registers, if they exist. */ + reg_sec = bfd_get_section_by_name (core_bfd, ".reg2"); + if (reg_sec) { + size = bfd_section_size (core_bfd, reg_sec); + the_regs = alloca (size); + if (bfd_get_section_contents (core_bfd, reg_sec, the_regs, + (unsigned)0, size)) + { + fetch_core_registers (the_regs, size, 2); + } + else + { + fprintf (stderr, "Couldn't fetch register set 2 from core file: %s\n", + bfd_errmsg (bfd_error)); + } + } + registers_fetched(); + return 0; /* FIXME, what result goes here? */ +} + +struct target_ops core_ops = { + "core", "Local core dump file", + core_open, core_close, + child_attach, core_detach, 0, 0, /* resume, wait */ + get_core_registers, + 0, 0, 0, 0, /* store_regs, prepare_to_store, conv_to, conv_from */ + core_xfer_memory, core_files_info, + 0, 0, /* core_insert_breakpoint, core_remove_breakpoint, */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, 0, 0, 0, 0, /* kill, load, add_syms, call fn, lookup sym */ + child_create_inferior, 0, /* mourn_inferior */ + core_stratum, 0, /* next */ + 0, 1, 1, 1, 0, /* all mem, mem, stack, regs, exec */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_core() +{ + + 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. This command has been superseded by the\n\ +`target core' and `detach' commands."); + add_target (&core_ops); +} diff --git a/gdb/coredep.c b/gdb/coredep.c new file mode 100644 index 00000000000..ea1c2734d29 --- /dev/null +++ b/gdb/coredep.c @@ -0,0 +1,86 @@ +/* Extract registers from a "standard" core file, for GDB. + Copyright (C) 1988-1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* core.c is supposed to be the more machine-independent aspects of this; + this file is more machine-specific. */ + +#include "defs.h" +#include "param.h" +#include "gdbcore.h" + +/* Some of these are needed on various systems, perhaps, to expand + REGISTER_U_ADDR appropriately? */ +/* #include */ +#include +#include +#include +#include +#include + + +/* Extract the register values out of the core file and store + them where `read_register' will find them. */ + +void +fetch_core_registers (core_reg_sect, core_reg_size) + char *core_reg_sect; + unsigned core_reg_size; +{ + register int regno; + register unsigned int addr; + int bad_reg = -1; + + for (regno = 0; regno < NUM_REGS; regno++) + { + addr = register_addr (regno, core_reg_size); + if (addr >= core_reg_size) { + if (bad_reg < 0) + bad_reg = regno; + } else { + supply_register (regno, core_reg_sect + addr); + } + } + if (bad_reg > 0) + { + error ("Register %s not found in core file.", reg_names[bad_reg]); + } +} + + +#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 */ diff --git a/gdb/cplus-dem.c b/gdb/cplus-dem.c new file mode 100644 index 00000000000..48109d8fa03 --- /dev/null +++ b/gdb/cplus-dem.c @@ -0,0 +1,1001 @@ +/* Demangler for GNU C++ + Copyright (C) 1989 Free Software Foundation, Inc. + written by James Clark (jjc@jclark.uucp) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This is for g++ 1.36.1 (November 6 version). It will probably + require changes for any other version. + + Modified for g++ 1.36.2 (November 18 version). */ + +/* This file exports one function + + char *cplus_demangle (const char *name, int mode) + + If NAME is a mangled function name produced by GNU C++, then + a pointer to a malloced string giving a C++ representation + of the name will be returned; otherwise NULL will be returned. + It is the caller's responsibility to free the string which + is returned. + + If MODE > 0, then ANSI qualifiers such as `const' and `void' are output. + Otherwise they are not. + If MODE >= 0, parameters are emitted; otherwise not. + + For example, + + cplus_demangle ("foo__1Ai", 0) => "A::foo(int)" + cplus_demangle ("foo__1Ai", 1) => "A::foo(int)" + cplus_demangle ("foo__1Ai", -1) => "A::foo" + + cplus_demangle ("foo__1Afe", 0) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", 1) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", -1) => "A::foo" + + This file imports xmalloc and xrealloc, which are like malloc and + realloc except that they generate a fatal error if there is no + available memory. */ + +/* define this if names don't start with _ */ +/* #define nounderscore 1 */ + +#include +#include + +#ifdef USG +#include +#include +#else +#include +#define memcpy(s1, s2, n) bcopy ((s2), (s1), (n)) +#define memcmp(s1, s2, n) bcmp ((s2), (s1), (n)) +#define strchr index +#define strrchr rindex +#endif + +#ifndef __STDC__ +#define const +#endif + +#ifdef __STDC__ +extern char *cplus_demangle (const char *type, int mode); +#else +extern char *cplus_demangle (); +#endif + +#ifdef __STDC__ +extern char *xmalloc (int); +extern char *xrealloc (char *, int); +extern void free (char *); +#else +extern char *xmalloc (); +extern char *xrealloc (); +extern void free (); +#endif + +static char **typevec = 0; +static int ntypes = 0; +static int typevec_size = 0; + +static struct { + const char *in; + const char *out; +} optable[] = { + "new", " new", + "delete", " delete", + "ne", "!=", + "eq", "==", + "ge", ">=", + "gt", ">", + "le", "<=", + "lt", "<", + "plus", "+", + "minus", "-", + "mult", "*", + "convert", "+", /* unary + */ + "negate", "-", /* unary - */ + "trunc_mod", "%", + "trunc_div", "/", + "truth_andif", "&&", + "truth_orif", "||", + "truth_not", "!", + "postincrement", "++", + "postdecrement", "--", + "bit_ior", "|", + "bit_xor", "^", + "bit_and", "&", + "bit_not", "~", + "call", "()", + "cond", "?:", + "alshift", "<<", + "arshift", ">>", + "component", "->", + "indirect", "*", + "method_call", "->()", + "addr", "&", /* unary & */ + "array", "[]", + "nop", "", /* for operator= */ +}; + +/* Beware: these aren't '\0' terminated. */ + +typedef struct { + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +#ifdef __STDC__ +static void string_need (string *s, int n); +static void string_delete (string *s); +static void string_init (string *s); +static void string_clear (string *s); +static int string_empty (string *s); +static void string_append (string *p, const char *s); +static void string_appends (string *p, string *s); +static void string_appendn (string *p, const char *s, int n); +static void string_prepend (string *p, const char *s); +#if 0 +static void string_prepends (string *p, string *s); +#endif +static void string_prependn (string *p, const char *s, int n); +static int get_count (const char **type, int *count); +static int do_args (const char **type, string *decl, int arg_mode); +static int do_type (const char **type, string *result, int arg_mode); +static int do_arg (const char **type, string *result, int arg_mode); +static void munge_function_name (string *name, int arg_mode); +static void remember_type (const char *type, int len); +#else +static void string_need (); +static void string_delete (); +static void string_init (); +static void string_clear (); +static int string_empty (); +static void string_append (); +static void string_appends (); +static void string_appendn (); +static void string_prepend (); +#if 0 +static void string_prepends (); +#endif +static void string_prependn (); +static int get_count (); +static int do_args (); +static int do_type (); +static int do_arg (); +static int do_args (); +static void munge_function_name (); +static void remember_type (); +#endif + +char * +cplus_demangle (type, arg_mode) + const char *type; + int arg_mode; +{ + string decl; + int n; + int success = 0; + int constructor = 0; + int const_flag = 0; + int i; + const char *p; +#ifndef LONGERNAMES + const char *premangle; +#endif + +# define print_ansi_qualifiers (arg_mode > 0) +# define print_arg_types (arg_mode >= 0) + + if (type == NULL || *type == '\0') + return NULL; +#ifndef nounderscore + if (*type++ != '_') + return NULL; +#endif + p = type; + while (*p != '\0' && !(*p == '_' && p[1] == '_')) + p++; + if (*p == '\0') + { + /* destructor */ + if (type[0] == '_' && type[1] == '$' && type[2] == '_') + { + int n = (strlen (type) - 3)*2 + 3 + 2 + 1; + char *tem = (char *) xmalloc (n); + strcpy (tem, type + 3); + strcat (tem, "::~"); + strcat (tem, type + 3); + strcat (tem, "()"); + return tem; + } + /* static data member */ + if (*type != '_' && (p = strchr (type, '$')) != NULL) + { + int n = strlen (type) + 2; + char *tem = (char *) xmalloc (n); + memcpy (tem, type, p - type); + strcpy (tem + (p - type), "::"); + strcpy (tem + (p - type) + 2, p + 1); + return tem; + } + /* virtual table "_vt$" */ + if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$') + { + int n = strlen (type + 4) + 14 + 1; + char *tem = (char *) xmalloc (n); + strcpy (tem, type + 4); + strcat (tem, " virtual table"); + return tem; + } + return NULL; + } + + string_init (&decl); + + if (p == type) + { + if (!isdigit (p[2])) + { + string_delete (&decl); + return NULL; + } + constructor = 1; + } + else + { + string_appendn (&decl, type, p - type); + munge_function_name (&decl, arg_mode); + } + p += 2; + +#ifndef LONGERNAMES + premangle = p; +#endif + switch (*p) + { + case 'C': + /* a const member function */ + if (!isdigit (p[1])) + { + string_delete (&decl); + return NULL; + } + p += 1; + const_flag = 1; + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do + { + n *= 10; + n += *p - '0'; + p += 1; + } + while (isdigit (*p)); + if (strlen (p) < n) + { + string_delete (&decl); + return NULL; + } + if (constructor) + { + string_appendn (&decl, p, n); + string_append (&decl, "::"); + string_appendn (&decl, p, n); + } + else + { + string_prepend (&decl, "::"); + string_prependn (&decl, p, n); + } + p += n; +#ifndef LONGERNAMES + remember_type (premangle, p - premangle); +#endif + success = do_args (&p, &decl, arg_mode); + if (const_flag && print_arg_types) + string_append (&decl, " const"); + break; + case 'F': + p += 1; + success = do_args (&p, &decl, arg_mode); + break; + } + + for (i = 0; i < ntypes; i++) + if (typevec[i] != NULL) + free (typevec[i]); + ntypes = 0; + if (typevec != NULL) + { + free ((char *)typevec); + typevec = NULL; + typevec_size = 0; + } + + if (success) + { + string_appendn (&decl, "", 1); + return decl.b; + } + else + { + string_delete (&decl); + return NULL; + } +} + +static int +get_count (type, count) + const char **type; + int *count; +{ + if (!isdigit (**type)) + return 0; + *count = **type - '0'; + *type += 1; + /* see flush_repeats in cplus-method.c */ + if (isdigit (**type)) + { + const char *p = *type; + int n = *count; + do + { + n *= 10; + n += *p - '0'; + p += 1; + } + while (isdigit (*p)); + if (*p == '_') + { + *type = p + 1; + *count = n; + } + } + return 1; +} + +/* result will be initialised here; it will be freed on failure */ + +static int +do_type (type, result, arg_mode) + const char **type; + string *result; + int arg_mode; +{ + int n; + int done; + int non_empty = 0; + int success; + string decl; + const char *remembered_type; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + while (success && !done) + { + int member; + switch (**type) + { + case 'P': + *type += 1; + string_prepend (&decl, "*"); + break; + + case 'R': + *type += 1; + string_prepend (&decl, "&"); + break; + + case 'T': + *type += 1; + if (!get_count (type, &n) || n >= ntypes) + success = 0; + else + { + remembered_type = typevec[n]; + type = &remembered_type; + } + break; + + case 'F': + *type += 1; + if (!string_empty (&decl) && decl.b[0] == '*') + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + if (!do_args (type, &decl, arg_mode) || **type != '_') + success = 0; + else + *type += 1; + break; + + case 'M': + case 'O': + { + int constp = 0; + int volatilep = 0; + + member = **type == 'M'; + *type += 1; + if (!isdigit (**type)) + { + success = 0; + break; + } + n = 0; + do + { + n *= 10; + n += **type - '0'; + *type += 1; + } + while (isdigit (**type)); + if (strlen (*type) < n) + { + success = 0; + break; + } + string_append (&decl, ")"); + string_prepend (&decl, "::"); + string_prependn (&decl, *type, n); + string_prepend (&decl, "("); + *type += n; + if (member) + { + if (**type == 'C') + { + *type += 1; + constp = 1; + } + if (**type == 'V') + { + *type += 1; + volatilep = 1; + } + if (*(*type)++ != 'F') + { + success = 0; + break; + } + } + if ((member && !do_args (type, &decl, arg_mode)) || **type != '_') + { + success = 0; + break; + } + *type += 1; + if (! print_ansi_qualifiers) + break; + if (constp) + { + if (non_empty) + string_append (&decl, " "); + else + non_empty = 1; + string_append (&decl, "const"); + } + if (volatilep) + { + if (non_empty) + string_append (&decl, " "); + else + non_empty = 1; + string_append (&decl, "volatile"); + } + break; + } + + case 'C': + if ((*type)[1] == 'P') + { + *type += 1; + if (print_ansi_qualifiers) + { + if (!string_empty (&decl)) + string_prepend (&decl, " "); + string_prepend (&decl, "const"); + } + break; + } + + /* fall through */ + default: + done = 1; + break; + } + } + + done = 0; + non_empty = 0; + while (success && !done) + { + switch (**type) + { + case 'C': + *type += 1; + if (print_ansi_qualifiers) + { + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "const"); + } + break; + case 'U': + *type += 1; + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "unsigned"); + break; + case 'V': + *type += 1; + if (print_ansi_qualifiers) + { + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "volatile"); + } + break; + default: + done = 1; + break; + } + } + + if (success) + switch (**type) + { + case '\0': + case '_': + break; + case 'v': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "void"); + break; + case 'x': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long long"); + break; + case 'l': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long"); + break; + case 'i': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "int"); + break; + case 's': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "short"); + break; + case 'c': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "char"); + break; + case 'r': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long double"); + break; + case 'd': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "double"); + break; + case 'f': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "float"); + break; + case 'G': + *type += 1; + if (!isdigit (**type)) + { + success = 0; + break; + } + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do + { + n *= 10; + n += **type - '0'; + *type += 1; + } + while (isdigit (**type)); + if (strlen (*type) < n) + { + success = 0; + break; + } + if (non_empty) + string_append (result, " "); + string_appendn (result, *type, n); + *type += n; + break; + default: + success = 0; + break; + } + + if (success) + { + if (!string_empty (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + string_delete (&decl); + return 1; + } + else + { + string_delete (&decl); + string_delete (result); + return 0; + } +} + +/* `result' will be initialised in do_type; it will be freed on failure */ + +static int +do_arg (type, result, arg_mode) + const char **type; + string *result; + int arg_mode; +{ + const char *start = *type; + + if (!do_type (type, result, arg_mode)) + return 0; + remember_type (start, *type - start); + return 1; +} + +static void +remember_type (start, len) + const char *start; + int len; +{ + char *tem; + + if (ntypes >= typevec_size) + { + if (typevec_size == 0) + { + typevec_size = 3; + typevec = (char **) xmalloc (sizeof (char*)*typevec_size); + } + else + { + typevec_size *= 2; + typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size); + } + } + tem = (char *) xmalloc (len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + typevec[ntypes++] = tem; +} + +/* `decl' must be already initialised, usually non-empty; + it won't be freed on failure */ + +static int +do_args (type, decl, arg_mode) + const char **type; + string *decl; + int arg_mode; +{ + string arg; + int need_comma = 0; + + if (print_arg_types) + string_append (decl, "("); + + while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v') + { + if (**type == 'N') + { + int r; + int t; + *type += 1; + if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes) + return 0; + while (--r >= 0) + { + const char *tem = typevec[t]; + if (need_comma && print_arg_types) + string_append (decl, ", "); + if (!do_arg (&tem, &arg, arg_mode)) + return 0; + if (print_arg_types) + string_appends (decl, &arg); + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma & print_arg_types) + string_append (decl, ", "); + if (!do_arg (type, &arg, arg_mode)) + return 0; + if (print_arg_types) + string_appends (decl, &arg); + string_delete (&arg); + need_comma = 1; + } + } + + if (**type == 'v') + *type += 1; + else if (**type == 'e') + { + *type += 1; + if (print_arg_types) + { + if (need_comma) + string_append (decl, ","); + string_append (decl, "..."); + } + } + + if (print_arg_types) + string_append (decl, ")"); + return 1; +} + +static void +munge_function_name (name, arg_mode) + string *name; + int arg_mode; +{ + if (!string_empty (name) && name->p - name->b >= 3 + && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$') + { + int i; + /* see if it's an assignment expression */ + if (name->p - name->b >= 10 /* op$assign_ */ + && memcmp (name->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++) + { + int len = name->p - name->b - 10; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, name->b + 10, len) == 0) + { + string_clear (name); + string_append (name, "operator"); + string_append (name, optable[i].out); + string_append (name, "="); + return; + } + } + } + else + { + for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++) + { + int len = name->p - name->b - 3; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, name->b + 3, len) == 0) + { + string_clear (name); + string_append (name, "operator"); + string_append (name, optable[i].out); + return; + } + } + } + return; + } + else if (!string_empty (name) && name->p - name->b >= 5 + && memcmp (name->b, "type$", 5) == 0) + { + /* type conversion operator */ + string type; + const char *tem = name->b + 5; + if (do_type (&tem, &type, arg_mode)) + { + string_clear (name); + string_append (name, "operator "); + string_appends (name, &type); + string_delete (&type); + return; + } + } +} + +/* a mini string-handling package */ + +static void +string_need (s, n) + string *s; + int n; +{ + if (s->b == NULL) + { + if (n < 32) + n = 32; + s->p = s->b = (char *) xmalloc (n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + int tem = s->p - s->b; + n += tem; + n *= 2; + s->b = (char *) xrealloc (s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void +string_delete (s) + string *s; +{ + if (s->b != NULL) + { + free (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void +string_init (s) + string *s; +{ + s->b = s->p = s->e = NULL; +} + +static void +string_clear (s) + string *s; +{ + s->p = s->b; +} + +static int +string_empty (s) + string *s; +{ + return s->b == s->p; +} + +static void +string_append (p, s) + string *p; + const char *s; +{ + int n; + if (s == NULL || *s == '\0') + return; + n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_appends (p, s) + string *p, *s; +{ + int n; + if (s->b == s->p) + return; + n = s->p - s->b; + string_need (p, n); + memcpy (p->p, s->b, n); + p->p += n; +} + +static void +string_appendn (p, s, n) + string *p; + const char *s; + int n; +{ + if (n == 0) + return; + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_prepend (p, s) + string *p; + const char *s; +{ + if (s == NULL || *s == '\0') + return; + string_prependn (p, s, strlen (s)); +} + +#if 0 +static void +string_prepends (p, s) + string *p, *s; +{ + if (s->b == s->p) + return; + string_prependn (p, s->b, s->p - s->b); +} +#endif + +static void +string_prependn (p, s, n) + string *p; + const char *s; + int n; +{ + char *q; + + if (n == 0) + return; + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + q[n] = q[0]; + memcpy (p->b, s, n); + p->p += n; +} diff --git a/gdb/createtags b/gdb/createtags new file mode 100755 index 00000000000..6f02ff23f70 --- /dev/null +++ b/gdb/createtags @@ -0,0 +1,20 @@ +#!/bin/sh +# +# Here we check to see if we are compiling in a directory that contains +# symlinks to the source files instead of the actual files. If this is so, +# we setup the TAGS entries to point to the actual source directory. +# +filelist="" +if test "`find main.c -type l -print `" != "" ; then + prefix=`ls -l main.c | awk '{print $11}' | sed 's;main.c$;;'` +else + prefix="" +fi + +# Replace .o at end of filename with .c +for i in $@ ; do + file=`echo $i-x- | sed -e 's/\.o-x-/\.c-x-/' | sed -e 's/-x-//'` + filelist="$filelist $prefix$file" +done + +etags $filelist diff --git a/gdb/depend b/gdb/depend new file mode 100755 index 00000000000..c78aa667e2f --- /dev/null +++ b/gdb/depend @@ -0,0 +1,195 @@ +altos-xdep.o : altos-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h gdbcore.h $(INCLUDE_DIR)/bfd.h +am29k-pinsn.o : am29k-pinsn.c defs.h target.h am29k-opcode.h +am29k-tdep.o : am29k-tdep.c defs.h gdbcore.h $(INCLUDE_DIR)/bfd.h frame.h \ + param.h tm.h config.status param-no-tm.h xm.h config.status value.h symtab.h inferior.h breakpoint.h +arm-pinsn.o : arm-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + arm-opcode.h +arm-tdep.o : arm-tdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h arm-opcode.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +arm-xdep.o : arm-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h arm-opcode.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +blockframe.o : blockframe.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + frame.h gdbcore.h $(INCLUDE_DIR)/bfd.h value.h target.h +breakpoint.o : breakpoint.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + frame.h breakpoint.h value.h expression.h gdbcore.h $(INCLUDE_DIR)/bfd.h \ + gdbcmd.h command.h inferior.h target.h +coffread.o : coffread.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + breakpoint.h value.h $(INCLUDE_DIR)/bfd.h $(BFD_DIR)/libcoff.h symfile.h +command.o : command.c defs.h command.h symtab.h value.h +convex-pinsn.o : convex-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + symtab.h convex-opcode.h +convex-tdep.o : convex-tdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + command.h symtab.h value.h frame.h inferior.h breakpoint.h \ + $(INCLUDE_DIR)/wait.h gdbcore.h $(INCLUDE_DIR)/bfd.h gdbcmd.h +convex-xdep.o : convex-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + command.h symtab.h value.h frame.h inferior.h breakpoint.h \ + $(INCLUDE_DIR)/wait.h gdbcore.h $(INCLUDE_DIR)/bfd.h gdbcmd.h +core.o : core.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h inferior.h \ + breakpoint.h value.h symtab.h command.h $(INCLUDE_DIR)/bfd.h target.h \ + gdbcore.h +coredep.o : coredep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +cplus-dem.o : cplus-dem.c +dbxread.o : dbxread.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + $(INCLUDE_DIR)/a.out.gnu.h $(INCLUDE_DIR)/target.h $(INCLUDE_DIR)/reloc.h \ + $(INCLUDE_DIR)/stab.gnu.h $(INCLUDE_DIR)/stab.def symtab.h breakpoint.h value.h \ + command.h target.h gdbcore.h $(INCLUDE_DIR)/bfd.h $(BFD_DIR)/liba.out.h \ + symfile.h +environ.o : environ.c environ.h +eval.o : eval.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h value.h \ + expression.h target.h +exec.o : exec.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h inferior.h \ + breakpoint.h value.h symtab.h target.h gdbcore.h $(INCLUDE_DIR)/bfd.h +expprint.o : expprint.c defs.h symtab.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + expression.h value.h +findvar.o : findvar.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + frame.h value.h gdbcore.h $(INCLUDE_DIR)/bfd.h inferior.h breakpoint.h \ + target.h +gould-pinsn.o : gould-pinsn.c gdbcore.h $(INCLUDE_DIR)/bfd.h defs.h param.h \ + tm.h config.status param-no-tm.h xm.h config.status symtab.h frame.h np1-opcode.h +gould-xdep.o : gould-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h gdbcore.h $(INCLUDE_DIR)/bfd.h +hp300hpux-xdep.o : hp300hpux-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + frame.h inferior.h breakpoint.h value.h symtab.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +i386-pinsn.o : i386-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + frame.h inferior.h breakpoint.h value.h gdbcore.h $(INCLUDE_DIR)/bfd.h +i386-tdep.o : i386-tdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h gdbcore.h $(INCLUDE_DIR)/bfd.h +i386-xdep.o : i386-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h gdbcore.h $(INCLUDE_DIR)/bfd.h +i960-pinsn.o : i960-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h +i960-tdep.o : i960-tdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + value.h frame.h signame.h ieee-float.h +ieee-float.o : ieee-float.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + ieee-float.h +infcmd.o : infcmd.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h frame.h \ + inferior.h breakpoint.h value.h environ.h gdbcmd.h command.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h target.h +inflow.o : inflow.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h command.h signals.h terminal.h \ + target.h +infptrace.o : infptrace.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h target.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +infrun.o : infrun.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h frame.h \ + inferior.h breakpoint.h value.h $(INCLUDE_DIR)/wait.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h signame.h command.h terminal.h target.h +inftarg.o : inftarg.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h target.h $(INCLUDE_DIR)/wait.h \ + gdbcore.h $(INCLUDE_DIR)/bfd.h ieee-float.h +m68k-pinsn.o : m68k-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + m68k-opcode.h gdbcore.h $(INCLUDE_DIR)/bfd.h +m68k-tdep.o : m68k-tdep.c defs.h ieee-float.h +main.o : main.c defs.h gdbcmd.h command.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + symtab.h inferior.h breakpoint.h value.h frame.h signals.h target.h +mem-break.o : mem-break.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status +mips-pinsn.o : mips-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + mips-opcode.h +mips-tdep.o : mips-tdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h gdbcmd.h command.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +mips-xdep.o : mips-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h gdbcore.h $(INCLUDE_DIR)/bfd.h +mipsread.o : mipsread.c param.h tm.h config.status param-no-tm.h xm.h config.status obstack.h defs.h \ + symtab.h gdbcore.h $(INCLUDE_DIR)/bfd.h symfile.h $(INCLUDE_DIR)/intel-coff.h +news-xdep.o : news-xdep.c +Onindy.o : ${srcdir}/nindy-share/Onindy.c ${srcdir}/nindy-share/ttycntl.h \ + ${srcdir}/nindy-share/block_io.h $(INCLUDE_DIR)/wait.h ${srcdir}/nindy-share/env.h \ + /usr/include/string.h +nindy.o : ${srcdir}/nindy-share/nindy.c ${srcdir}/nindy-share/ttycntl.h ${srcdir}/nindy-share/block_io.h \ + $(INCLUDE_DIR)/wait.h ${srcdir}/nindy-share/env.h /usr/include/string.h +ttybreak.o : ${srcdir}/nindy-share/ttybreak.c ${srcdir}/nindy-share/ttycntl.h +ttyflush.o : ${srcdir}/nindy-share/ttyflush.c ${srcdir}/nindy-share/ttycntl.h +nindy-tdep.o : nindy-tdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + frame.h +ns32k-pinsn.o : ns32k-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + symtab.h ns32k-opcode.h gdbcore.h $(INCLUDE_DIR)/bfd.h +printcmd.o : printcmd.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + symtab.h value.h expression.h gdbcore.h $(INCLUDE_DIR)/bfd.h gdbcmd.h \ + command.h target.h +pyr-pinsn.o : pyr-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + pyr-opcode.h gdbcore.h $(INCLUDE_DIR)/bfd.h +pyr-tdep.o : pyr-tdep.c +pyr-xdep.o : pyr-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h gdbcore.h $(INCLUDE_DIR)/bfd.h +remote-eb.o : remote-eb.c defs.h tm-29k.h param-no-tm.h xm.h config.status inferior.h \ + breakpoint.h value.h symtab.h frame.h param.h $(INCLUDE_DIR)/wait.h \ + terminal.h target.h +remote-nindy.o : remote-nindy.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + frame.h inferior.h breakpoint.h value.h symtab.h target.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h command.h ieee-float.h $(INCLUDE_DIR)/wait.h \ + ${srcdir}/nindy-share/ttycntl.h ${srcdir}/nindy-share/demux.h ${srcdir}/nindy-share/env.h \ + ${srcdir}/nindy-share/stop.h +remote-vx.o : remote-vx.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h $(INCLUDE_DIR)/wait.h target.h \ + gdbcore.h $(INCLUDE_DIR)/bfd.h command.h symfile.h ${srcdir}/vx-share/xdr_ptrace.h \ + ${srcdir}/vx-share/xdr_regs.h ${srcdir}/vx-share/reg.h ${srcdir}/vx-share/xdr_ld.h \ + ${srcdir}/vx-share/xdr_rdb.h ${srcdir}/vx-share/dbgRpcLib.h +remote.o : remote.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h target.h $(INCLUDE_DIR)/wait.h \ + terminal.h +signame.o : signame.c signame.h +solib.o : solib.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h command.h +source.o : source.c defs.h symtab.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + command.h frame.h gdbcore.h $(INCLUDE_DIR)/bfd.h +sparc-pinsn.o : sparc-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + symtab.h sparc-opcode.h gdbcore.h $(INCLUDE_DIR)/bfd.h /usr/include/string.h \ + target.h +sparc-tdep.o : sparc-tdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h obstack.h signame.h target.h \ + ieee-float.h gdbcore.h $(INCLUDE_DIR)/bfd.h +sparc-xdep.o : sparc-xdep.c defs.h tm-sparc.h param-no-tm.h xm.h config.status inferior.h \ + breakpoint.h value.h symtab.h frame.h param.h target.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +stack.o : stack.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h frame.h \ + gdbcmd.h command.h value.h gdbcore.h $(INCLUDE_DIR)/bfd.h target.h \ + breakpoint.h +sun3-xdep.o : sun3-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status inferior.h \ + breakpoint.h value.h symtab.h frame.h gdbcore.h $(INCLUDE_DIR)/bfd.h +sun386-xdep.o : sun386-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + frame.h inferior.h breakpoint.h value.h symtab.h signame.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +symfile.o : symfile.c defs.h symtab.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + gdbcore.h $(INCLUDE_DIR)/bfd.h frame.h target.h value.h symfile.h gdbcmd.h \ + command.h breakpoint.h +symmetry-tdep.o : symmetry-tdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + frame.h inferior.h breakpoint.h value.h symtab.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +symmetry-xdep.o : symmetry-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + frame.h inferior.h breakpoint.h value.h symtab.h gdbcore.h \ + $(INCLUDE_DIR)/bfd.h +symmisc.o : symmisc.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + breakpoint.h value.h command.h +symtab.o : symtab.c defs.h symtab.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + gdbcore.h $(INCLUDE_DIR)/bfd.h frame.h target.h value.h symfile.h gdbcmd.h \ + command.h +target.o : target.c defs.h target.h gdbcmd.h command.h symtab.h inferior.h \ + breakpoint.h value.h frame.h param.h tm.h config.status param-no-tm.h xm.h config.status \ + $(INCLUDE_DIR)/bfd.h symfile.h +tdesc.o : tdesc.c +umax-xdep.o : umax-xdep.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status frame.h \ + inferior.h breakpoint.h value.h symtab.h gdbcore.h $(INCLUDE_DIR)/bfd.h +utils.o : utils.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status signals.h gdbcmd.h \ + command.h terminal.h $(INCLUDE_DIR)/bfd.h target.h +valarith.o : valarith.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status value.h \ + symtab.h expression.h target.h +valops.o : valops.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h value.h \ + frame.h inferior.h breakpoint.h gdbcore.h $(INCLUDE_DIR)/bfd.h target.h +valprint.o : valprint.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + value.h gdbcore.h $(INCLUDE_DIR)/bfd.h gdbcmd.h command.h target.h obstack.h +values.o : values.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h value.h \ + gdbcore.h $(INCLUDE_DIR)/bfd.h frame.h command.h +vax-pinsn.o : vax-pinsn.c defs.h param.h tm.h config.status param-no-tm.h xm.h config.status symtab.h \ + vax-opcode.h +xdr_ld.o : ${srcdir}/vx-share/xdr_ld.c ${srcdir}/vx-share/vxWorks.h ${srcdir}/vx-share/vxTypes.h \ + /usr/include/rpc/rpc.h ${srcdir}/vx-share/xdr_ld.h +xdr_ptrace.o : ${srcdir}/vx-share/xdr_ptrace.c +xdr_rdb.o : ${srcdir}/vx-share/xdr_rdb.c ${srcdir}/vx-share/vxWorks.h ${srcdir}/vx-share/vxTypes.h \ + ${srcdir}/vx-share/xdr_rdb.h +xdr_regs.o : ${srcdir}/vx-share/xdr_regs.c diff --git a/gdb/expread.tab.c b/gdb/expread.tab.c new file mode 100755 index 00000000000..86fbd0f5a3e --- /dev/null +++ b/gdb/expread.tab.c @@ -0,0 +1,2657 @@ + +/* A Bison parser, made from ../expread.y */ + +#define INT 258 +#define CHAR 259 +#define UINT 260 +#define FLOAT 261 +#define STRING 262 +#define NAME 263 +#define BLOCKNAME 264 +#define TYPENAME 265 +#define NAME_OR_INT 266 +#define NAME_OR_UINT 267 +#define STRUCT 268 +#define UNION 269 +#define ENUM 270 +#define SIZEOF 271 +#define UNSIGNED 272 +#define COLONCOLON 273 +#define ERROR 274 +#define SIGNED 275 +#define LONG 276 +#define SHORT 277 +#define INT_KEYWORD 278 +#define LAST 279 +#define REGNAME 280 +#define VARIABLE 281 +#define ASSIGN_MODIFY 282 +#define THIS 283 +#define ABOVE_COMMA 284 +#define OR 285 +#define AND 286 +#define EQUAL 287 +#define NOTEQUAL 288 +#define LEQ 289 +#define GEQ 290 +#define LSH 291 +#define RSH 292 +#define UNARY 293 +#define INCREMENT 294 +#define DECREMENT 295 +#define ARROW 296 + +#line 29 "../expread.y" + +#include +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "expression.h" +#include "value.h" +#include "command.h" + +static struct expression *expout; +static int expout_size; +static int expout_ptr; + +static int yylex (); +static void yyerror (); +static void write_exp_elt (); +static void write_exp_elt_opcode (); +static void write_exp_elt_sym (); +static void write_exp_elt_longcst (); +static void write_exp_elt_dblcst (); +static void write_exp_elt_type (); +static void write_exp_elt_intern (); +static void write_exp_string (); +static void start_arglist (); +static int end_arglist (); +static void free_funcalls (); +static char *copy_name (); +static int parse_number (); + +/* If this is nonzero, this block is used as the lexical context + for symbol names. */ + +static struct block *expression_context_block; + +/* The innermost context required by the stack and register variables + we've encountered so far. */ +struct block *innermost_block; + +/* The block in which the most recently discovered symbol was found. */ +struct block *block_found; + +/* Number of arguments seen so far in innermost function call. */ +static int arglist_len; + +/* Data structure for saving values of arglist_len + for function calls whose arguments contain other function calls. */ + +struct funcall + { + struct funcall *next; + int arglist_len; + }; + +struct funcall *funcall_chain; + +/* This kind of datum is used to represent the name + of a symbol token. */ + +struct stoken + { + char *ptr; + int length; + }; + +struct ttype + { + struct stoken stoken; + struct type *type; + }; + +struct symtoken + { + struct stoken stoken; + struct symbol *sym; + int is_a_field_of_this; + }; + +/* For parsing of complicated types. + An array should be preceded in the list by the size of the array. */ +enum type_pieces + {tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function}; +static enum type_pieces *type_stack; +static int type_stack_depth, type_stack_size; + +static void push_type (); +static enum type_pieces pop_type (); + +/* Allow debugging of parsing. */ +#define YYDEBUG 1 + +#line 125 "../expread.y" +typedef union + { + LONGEST lval; + unsigned LONGEST ulval; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + struct ttype tsym; + struct symtoken ssym; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } YYSTYPE; + +#ifndef YYLTYPE +typedef + struct yyltype + { + int timestamp; + int first_line; + int first_column; + int last_line; + int last_column; + char *text; + } + yyltype; + +#define YYLTYPE yyltype +#endif + +#include + +#ifndef __STDC__ +#define const +#endif + + + +#define YYFINAL 189 +#define YYFLAG -32768 +#define YYNTBASE 66 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 296 ? yytranslate[x] : 84) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 59, 2, 2, 2, 51, 37, 2, 58, + 62, 49, 47, 29, 48, 56, 50, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 65, 2, 40, + 31, 41, 32, 46, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 57, 2, 61, 36, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 63, 35, 64, 60, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 30, 33, 34, 38, 39, 42, 43, + 44, 45, 52, 53, 54, 55 +}; + +static const short yyrline[] = { 0, + 218, 222, 223, 228, 231, 234, 238, 242, 246, 250, + 254, 258, 262, 266, 272, 276, 282, 286, 290, 294, + 300, 303, 307, 311, 317, 323, 329, 333, 337, 341, + 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, + 385, 389, 393, 397, 401, 405, 409, 413, 419, 429, + 442, 454, 467, 474, 481, 484, 490, 496, 502, 509, + 516, 523, 540, 550, 562, 575, 621, 695, 696, 731, + 733, 735, 738, 740, 745, 751, 753, 757, 759, 763, + 767, 768, 770, 772, 775, 782, 784, 786, 788, 790, + 792, 794, 796, 798, 801, 804, 807, 809, 811, 813, + 817, 818, 824, 830, 839, 844, 851, 852, 853, 854, + 855, 858, 859, 860, 861 +}; + +static const char * const yytname[] = { 0, +"error","$illegal.","INT","CHAR","UINT","FLOAT","STRING","NAME","BLOCKNAME","TYPENAME", +"NAME_OR_INT","NAME_OR_UINT","STRUCT","UNION","ENUM","SIZEOF","UNSIGNED","COLONCOLON","ERROR","SIGNED", +"LONG","SHORT","INT_KEYWORD","LAST","REGNAME","VARIABLE","ASSIGN_MODIFY","THIS","','","ABOVE_COMMA", +"'='","'?'","OR","AND","'|'","'^'","'&'","EQUAL","NOTEQUAL","'<'", +"'>'","LEQ","GEQ","LSH","RSH","'@'","'+'","'-'","'*'","'/'", +"'%'","UNARY","INCREMENT","DECREMENT","ARROW","'.'","'['","'('","'!'","'~'", +"']'","')'","'{'","'}'","':'","start" +}; + +static const short yyr1[] = { 0, + 66, 67, 67, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 69, 68, + 70, 70, 70, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 71, 71, 72, 72, 72, 72, 73, 73, 74, + 74, 74, 75, 75, 75, 75, 75, 76, 76, 77, + 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 80, 80, 80, 80, 81, 81, 82, 82, 82, 82, + 82, 83, 83, 83, 83 +}; + +static const short yyr2[] = { 0, + 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 3, 4, 3, 4, 4, 0, 5, + 0, 1, 3, 4, 4, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 5, 3, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, + 1, 1, 3, 3, 3, 2, 1, 1, 2, 1, + 2, 1, 3, 2, 1, 2, 1, 2, 3, 2, + 1, 3, 6, 8, 9, 1, 1, 1, 1, 2, + 3, 2, 3, 2, 2, 2, 2, 1, 2, 1, + 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1 +}; + +static const short yydefact[] = { 0, + 49, 53, 51, 54, 60, 112, 113, 86, 50, 52, + 0, 0, 0, 0, 98, 0, 100, 88, 89, 87, + 56, 57, 58, 61, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 0, 55, 0, 67, 107, + 108, 109, 110, 111, 94, 95, 96, 0, 13, 101, + 103, 104, 102, 97, 66, 103, 104, 99, 90, 92, + 5, 6, 4, 9, 10, 0, 81, 0, 68, 7, + 8, 0, 68, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 12, 0, 0, + 0, 19, 0, 0, 0, 91, 93, 26, 0, 0, + 0, 70, 0, 0, 69, 72, 75, 77, 0, 0, + 3, 48, 47, 0, 45, 44, 43, 42, 41, 35, + 36, 39, 40, 37, 38, 33, 34, 27, 31, 32, + 28, 29, 30, 0, 14, 0, 16, 0, 21, 64, + 65, 59, 0, 25, 82, 71, 0, 78, 80, 0, + 0, 74, 76, 24, 0, 15, 17, 18, 22, 0, + 0, 79, 73, 46, 0, 20, 0, 23, 83, 0, + 84, 105, 0, 0, 85, 106, 0, 0, 0 +}; + +static const short yydefgoto[] = { 187, + 66, 35, 149, 170, 36, 37, 67, 115, 116, 117, + 118, 68, 38, 54, 183, 151, 39 +}; + +static const short yypact[] = { 159, +-32768,-32768,-32768,-32768,-32768,-32768, -13,-32768,-32768,-32768, + 21, 21, 21, 220, 121, 21, 124, -15, 3,-32768, +-32768,-32768,-32768,-32768, 159, 159, 159, 159, 159, 159, + 159, 159, 272, 80, 306, 32,-32768, 99,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768,-32768, 159, 508,-32768, + 100, 101,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + 508, 508, 508, 508, 508, -4,-32768, -52, 79, 508, + 508, -55, 92, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, + 159, 159, 159, 159, 159, 159,-32768,-32768, 90, 104, + 159,-32768, 21, 21, -35,-32768,-32768,-32768, 272, 159, + 110, 157, 25, 209,-32768, 30,-32768,-32768, 159, 84, + 306, 306, 306, 271, 358, 382, 405, 427, 448, 467, + 467, 144, 144, 144, 144, 480, 480, 492, 502, 502, + 508, 508, 508, 159,-32768, 159,-32768, 66, 159, 111, +-32768, 31, 122, 508,-32768,-32768, 94,-32768,-32768, 95, + 98,-32768,-32768, 508, 159, 508, 508,-32768, 306, 63, + 107,-32768,-32768, 333, 159,-32768, 116, 306, 128, 239, +-32768, 145, 64, 272,-32768, 145, 204, 205,-32768 +}; + +static const short yypgoto[] = {-32768, + 2, -14,-32768,-32768,-32768,-32768,-32768, -8,-32768, 93, + 105, -32, -26, 193,-32768, 8,-32768 +}; + + +#define YYLAST 566 + + +static const short yytable[] = { 49, + 72, 34, 109, 69, -62, 109, 73, 59, 119, 110, + 61, 62, 63, 64, 65, 105, 70, 71, 45, 46, + 47, 69, 109, 55, 74, 60, 152, 157, 40, 41, + 42, 43, 44, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 103, + 17, 18, 19, 20, 21, 22, 23, 108, 24, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 153, 28, 29, 158, 113, 161, 30, 31, + 32, 175, 184, 33, 74, 154, 111, 40, 41, 42, + 43, 44, 148, 156, 164, 160, 145, 147, 74, 120, + 150, 40, 41, 42, 43, 44, 104, 40, 41, 42, + 43, 44, 106, 107, 176, 185, 168, 112, -63, 166, + 50, 167, 155, 50, 169, 113, 114, 154, 144, 171, + 112, 51, 52, 53, 56, 57, 53, 182, 113, 114, + 174, 186, 146, 73, 172, 177, 173, 73, 155, 159, + 178, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 179, 17, 18, + 19, 20, 21, 22, 23, 180, 24, 89, 90, 91, + 92, 93, 94, 95, 96, 25, 97, 98, 99, 100, + 101, 102, 109, 188, 189, 112, 26, 27, 162, 58, + 0, 28, 29, 113, 114, 0, 30, 31, 32, 0, + 163, 33, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 0, 17, + 18, 19, 20, 21, 22, 23, 0, 24, 8, 0, + 0, 11, 12, 13, 0, 15, 25, 112, 17, 18, + 19, 20, 0, 0, 0, 113, 114, 26, 27, 0, + 159, 0, 28, 29, 0, 0, 0, 48, 31, 32, + 0, 8, 33, 0, 11, 12, 13, 0, 15, 0, + 0, 17, 18, 19, 20, 0, 0, 75, 0, 0, + 181, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 0, 97, 98, 99, 100, 101, 102, 0, + 0, 0, 75, 0, 0, 165, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 0, 97, 98, + 99, 100, 101, 102, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 0, 97, 98, 99, 100, 101, + 102, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 0, + 97, 98, 99, 100, 101, 102, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 0, 97, 98, 99, 100, 101, 102, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 0, 97, 98, 99, + 100, 101, 102, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 0, 97, + 98, 99, 100, 101, 102, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 0, + 97, 98, 99, 100, 101, 102, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 0, 97, + 98, 99, 100, 101, 102, 91, 92, 93, 94, 95, + 96, 0, 97, 98, 99, 100, 101, 102, 92, 93, + 94, 95, 96, 0, 97, 98, 99, 100, 101, 102, + 94, 95, 96, 0, 97, 98, 99, 100, 101, 102, + 97, 98, 99, 100, 101, 102 +}; + +static const short yycheck[] = { 14, + 33, 0, 58, 30, 18, 58, 33, 23, 64, 62, + 25, 26, 27, 28, 29, 48, 31, 32, 11, 12, + 13, 48, 58, 16, 29, 23, 62, 3, 8, 9, + 10, 11, 12, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, + 20, 21, 22, 23, 24, 25, 26, 62, 28, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 109, 53, 54, 61, 57, 58, 58, 59, + 60, 29, 29, 63, 29, 110, 18, 8, 9, 10, + 11, 12, 101, 112, 119, 114, 99, 100, 29, 18, + 103, 8, 9, 10, 11, 12, 18, 8, 9, 10, + 11, 12, 23, 23, 62, 62, 61, 49, 18, 144, + 10, 146, 49, 10, 149, 57, 58, 152, 49, 18, + 49, 21, 22, 23, 21, 22, 23, 180, 57, 58, + 165, 184, 49, 180, 61, 49, 62, 184, 49, 62, + 175, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 62, 20, 21, + 22, 23, 24, 25, 26, 58, 28, 44, 45, 46, + 47, 48, 49, 50, 51, 37, 53, 54, 55, 56, + 57, 58, 58, 0, 0, 49, 48, 49, 116, 17, + -1, 53, 54, 57, 58, -1, 58, 59, 60, -1, + 116, 63, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, -1, 20, + 21, 22, 23, 24, 25, 26, -1, 28, 10, -1, + -1, 13, 14, 15, -1, 17, 37, 49, 20, 21, + 22, 23, -1, -1, -1, 57, 58, 48, 49, -1, + 62, -1, 53, 54, -1, -1, -1, 58, 59, 60, + -1, 10, 63, -1, 13, 14, 15, -1, 17, -1, + -1, 20, 21, 22, 23, -1, -1, 27, -1, -1, + 62, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, -1, 53, 54, 55, 56, 57, 58, -1, + -1, -1, 27, -1, -1, 65, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, -1, 53, 54, + 55, 56, 57, 58, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, -1, 53, 54, 55, 56, 57, + 58, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, + 53, 54, 55, 56, 57, 58, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, -1, 53, 54, 55, 56, 57, 58, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, -1, 53, 54, 55, + 56, 57, 58, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, -1, 53, + 54, 55, 56, 57, 58, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, + 53, 54, 55, 56, 57, 58, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, -1, 53, + 54, 55, 56, 57, 58, 46, 47, 48, 49, 50, + 51, -1, 53, 54, 55, 56, 57, 58, 47, 48, + 49, 50, 51, -1, 53, 54, 55, 56, 57, 58, + 49, 50, 51, -1, 53, 54, 55, 56, 57, 58, + 53, 54, 55, 56, 57, 58 +}; +#define YYPURE 1 + +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984 Bob Corbett and Richard Stallman + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) +#include +#endif + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYFAIL goto yyerrlab; +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYIMPURE +#define YYLEX yylex() +#endif + +#ifndef YYPURE +#define YYLEX yylex(&yylval, &yylloc) +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYIMPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ + +int yynerrs; /* number of parse errors so far */ +#endif /* YYIMPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYMAXDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 200 +#endif + +/* YYMAXLIMIT is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#ifndef YYMAXLIMIT +#define YYMAXLIMIT 10000 +#endif + + +#line 90 "bison.simple" +int +yyparse() +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYMAXDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYMAXDEPTH]; /* the semantic value stack */ + YYLTYPE yylsa[YYMAXDEPTH]; /* the location stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + YYLTYPE *yyls = yylsa; + + int yymaxdepth = YYMAXDEPTH; + +#ifndef YYPURE + int yychar; + YYSTYPE yylval; + YYLTYPE yylloc; + int yynerrs; +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. */ + + yyssp = yyss - 1; + yyvsp = yyvs; + yylsp = yyls; + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yymaxdepth - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + YYLTYPE *yyls1 = yyls; + short *yyss1 = yyss; + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yymaxdepth); + + yyss = yyss1; yyvs = yyvs1; yyls = yyls1; +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yymaxdepth >= YYMAXLIMIT) + yyerror("parser stack overflow"); + yymaxdepth *= 2; + if (yymaxdepth > YYMAXLIMIT) + yymaxdepth = YYMAXLIMIT; + yyss = (short *) alloca (yymaxdepth * sizeof (*yyssp)); + bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yymaxdepth * sizeof (*yyvsp)); + bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yymaxdepth * sizeof (*yylsp)); + bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yymaxdepth); +#endif + + if (yyssp >= yyss + yymaxdepth - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +yyresume: + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Next token is %d (%s)\n", yychar, yytname[yychar1]); +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + if (yylen == 1) + fprintf (stderr, "Reducing 1 value via line %d, ", + yyrline[yyn]); + else + fprintf (stderr, "Reducing %d values via line %d, ", + yylen, yyrline[yyn]); + } +#endif + + + switch (yyn) { + +case 3: +#line 224 "../expread.y" +{ write_exp_elt_opcode (BINOP_COMMA); ; + break;} +case 4: +#line 229 "../expread.y" +{ write_exp_elt_opcode (UNOP_IND); ; + break;} +case 5: +#line 232 "../expread.y" +{ write_exp_elt_opcode (UNOP_ADDR); ; + break;} +case 6: +#line 235 "../expread.y" +{ write_exp_elt_opcode (UNOP_NEG); ; + break;} +case 7: +#line 239 "../expread.y" +{ write_exp_elt_opcode (UNOP_ZEROP); ; + break;} +case 8: +#line 243 "../expread.y" +{ write_exp_elt_opcode (UNOP_LOGNOT); ; + break;} +case 9: +#line 247 "../expread.y" +{ write_exp_elt_opcode (UNOP_PREINCREMENT); ; + break;} +case 10: +#line 251 "../expread.y" +{ write_exp_elt_opcode (UNOP_PREDECREMENT); ; + break;} +case 11: +#line 255 "../expread.y" +{ write_exp_elt_opcode (UNOP_POSTINCREMENT); ; + break;} +case 12: +#line 259 "../expread.y" +{ write_exp_elt_opcode (UNOP_POSTDECREMENT); ; + break;} +case 13: +#line 263 "../expread.y" +{ write_exp_elt_opcode (UNOP_SIZEOF); ; + break;} +case 14: +#line 267 "../expread.y" +{ write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_PTR); ; + break;} +case 15: +#line 273 "../expread.y" +{ write_exp_elt_opcode (STRUCTOP_MPTR); ; + break;} +case 16: +#line 277 "../expread.y" +{ write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_STRUCT); ; + break;} +case 17: +#line 283 "../expread.y" +{ write_exp_elt_opcode (STRUCTOP_MEMBER); ; + break;} +case 18: +#line 287 "../expread.y" +{ write_exp_elt_opcode (BINOP_SUBSCRIPT); ; + break;} +case 19: +#line 293 "../expread.y" +{ start_arglist (); ; + break;} +case 20: +#line 295 "../expread.y" +{ write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); ; + break;} +case 22: +#line 304 "../expread.y" +{ arglist_len = 1; ; + break;} +case 23: +#line 308 "../expread.y" +{ arglist_len++; ; + break;} +case 24: +#line 312 "../expread.y" +{ write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_MEMVAL); ; + break;} +case 25: +#line 318 "../expread.y" +{ write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_CAST); ; + break;} +case 26: +#line 324 "../expread.y" +{ ; + break;} +case 27: +#line 330 "../expread.y" +{ write_exp_elt_opcode (BINOP_REPEAT); ; + break;} +case 28: +#line 334 "../expread.y" +{ write_exp_elt_opcode (BINOP_MUL); ; + break;} +case 29: +#line 338 "../expread.y" +{ write_exp_elt_opcode (BINOP_DIV); ; + break;} +case 30: +#line 342 "../expread.y" +{ write_exp_elt_opcode (BINOP_REM); ; + break;} +case 31: +#line 346 "../expread.y" +{ write_exp_elt_opcode (BINOP_ADD); ; + break;} +case 32: +#line 350 "../expread.y" +{ write_exp_elt_opcode (BINOP_SUB); ; + break;} +case 33: +#line 354 "../expread.y" +{ write_exp_elt_opcode (BINOP_LSH); ; + break;} +case 34: +#line 358 "../expread.y" +{ write_exp_elt_opcode (BINOP_RSH); ; + break;} +case 35: +#line 362 "../expread.y" +{ write_exp_elt_opcode (BINOP_EQUAL); ; + break;} +case 36: +#line 366 "../expread.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); ; + break;} +case 37: +#line 370 "../expread.y" +{ write_exp_elt_opcode (BINOP_LEQ); ; + break;} +case 38: +#line 374 "../expread.y" +{ write_exp_elt_opcode (BINOP_GEQ); ; + break;} +case 39: +#line 378 "../expread.y" +{ write_exp_elt_opcode (BINOP_LESS); ; + break;} +case 40: +#line 382 "../expread.y" +{ write_exp_elt_opcode (BINOP_GTR); ; + break;} +case 41: +#line 386 "../expread.y" +{ write_exp_elt_opcode (BINOP_LOGAND); ; + break;} +case 42: +#line 390 "../expread.y" +{ write_exp_elt_opcode (BINOP_LOGXOR); ; + break;} +case 43: +#line 394 "../expread.y" +{ write_exp_elt_opcode (BINOP_LOGIOR); ; + break;} +case 44: +#line 398 "../expread.y" +{ write_exp_elt_opcode (BINOP_AND); ; + break;} +case 45: +#line 402 "../expread.y" +{ write_exp_elt_opcode (BINOP_OR); ; + break;} +case 46: +#line 406 "../expread.y" +{ write_exp_elt_opcode (TERNOP_COND); ; + break;} +case 47: +#line 410 "../expread.y" +{ write_exp_elt_opcode (BINOP_ASSIGN); ; + break;} +case 48: +#line 414 "../expread.y" +{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode (yyvsp[-1].opcode); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); ; + break;} +case 49: +#line 420 "../expread.y" +{ write_exp_elt_opcode (OP_LONG); + if (yyvsp[0].lval == (int) yyvsp[0].lval || yyvsp[0].lval == (unsigned int) yyvsp[0].lval) + write_exp_elt_type (builtin_type_int); + else + write_exp_elt_type (BUILTIN_TYPE_LONGEST); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 50: +#line 430 "../expread.y" +{ YYSTYPE val; + parse_number (yyvsp[0].ssym.stoken.ptr, yyvsp[0].ssym.stoken.length, 0, &val); + write_exp_elt_opcode (OP_LONG); + if (val.lval == (int) val.lval || + val.lval == (unsigned int) val.lval) + write_exp_elt_type (builtin_type_int); + else + write_exp_elt_type (BUILTIN_TYPE_LONGEST); + write_exp_elt_longcst (val.lval); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 51: +#line 443 "../expread.y" +{ + write_exp_elt_opcode (OP_LONG); + if (yyvsp[0].ulval == (unsigned int) yyvsp[0].ulval) + write_exp_elt_type (builtin_type_unsigned_int); + else + write_exp_elt_type (BUILTIN_TYPE_UNSIGNED_LONGEST); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_LONG); + ; + break;} +case 52: +#line 455 "../expread.y" +{ YYSTYPE val; + parse_number (yyvsp[0].ssym.stoken.ptr, yyvsp[0].ssym.stoken.length, 0, &val); + write_exp_elt_opcode (OP_LONG); + if (val.ulval == (unsigned int) val.ulval) + write_exp_elt_type (builtin_type_unsigned_int); + else + write_exp_elt_type (BUILTIN_TYPE_UNSIGNED_LONGEST); + write_exp_elt_longcst ((LONGEST)val.ulval); + write_exp_elt_opcode (OP_LONG); + ; + break;} +case 53: +#line 468 "../expread.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 54: +#line 475 "../expread.y" +{ write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst (yyvsp[0].dval); + write_exp_elt_opcode (OP_DOUBLE); ; + break;} +case 56: +#line 485 "../expread.y" +{ write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_LAST); ; + break;} +case 57: +#line 491 "../expread.y" +{ write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_REGISTER); ; + break;} +case 58: +#line 497 "../expread.y" +{ write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern (yyvsp[0].ivar); + write_exp_elt_opcode (OP_INTERNALVAR); ; + break;} +case 59: +#line 503 "../expread.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (yyvsp[-1].tval)); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 60: +#line 510 "../expread.y" +{ write_exp_elt_opcode (OP_STRING); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (OP_STRING); ; + break;} +case 61: +#line 517 "../expread.y" +{ write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); ; + break;} +case 62: +#line 524 "../expread.y" +{ + if (yyvsp[0].ssym.sym != 0) + yyval.bval = SYMBOL_BLOCK_VALUE (yyvsp[0].ssym.sym); + else + { + struct symtab *tem = + lookup_symtab (copy_name (yyvsp[0].ssym.stoken)); + if (tem) + yyval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), 1); + else + error ("No file or function \"%s\".", + copy_name (yyvsp[0].ssym.stoken)); + } + ; + break;} +case 63: +#line 541 "../expread.y" +{ struct symbol *tem + = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, 0, NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + yyval.bval = SYMBOL_BLOCK_VALUE (tem); ; + break;} +case 64: +#line 551 "../expread.y" +{ struct symbol *sym; + sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, 0, NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); ; + break;} +case 65: +#line 563 "../expread.y" +{ + struct type *type = yyvsp[-2].tval; + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + error ("`%s' is not defined as an aggregate type.", + TYPE_NAME (type)); + + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (OP_SCOPE); + ; + break;} +case 66: +#line 576 "../expread.y" +{ + char *name = copy_name (yyvsp[0].sval); + struct symbol *sym; + int i; + + sym = + lookup_symbol (name, 0, VAR_NAMESPACE, 0, NULL); + if (sym) + { + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + break; + } + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, name)) + break; + + if (i < misc_function_count) + { + enum misc_function_type mft = + misc_function_vector[i].type; + + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (mft == mf_data || mft == mf_bss) + write_exp_elt_type (builtin_type_int); + else if (mft == mf_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else + if (symtab_list == 0 + && partial_symtab_list == 0) + error ("No symbol table is loaded. Use the \"file\" command."); + else + error ("No symbol \"%s\" in current context.", name); + ; + break;} +case 67: +#line 622 "../expread.y" +{ struct symbol *sym = yyvsp[0].ssym.sym; + + if (sym) + { + switch (sym->class) + { + case LOC_REGISTER: + case LOC_ARG: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + if (innermost_block == 0 || + contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + else if (yyvsp[0].ssym.is_a_field_of_this) + { + /* C++: it hangs off of `this'. Must + not inadvertently convert from a method call + to data ref. */ + if (innermost_block == 0 || + contained_in (block_found, innermost_block)) + innermost_block = block_found; + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string (yyvsp[0].ssym.stoken); + write_exp_elt_opcode (STRUCTOP_PTR); + } + else + { + register int i; + register char *arg = copy_name (yyvsp[0].ssym.stoken); + + /* FIXME, this search is linear! At least + optimize the strcmp with a 1-char cmp... */ + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, arg)) + break; + + if (i < misc_function_count) + { + enum misc_function_type mft = + misc_function_vector[i].type; + + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (mft == mf_data || mft == mf_bss) + write_exp_elt_type (builtin_type_int); + else if (mft == mf_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else if (symtab_list == 0 + && partial_symtab_list == 0) + error ("No symbol table is loaded. Use the \"file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name (yyvsp[0].ssym.stoken)); + } + ; + break;} +case 69: +#line 697 "../expread.y" +{ + /* This is where the interesting stuff happens. */ + int done = 0; + int array_size; + struct type *follow_type = yyvsp[-1].tval; + + while (!done) + switch (pop_type ()) + { + case tp_end: + done = 1; + break; + case tp_pointer: + follow_type = lookup_pointer_type (follow_type); + break; + case tp_reference: + follow_type = lookup_reference_type (follow_type); + break; + case tp_array: + array_size = (int) pop_type (); + if (array_size != -1) + follow_type = create_array_type (follow_type, + array_size); + else + follow_type = lookup_pointer_type (follow_type); + break; + case tp_function: + follow_type = lookup_function_type (follow_type); + break; + } + yyval.tval = follow_type; + ; + break;} +case 70: +#line 732 "../expread.y" +{ push_type (tp_pointer); yyval.voidval = 0; ; + break;} +case 71: +#line 734 "../expread.y" +{ push_type (tp_pointer); yyval.voidval = yyvsp[0].voidval; ; + break;} +case 73: +#line 739 "../expread.y" +{ yyval.voidval = yyvsp[-1].voidval; ; + break;} +case 74: +#line 741 "../expread.y" +{ + push_type ((enum type_pieces) yyvsp[0].lval); + push_type (tp_array); + ; + break;} +case 75: +#line 746 "../expread.y" +{ + push_type ((enum type_pieces) yyvsp[0].lval); + push_type (tp_array); + yyval.voidval = 0; + ; + break;} +case 76: +#line 752 "../expread.y" +{ push_type (tp_function); ; + break;} +case 77: +#line 754 "../expread.y" +{ push_type (tp_function); ; + break;} +case 78: +#line 758 "../expread.y" +{ yyval.lval = -1; ; + break;} +case 79: +#line 760 "../expread.y" +{ yyval.lval = yyvsp[-1].lval; ; + break;} +case 80: +#line 764 "../expread.y" +{ yyval.voidval = 0; ; + break;} +case 82: +#line 769 "../expread.y" +{ yyval.tval = lookup_member_type (builtin_type_int, yyvsp[-2].tval); ; + break;} +case 83: +#line 771 "../expread.y" +{ yyval.tval = lookup_member_type (yyvsp[-5].tval, yyvsp[-3].tval); ; + break;} +case 84: +#line 773 "../expread.y" +{ yyval.tval = lookup_member_type + (lookup_function_type (yyvsp[-7].tval), yyvsp[-5].tval); ; + break;} +case 85: +#line 776 "../expread.y" +{ yyval.tval = lookup_member_type + (lookup_function_type (yyvsp[-8].tval), yyvsp[-6].tval); + free (yyvsp[-1].tvec); ; + break;} +case 86: +#line 783 "../expread.y" +{ yyval.tval = yyvsp[0].tsym.type; ; + break;} +case 87: +#line 785 "../expread.y" +{ yyval.tval = builtin_type_int; ; + break;} +case 88: +#line 787 "../expread.y" +{ yyval.tval = builtin_type_long; ; + break;} +case 89: +#line 789 "../expread.y" +{ yyval.tval = builtin_type_short; ; + break;} +case 90: +#line 791 "../expread.y" +{ yyval.tval = builtin_type_long; ; + break;} +case 91: +#line 793 "../expread.y" +{ yyval.tval = builtin_type_unsigned_long; ; + break;} +case 92: +#line 795 "../expread.y" +{ yyval.tval = builtin_type_short; ; + break;} +case 93: +#line 797 "../expread.y" +{ yyval.tval = builtin_type_unsigned_short; ; + break;} +case 94: +#line 799 "../expread.y" +{ yyval.tval = lookup_struct (copy_name (yyvsp[0].sval), + expression_context_block); ; + break;} +case 95: +#line 802 "../expread.y" +{ yyval.tval = lookup_union (copy_name (yyvsp[0].sval), + expression_context_block); ; + break;} +case 96: +#line 805 "../expread.y" +{ yyval.tval = lookup_enum (copy_name (yyvsp[0].sval), + expression_context_block); ; + break;} +case 97: +#line 808 "../expread.y" +{ yyval.tval = lookup_unsigned_typename (TYPE_NAME(yyvsp[0].tsym.type)); ; + break;} +case 98: +#line 810 "../expread.y" +{ yyval.tval = builtin_type_unsigned_int; ; + break;} +case 99: +#line 812 "../expread.y" +{ yyval.tval = yyvsp[0].tsym.type; ; + break;} +case 100: +#line 814 "../expread.y" +{ yyval.tval = builtin_type_int; ; + break;} +case 102: +#line 819 "../expread.y" +{ + yyval.tsym.stoken.ptr = "int"; + yyval.tsym.stoken.length = 3; + yyval.tsym.type = builtin_type_int; + ; + break;} +case 103: +#line 825 "../expread.y" +{ + yyval.tsym.stoken.ptr = "long"; + yyval.tsym.stoken.length = 4; + yyval.tsym.type = builtin_type_long; + ; + break;} +case 104: +#line 831 "../expread.y" +{ + yyval.tsym.stoken.ptr = "short"; + yyval.tsym.stoken.length = 5; + yyval.tsym.type = builtin_type_short; + ; + break;} +case 105: +#line 840 "../expread.y" +{ yyval.tvec = (struct type **)xmalloc (sizeof (struct type *) * 2); + yyval.tvec[0] = (struct type *)0; + yyval.tvec[1] = yyvsp[0].tval; + ; + break;} +case 106: +#line 845 "../expread.y" +{ int len = sizeof (struct type *) * ++(yyvsp[-2].ivec[0]); + yyval.tvec = (struct type **)xrealloc (yyvsp[-2].tvec, len); + yyval.tvec[yyval.ivec[0]] = yyvsp[0].tval; + ; + break;} +case 107: +#line 851 "../expread.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +case 108: +#line 852 "../expread.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +case 109: +#line 853 "../expread.y" +{ yyval.sval = yyvsp[0].tsym.stoken; ; + break;} +case 110: +#line 854 "../expread.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +case 111: +#line 855 "../expread.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 327 "bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + yyerror("parse error"); + } + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 864 "../expread.y" + + +/* Begin counting arguments for a function call, + saving the data about any containing call. */ + +static void +start_arglist () +{ + register struct funcall *new = (struct funcall *) xmalloc (sizeof (struct funcall)); + + new->next = funcall_chain; + new->arglist_len = arglist_len; + arglist_len = 0; + funcall_chain = new; +} + +/* Return the number of arguments in a function call just terminated, + and restore the data for the containing function call. */ + +static int +end_arglist () +{ + register int val = arglist_len; + register struct funcall *call = funcall_chain; + funcall_chain = call->next; + arglist_len = call->arglist_len; + free (call); + return val; +} + +/* Free everything in the funcall chain. + Used when there is an error inside parsing. */ + +static void +free_funcalls () +{ + register struct funcall *call, *next; + + for (call = funcall_chain; call; call = next) + { + next = call->next; + free (call); + } +} + +/* This page contains the functions for adding data to the struct expression + being constructed. */ + +/* Add one element to the end of the expression. */ + +/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into + a register through here */ + +static void +write_exp_elt (expelt) + union exp_element expelt; +{ + if (expout_ptr >= expout_size) + { + expout_size *= 2; + expout = (struct expression *) xrealloc (expout, + sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + } + expout->elts[expout_ptr++] = expelt; +} + +static void +write_exp_elt_opcode (expelt) + enum exp_opcode expelt; +{ + union exp_element tmp; + + tmp.opcode = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_sym (expelt) + struct symbol *expelt; +{ + union exp_element tmp; + + tmp.symbol = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_longcst (expelt) + LONGEST expelt; +{ + union exp_element tmp; + + tmp.longconst = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_dblcst (expelt) + double expelt; +{ + union exp_element tmp; + + tmp.doubleconst = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_type (expelt) + struct type *expelt; +{ + union exp_element tmp; + + tmp.type = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_intern (expelt) + struct internalvar *expelt; +{ + union exp_element tmp; + + tmp.internalvar = expelt; + + write_exp_elt (tmp); +} + +/* Add a string constant to the end of the expression. + Follow it by its length in bytes, as a separate exp_element. */ + +static void +write_exp_string (str) + struct stoken str; +{ + register int len = str.length; + register int lenelt + = (len + sizeof (union exp_element)) / sizeof (union exp_element); + + expout_ptr += lenelt; + + if (expout_ptr >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + 10); + expout = (struct expression *) + xrealloc (expout, (sizeof (struct expression) + + (expout_size * sizeof (union exp_element)))); + } + bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len); + ((char *) &expout->elts[expout_ptr - lenelt])[len] = 0; + write_exp_elt_longcst ((LONGEST) len); +} + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +static char *lexptr; + +/* Tokens that refer to names do so with explicit pointer and length, + so they can share the storage that lexptr is parsing. + + When it is necessary to pass a name to a function that expects + a null-terminated string, the substring is copied out + into a block of storage that namecopy points to. + + namecopy is allocated once, guaranteed big enough, for each parsing. */ + +static char *namecopy; + +/* Current depth in parentheses within the expression. */ + +static int paren_depth; + +/* Nonzero means stop parsing on first comma (if not within parentheses). */ + +static int comma_terminates; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (p, len, parsed_float, putithere) + register char *p; + register int len; + int parsed_float; + YYSTYPE *putithere; +{ + register LONGEST n = 0; + register int i; + register int c; + register int base = input_radix; + int unsigned_p = 0; + + extern double atof (); + + if (parsed_float) + { + /* It's a float since it contains a point or an exponent. */ + putithere->dval = atof (p); + return FLOAT; + } + + /* Handle base-switching prefixes 0x, 0t, 0d, 0 */ + if (p[0] == '0') + switch (p[1]) + { + case 'x': + case 'X': + if (len >= 3) + { + p += 2; + base = 16; + len -= 2; + } + break; + + case 't': + case 'T': + case 'd': + case 'D': + if (len >= 3) + { + p += 2; + base = 10; + len -= 2; + } + break; + + default: + base = 8; + break; + } + + while (len-- > 0) + { + c = *p++; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != 'l' && c != 'u') + n *= base; + if (c >= '0' && c <= '9') + n += i = c - '0'; + else + { + if (base > 10 && c >= 'a' && c <= 'f') + n += i = c - 'a' + 10; + else if (len == 0 && c == 'l') + ; + else if (len == 0 && c == 'u') + unsigned_p = 1; + else + return ERROR; /* Char not a digit */ + } + if (i >= base) + return ERROR; /* Invalid digit in this base */ + } + + if (unsigned_p) + { + putithere->ulval = n; + return UINT; + } + else + { + putithere->lval = n; + return INT; + } +} + +struct token +{ + char *operator; + int token; + enum exp_opcode opcode; +}; + +static struct token tokentab3[] = + { + {">>=", ASSIGN_MODIFY, BINOP_RSH}, + {"<<=", ASSIGN_MODIFY, BINOP_LSH} + }; + +static struct token tokentab2[] = + { + {"+=", ASSIGN_MODIFY, BINOP_ADD}, + {"-=", ASSIGN_MODIFY, BINOP_SUB}, + {"*=", ASSIGN_MODIFY, BINOP_MUL}, + {"/=", ASSIGN_MODIFY, BINOP_DIV}, + {"%=", ASSIGN_MODIFY, BINOP_REM}, + {"|=", ASSIGN_MODIFY, BINOP_LOGIOR}, + {"&=", ASSIGN_MODIFY, BINOP_LOGAND}, + {"^=", ASSIGN_MODIFY, BINOP_LOGXOR}, + {"++", INCREMENT, BINOP_END}, + {"--", DECREMENT, BINOP_END}, + {"->", ARROW, BINOP_END}, + {"&&", AND, BINOP_END}, + {"||", OR, BINOP_END}, + {"::", COLONCOLON, BINOP_END}, + {"<<", LSH, BINOP_END}, + {">>", RSH, BINOP_END}, + {"==", EQUAL, BINOP_END}, + {"!=", NOTEQUAL, BINOP_END}, + {"<=", LEQ, BINOP_END}, + {">=", GEQ, BINOP_END} + }; + +/* assign machine-independent names to certain registers + * (unless overridden by the REGISTER_NAMES table) + */ +struct std_regs { + char *name; + int regnum; +} std_regs[] = { +#ifdef PC_REGNUM + { "pc", PC_REGNUM }, +#endif +#ifdef FP_REGNUM + { "fp", FP_REGNUM }, +#endif +#ifdef SP_REGNUM + { "sp", SP_REGNUM }, +#endif +#ifdef PS_REGNUM + { "ps", PS_REGNUM }, +#endif +}; + +#define NUM_STD_REGS (sizeof std_regs / sizeof std_regs[0]) + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + register int c; + register int namelen; + register unsigned i; + register char *tokstart; + + retry: + + tokstart = lexptr; + /* See if it is a special token of length 3. */ + for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) + if (!strncmp (tokstart, tokentab3[i].operator, 3)) + { + lexptr += 3; + yylval.opcode = tokentab3[i].opcode; + return tokentab3[i].token; + } + + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) + if (!strncmp (tokstart, tokentab2[i].operator, 2)) + { + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + yylval.lval = c; + c = *lexptr++; + if (c != '\'') + error ("Invalid character constant."); + return CHAR; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] < '0' || lexptr[1] > '9') + goto symbol; /* Nope, must be a symbol. */ + /* FALL THRU into number case. */ + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + /* It's a number. */ + int got_dot = 0, got_e = 0, toktype; + register char *p = tokstart; + int hex = input_radix > 10; + + if (c == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + hex = 1; + } + else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) + { + p += 2; + hex = 0; + } + + for (;; ++p) + { + if (!hex && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!hex && !got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + /* We will take any letters or digits. parse_number will + complain if past the radix, or if L or U are not final. */ + else if ((*p < '0' || *p > '9') + && ((*p < 'a' || *p > 'z') + && (*p < 'A' || *p > 'Z'))) + break; + } + toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval); + if (toktype == ERROR) + { + char *err_copy = (char *) alloca (p - tokstart + 1); + + bcopy (tokstart, err_copy, p - tokstart); + err_copy[p - tokstart] = 0; + error ("Invalid number \"%s\".", err_copy); + } + lexptr = p; + return toktype; + } + + case '+': + case '-': + case '*': + case '/': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + symbol: + lexptr++; + return c; + + case '"': + for (namelen = 1; (c = tokstart[namelen]) != '"'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + return STRING; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). + Make token type LAST, and put the number (the digits) in yylval. */ + + if (*tokstart == '$') + { + register int negate = 0; + c = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (namelen >= 2 && tokstart[1] == '$') + { + negate = 1; + c = 2; + } + if (c == namelen) + { + /* Just dollars (one or two) */ + yylval.lval = - negate; + return LAST; + } + /* Is the rest of the token digits? */ + for (; c < namelen; c++) + if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) + break; + if (c == namelen) + { + yylval.lval = atoi (tokstart + 1 + negate); + if (negate) + yylval.lval = - yylval.lval; + return LAST; + } + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + + if (*tokstart == '$') { + for (c = 0; c < NUM_REGS; c++) + if (namelen - 1 == strlen (reg_names[c]) + && !strncmp (tokstart + 1, reg_names[c], namelen - 1)) + { + yylval.lval = c; + return REGNAME; + } + for (c = 0; c < NUM_STD_REGS; c++) + if (namelen - 1 == strlen (std_regs[c].name) + && !strncmp (tokstart + 1, std_regs[c].name, namelen - 1)) + { + yylval.lval = std_regs[c].regnum; + return REGNAME; + } + } + /* Catch specific keywords. Should be done with a data structure. */ + switch (namelen) + { + case 8: + if (!strncmp (tokstart, "unsigned", 8)) + return UNSIGNED; + break; + case 6: + if (!strncmp (tokstart, "struct", 6)) + return STRUCT; + if (!strncmp (tokstart, "signed", 6)) + return SIGNED; + if (!strncmp (tokstart, "sizeof", 6)) + return SIZEOF; + break; + case 5: + if (!strncmp (tokstart, "union", 5)) + return UNION; + if (!strncmp (tokstart, "short", 5)) + return SHORT; + break; + case 4: + if (!strncmp (tokstart, "enum", 4)) + return ENUM; + if (!strncmp (tokstart, "long", 4)) + return LONG; + if (!strncmp (tokstart, "this", 4)) + { + static const char this_name[] = + { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' }; + + if (lookup_symbol (this_name, expression_context_block, + VAR_NAMESPACE, 0, NULL)) + return THIS; + } + break; + case 3: + if (!strncmp (tokstart, "int", 3)) + return INT_KEYWORD; + break; + default: + break; + } + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + /* Any other names starting in $ are debugger internal variables. */ + + if (*tokstart == '$') + { + yylval.ivar = lookup_internalvar (copy_name (yylval.sval) + 1); + return VARIABLE; + } + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions or symtabs. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + char *tmp = copy_name (yylval.sval); + struct symbol *sym; + int is_a_field_of_this = 0; + int hextype; + + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, &is_a_field_of_this, NULL); + if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) || + lookup_partial_symtab (tmp)) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return BLOCKNAME; + } + if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + yylval.tsym.type = SYMBOL_TYPE (sym); + return TYPENAME; + } + if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) + return TYPENAME; + + /* Input names that aren't symbols but ARE valid hex numbers, + when the input radix permits them, can be names or numbers + depending on the parse. Note we support radixes > 16 here. */ + if (!sym && + ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) || + (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10))) + { + YYSTYPE newlval; /* Its value is ignored. */ + hextype = parse_number (tokstart, namelen, 0, &newlval); + if (hextype == INT) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME_OR_INT; + } + if (hextype == UINT) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME_OR_UINT; + } + } + + /* Any other kind of symbol */ + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME; + } +} + +static void +yyerror (msg) + char *msg; +{ + error ("Invalid syntax in expression."); +} + +/* Return a null-terminated temporary copy of the name + of a string token. */ + +static char * +copy_name (token) + struct stoken token; +{ + bcopy (token.ptr, namecopy, token.length); + namecopy[token.length] = 0; + return namecopy; +} + +/* Reverse an expression from suffix form (in which it is constructed) + to prefix form (in which we can conveniently print or execute it). */ + +static void prefixify_subexp (); + +static void +prefixify_expression (expr) + register struct expression *expr; +{ + register int len = sizeof (struct expression) + + expr->nelts * sizeof (union exp_element); + register struct expression *temp; + register int inpos = expr->nelts, outpos = 0; + + temp = (struct expression *) alloca (len); + + /* Copy the original expression into temp. */ + bcopy (expr, temp, len); + + prefixify_subexp (temp, expr, inpos, outpos); +} + +/* Return the number of exp_elements in the subexpression of EXPR + whose last exp_element is at index ENDPOS - 1 in EXPR. */ + +static int +length_of_subexp (expr, endpos) + register struct expression *expr; + register int endpos; +{ + register int oplen = 1; + register int args = 0; + register int i; + + if (endpos < 0) + error ("?error in length_of_subexp"); + + i = (int) expr->elts[endpos - 1].opcode; + + switch (i) + { + /* C++ */ + case OP_SCOPE: + oplen = 4 + ((expr->elts[endpos - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case OP_LONG: + case OP_DOUBLE: + oplen = 4; + break; + + case OP_VAR_VALUE: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + expr->elts[endpos - 2].longconst; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + case OP_STRING: + oplen = 3 + ((expr->elts[endpos - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + (i < (int) BINOP_END); + } + + while (args > 0) + { + oplen += length_of_subexp (expr, endpos - oplen); + args--; + } + + return oplen; +} + +/* Copy the subexpression ending just before index INEND in INEXPR + into OUTEXPR, starting at index OUTBEG. + In the process, convert it from suffix to prefix form. */ + +static void +prefixify_subexp (inexpr, outexpr, inend, outbeg) + register struct expression *inexpr; + struct expression *outexpr; + register int inend; + int outbeg; +{ + register int oplen = 1; + register int args = 0; + register int i; + int *arglens; + enum exp_opcode opcode; + + /* Compute how long the last operation is (in OPLEN), + and also how many preceding subexpressions serve as + arguments for it (in ARGS). */ + + opcode = inexpr->elts[inend - 1].opcode; + switch (opcode) + { + /* C++ */ + case OP_SCOPE: + oplen = 4 + ((inexpr->elts[inend - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case OP_LONG: + case OP_DOUBLE: + oplen = 4; + break; + + case OP_VAR_VALUE: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + inexpr->elts[inend - 2].longconst; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + case OP_STRING: + oplen = 3 + ((inexpr->elts[inend - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + ((int) opcode < (int) BINOP_END); + } + + /* Copy the final operator itself, from the end of the input + to the beginning of the output. */ + inend -= oplen; + bcopy (&inexpr->elts[inend], &outexpr->elts[outbeg], + oplen * sizeof (union exp_element)); + outbeg += oplen; + + /* Find the lengths of the arg subexpressions. */ + arglens = (int *) alloca (args * sizeof (int)); + for (i = args - 1; i >= 0; i--) + { + oplen = length_of_subexp (inexpr, inend); + arglens[i] = oplen; + inend -= oplen; + } + + /* Now copy each subexpression, preserving the order of + the subexpressions, but prefixifying each one. + In this loop, inend starts at the beginning of + the expression this level is working on + and marches forward over the arguments. + outbeg does similarly in the output. */ + for (i = 0; i < args; i++) + { + oplen = arglens[i]; + inend += oplen; + prefixify_subexp (inexpr, outexpr, inend, outbeg); + outbeg += oplen; + } +} + +/* This page contains the two entry points to this file. */ + +/* Read a C expression from the string *STRINGPTR points to, + parse it, and return a pointer to a struct expression that we malloc. + Use block BLOCK as the lexical context for variable names; + if BLOCK is zero, use the block of the selected stack frame. + Meanwhile, advance *STRINGPTR to point after the expression, + at the first nonwhite character that is not part of the expression + (possibly a null character). + + If COMMA is nonzero, stop if a comma is reached. */ + +struct expression * +parse_c_1 (stringptr, block, comma) + char **stringptr; + struct block *block; + int comma; +{ + struct cleanup *old_chain; + + lexptr = *stringptr; + + paren_depth = 0; + type_stack_depth = 0; + + comma_terminates = comma; + + if (lexptr == 0 || *lexptr == 0) + error_no_arg ("expression to compute"); + + old_chain = make_cleanup (free_funcalls, 0); + funcall_chain = 0; + + expression_context_block = block ? block : get_selected_block (); + + namecopy = (char *) alloca (strlen (lexptr) + 1); + expout_size = 10; + expout_ptr = 0; + expout = (struct expression *) + xmalloc (sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + make_cleanup (free_current_contents, &expout); + if (yyparse ()) + yyerror (NULL); + discard_cleanups (old_chain); + expout->nelts = expout_ptr; + expout = (struct expression *) + xrealloc (expout, + sizeof (struct expression) + + expout_ptr * sizeof (union exp_element)); + prefixify_expression (expout); + *stringptr = lexptr; + return expout; +} + +/* Parse STRING as an expression, and complain if this fails + to use up all of the contents of STRING. */ + +struct expression * +parse_c_expression (string) + char *string; +{ + register struct expression *exp; + exp = parse_c_1 (&string, 0, 0); + if (*string) + error ("Junk after end of expression."); + return exp; +} + +static void +push_type (tp) + enum type_pieces tp; +{ + if (type_stack_depth == type_stack_size) + { + type_stack_size *= 2; + type_stack = (enum type_pieces *) + xrealloc (type_stack, type_stack_size * sizeof (enum type_pieces)); + } + type_stack[type_stack_depth++] = tp; +} + +static enum type_pieces +pop_type () +{ + if (type_stack_depth) + return type_stack[--type_stack_depth]; + return tp_end; +} + +void +_initialize_expread () +{ + type_stack_size = 80; + type_stack_depth = 0; + type_stack = (enum type_pieces *) + xmalloc (type_stack_size * sizeof (enum type_pieces)); +} diff --git a/gdb/expread.y b/gdb/expread.y new file mode 100755 index 00000000000..3b19750448d --- /dev/null +++ b/gdb/expread.y @@ -0,0 +1,1902 @@ +/* Parse C expressions for GDB. + Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Parse a C expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. */ + +%{ +#include +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "expression.h" +#include "value.h" +#include "command.h" + +static struct expression *expout; +static int expout_size; +static int expout_ptr; + +static int yylex (); +static void yyerror (); +static void write_exp_elt (); +static void write_exp_elt_opcode (); +static void write_exp_elt_sym (); +static void write_exp_elt_longcst (); +static void write_exp_elt_dblcst (); +static void write_exp_elt_type (); +static void write_exp_elt_intern (); +static void write_exp_string (); +static void start_arglist (); +static int end_arglist (); +static void free_funcalls (); +static char *copy_name (); +static int parse_number (); + +/* If this is nonzero, this block is used as the lexical context + for symbol names. */ + +static struct block *expression_context_block; + +/* The innermost context required by the stack and register variables + we've encountered so far. */ +struct block *innermost_block; + +/* The block in which the most recently discovered symbol was found. */ +struct block *block_found; + +/* Number of arguments seen so far in innermost function call. */ +static int arglist_len; + +/* Data structure for saving values of arglist_len + for function calls whose arguments contain other function calls. */ + +struct funcall + { + struct funcall *next; + int arglist_len; + }; + +struct funcall *funcall_chain; + +/* This kind of datum is used to represent the name + of a symbol token. */ + +struct stoken + { + char *ptr; + int length; + }; + +struct ttype + { + struct stoken stoken; + struct type *type; + }; + +struct symtoken + { + struct stoken stoken; + struct symbol *sym; + int is_a_field_of_this; + }; + +/* For parsing of complicated types. + An array should be preceded in the list by the size of the array. */ +enum type_pieces + {tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function}; +static enum type_pieces *type_stack; +static int type_stack_depth, type_stack_size; + +static void push_type (); +static enum type_pieces pop_type (); + +/* Allow debugging of parsing. */ +#define YYDEBUG 1 +%} + +/* Although the yacc "value" of an expression is not used, + since the result is stored in the structure being created, + other node types do have values. */ + +%union + { + LONGEST lval; + unsigned LONGEST ulval; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + struct ttype tsym; + struct symtoken ssym; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } + +%type exp exp1 start variable +%type type typebase +%type nonempty_typelist +%type block + +/* Fancy type parsing. */ +%type func_mod direct_abs_decl abs_decl +%type ptype +%type array_mod + +%token INT CHAR +%token UINT +%token FLOAT + +/* Both NAME and TYPENAME tokens represent symbols in the input, + and both convey their data as strings. + But a TYPENAME is a string that happens to be defined as a typedef + or builtin type name (such as int or char) + and a NAME is any other symbol. + + Contexts where this distinction is not important can use the + nonterminal "name", which matches either NAME or TYPENAME. */ + +%token STRING +%token NAME BLOCKNAME +%token TYPENAME +%type name +%type name_not_typename +%type typename + +/* A NAME_OR_INT is a symbol which is not known in the symbol table, + but which would parse as a valid number in the current input radix. + E.g. "c" when input_radix==16. Depending on the parse, it will be + turned into a name or into a number. NAME_OR_UINT ditto. */ + +%token NAME_OR_INT NAME_OR_UINT + +%token STRUCT UNION ENUM SIZEOF UNSIGNED COLONCOLON +%token ERROR + +/* Special type cases, put in to allow the parser to distinguish different + legal basetypes. */ +%token SIGNED LONG SHORT INT_KEYWORD + +%token LAST REGNAME + +%token VARIABLE + +%token ASSIGN_MODIFY + +/* C++ */ +%token THIS + +%left ',' +%left ABOVE_COMMA +%right '=' ASSIGN_MODIFY +%right '?' +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOTEQUAL +%left '<' '>' LEQ GEQ +%left LSH RSH +%left '@' +%left '+' '-' +%left '*' '/' '%' +%right UNARY INCREMENT DECREMENT +%right ARROW '.' '[' '(' +%left COLONCOLON + +%% + +start : exp1 + ; + +/* Expressions, including the comma operator. */ +exp1 : exp + | exp1 ',' exp + { write_exp_elt_opcode (BINOP_COMMA); } + ; + +/* Expressions, not including the comma operator. */ +exp : '*' exp %prec UNARY + { write_exp_elt_opcode (UNOP_IND); } + +exp : '&' exp %prec UNARY + { write_exp_elt_opcode (UNOP_ADDR); } + +exp : '-' exp %prec UNARY + { write_exp_elt_opcode (UNOP_NEG); } + ; + +exp : '!' exp %prec UNARY + { write_exp_elt_opcode (UNOP_ZEROP); } + ; + +exp : '~' exp %prec UNARY + { write_exp_elt_opcode (UNOP_LOGNOT); } + ; + +exp : INCREMENT exp %prec UNARY + { write_exp_elt_opcode (UNOP_PREINCREMENT); } + ; + +exp : DECREMENT exp %prec UNARY + { write_exp_elt_opcode (UNOP_PREDECREMENT); } + ; + +exp : exp INCREMENT %prec UNARY + { write_exp_elt_opcode (UNOP_POSTINCREMENT); } + ; + +exp : exp DECREMENT %prec UNARY + { write_exp_elt_opcode (UNOP_POSTDECREMENT); } + ; + +exp : SIZEOF exp %prec UNARY + { write_exp_elt_opcode (UNOP_SIZEOF); } + ; + +exp : exp ARROW name + { write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_PTR); } + ; + +exp : exp ARROW '*' exp + { write_exp_elt_opcode (STRUCTOP_MPTR); } + ; + +exp : exp '.' name + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_STRUCT); } + ; + +exp : exp '.' '*' exp + { write_exp_elt_opcode (STRUCTOP_MEMBER); } + ; + +exp : exp '[' exp1 ']' + { write_exp_elt_opcode (BINOP_SUBSCRIPT); } + ; + +exp : exp '(' + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + { start_arglist (); } + arglist ')' %prec ARROW + { write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } + ; + +arglist : + ; + +arglist : exp + { arglist_len = 1; } + ; + +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +exp : '{' type '}' exp %prec UNARY + { write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_MEMVAL); } + ; + +exp : '(' type ')' exp %prec UNARY + { write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_CAST); } + ; + +exp : '(' exp1 ')' + { } + ; + +/* Binary operators in order of decreasing precedence. */ + +exp : exp '@' exp + { write_exp_elt_opcode (BINOP_REPEAT); } + ; + +exp : exp '*' exp + { write_exp_elt_opcode (BINOP_MUL); } + ; + +exp : exp '/' exp + { write_exp_elt_opcode (BINOP_DIV); } + ; + +exp : exp '%' exp + { write_exp_elt_opcode (BINOP_REM); } + ; + +exp : exp '+' exp + { write_exp_elt_opcode (BINOP_ADD); } + ; + +exp : exp '-' exp + { write_exp_elt_opcode (BINOP_SUB); } + ; + +exp : exp LSH exp + { write_exp_elt_opcode (BINOP_LSH); } + ; + +exp : exp RSH exp + { write_exp_elt_opcode (BINOP_RSH); } + ; + +exp : exp EQUAL exp + { write_exp_elt_opcode (BINOP_EQUAL); } + ; + +exp : exp NOTEQUAL exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + ; + +exp : exp LEQ exp + { write_exp_elt_opcode (BINOP_LEQ); } + ; + +exp : exp GEQ exp + { write_exp_elt_opcode (BINOP_GEQ); } + ; + +exp : exp '<' exp + { write_exp_elt_opcode (BINOP_LESS); } + ; + +exp : exp '>' exp + { write_exp_elt_opcode (BINOP_GTR); } + ; + +exp : exp '&' exp + { write_exp_elt_opcode (BINOP_LOGAND); } + ; + +exp : exp '^' exp + { write_exp_elt_opcode (BINOP_LOGXOR); } + ; + +exp : exp '|' exp + { write_exp_elt_opcode (BINOP_LOGIOR); } + ; + +exp : exp AND exp + { write_exp_elt_opcode (BINOP_AND); } + ; + +exp : exp OR exp + { write_exp_elt_opcode (BINOP_OR); } + ; + +exp : exp '?' exp ':' exp %prec '?' + { write_exp_elt_opcode (TERNOP_COND); } + ; + +exp : exp '=' exp + { write_exp_elt_opcode (BINOP_ASSIGN); } + ; + +exp : exp ASSIGN_MODIFY exp + { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode ($2); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); } + ; + +exp : INT + { write_exp_elt_opcode (OP_LONG); + if ($1 == (int) $1 || $1 == (unsigned int) $1) + write_exp_elt_type (builtin_type_int); + else + write_exp_elt_type (BUILTIN_TYPE_LONGEST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : NAME_OR_INT + { YYSTYPE val; + parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val); + write_exp_elt_opcode (OP_LONG); + if (val.lval == (int) val.lval || + val.lval == (unsigned int) val.lval) + write_exp_elt_type (builtin_type_int); + else + write_exp_elt_type (BUILTIN_TYPE_LONGEST); + write_exp_elt_longcst (val.lval); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : UINT + { + write_exp_elt_opcode (OP_LONG); + if ($1 == (unsigned int) $1) + write_exp_elt_type (builtin_type_unsigned_int); + else + write_exp_elt_type (BUILTIN_TYPE_UNSIGNED_LONGEST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); + } + ; + +exp : NAME_OR_UINT + { YYSTYPE val; + parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val); + write_exp_elt_opcode (OP_LONG); + if (val.ulval == (unsigned int) val.ulval) + write_exp_elt_type (builtin_type_unsigned_int); + else + write_exp_elt_type (BUILTIN_TYPE_UNSIGNED_LONGEST); + write_exp_elt_longcst ((LONGEST)val.ulval); + write_exp_elt_opcode (OP_LONG); + } + ; + +exp : CHAR + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : FLOAT + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst ($1); + write_exp_elt_opcode (OP_DOUBLE); } + ; + +exp : variable + ; + +exp : LAST + { write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LAST); } + ; + +exp : REGNAME + { write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_REGISTER); } + ; + +exp : VARIABLE + { write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern ($1); + write_exp_elt_opcode (OP_INTERNALVAR); } + ; + +exp : SIZEOF '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : STRING + { write_exp_elt_opcode (OP_STRING); + write_exp_string ($1); + write_exp_elt_opcode (OP_STRING); } + ; + +/* C++. */ +exp : THIS + { write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); } + ; + +/* end of C++. */ + +block : BLOCKNAME + { + if ($1.sym != 0) + $$ = SYMBOL_BLOCK_VALUE ($1.sym); + else + { + struct symtab *tem = + lookup_symtab (copy_name ($1.stoken)); + if (tem) + $$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), 1); + else + error ("No file or function \"%s\".", + copy_name ($1.stoken)); + } + } + ; + +block : block COLONCOLON name + { struct symbol *tem + = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, 0, NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name ($3)); + $$ = SYMBOL_BLOCK_VALUE (tem); } + ; + +variable: block COLONCOLON name + { struct symbol *sym; + sym = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, 0, NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name ($3)); + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } + ; + +variable: typebase COLONCOLON name + { + struct type *type = $1; + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + error ("`%s' is not defined as an aggregate type.", + TYPE_NAME (type)); + + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); + write_exp_string ($3); + write_exp_elt_opcode (OP_SCOPE); + } + | COLONCOLON name + { + char *name = copy_name ($2); + struct symbol *sym; + int i; + + sym = + lookup_symbol (name, 0, VAR_NAMESPACE, 0, NULL); + if (sym) + { + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + break; + } + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, name)) + break; + + if (i < misc_function_count) + { + enum misc_function_type mft = + misc_function_vector[i].type; + + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (mft == mf_data || mft == mf_bss) + write_exp_elt_type (builtin_type_int); + else if (mft == mf_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else + if (symtab_list == 0 + && partial_symtab_list == 0) + error ("No symbol table is loaded. Use the \"file\" command."); + else + error ("No symbol \"%s\" in current context.", name); + } + ; + +variable: name_not_typename + { struct symbol *sym = $1.sym; + + if (sym) + { + switch (sym->class) + { + case LOC_REGISTER: + case LOC_ARG: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + if (innermost_block == 0 || + contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + else if ($1.is_a_field_of_this) + { + /* C++: it hangs off of `this'. Must + not inadvertently convert from a method call + to data ref. */ + if (innermost_block == 0 || + contained_in (block_found, innermost_block)) + innermost_block = block_found; + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string ($1.stoken); + write_exp_elt_opcode (STRUCTOP_PTR); + } + else + { + register int i; + register char *arg = copy_name ($1.stoken); + + /* FIXME, this search is linear! At least + optimize the strcmp with a 1-char cmp... */ + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, arg)) + break; + + if (i < misc_function_count) + { + enum misc_function_type mft = + misc_function_vector[i].type; + + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (mft == mf_data || mft == mf_bss) + write_exp_elt_type (builtin_type_int); + else if (mft == mf_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else if (symtab_list == 0 + && partial_symtab_list == 0) + error ("No symbol table is loaded. Use the \"file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name ($1.stoken)); + } + } + ; + + +ptype : typebase + | typebase abs_decl + { + /* This is where the interesting stuff happens. */ + int done = 0; + int array_size; + struct type *follow_type = $1; + + while (!done) + switch (pop_type ()) + { + case tp_end: + done = 1; + break; + case tp_pointer: + follow_type = lookup_pointer_type (follow_type); + break; + case tp_reference: + follow_type = lookup_reference_type (follow_type); + break; + case tp_array: + array_size = (int) pop_type (); + if (array_size != -1) + follow_type = create_array_type (follow_type, + array_size); + else + follow_type = lookup_pointer_type (follow_type); + break; + case tp_function: + follow_type = lookup_function_type (follow_type); + break; + } + $$ = follow_type; + } + ; + +abs_decl: '*' + { push_type (tp_pointer); $$ = 0; } + | '*' abs_decl + { push_type (tp_pointer); $$ = $2; } + | direct_abs_decl + ; + +direct_abs_decl: '(' abs_decl ')' + { $$ = $2; } + | direct_abs_decl array_mod + { + push_type ((enum type_pieces) $2); + push_type (tp_array); + } + | array_mod + { + push_type ((enum type_pieces) $1); + push_type (tp_array); + $$ = 0; + } + | direct_abs_decl func_mod + { push_type (tp_function); } + | func_mod + { push_type (tp_function); } + ; + +array_mod: '[' ']' + { $$ = -1; } + | '[' INT ']' + { $$ = $2; } + ; + +func_mod: '(' ')' + { $$ = 0; } + ; + +type : ptype + | typebase COLONCOLON '*' + { $$ = lookup_member_type (builtin_type_int, $1); } + | type '(' typebase COLONCOLON '*' ')' + { $$ = lookup_member_type ($1, $3); } + | type '(' typebase COLONCOLON '*' ')' '(' ')' + { $$ = lookup_member_type + (lookup_function_type ($1), $3); } + | type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')' + { $$ = lookup_member_type + (lookup_function_type ($1), $3); + free ($8); } + ; + +typebase + : TYPENAME + { $$ = $1.type; } + | INT_KEYWORD + { $$ = builtin_type_int; } + | LONG + { $$ = builtin_type_long; } + | SHORT + { $$ = builtin_type_short; } + | LONG INT_KEYWORD + { $$ = builtin_type_long; } + | UNSIGNED LONG INT_KEYWORD + { $$ = builtin_type_unsigned_long; } + | SHORT INT_KEYWORD + { $$ = builtin_type_short; } + | UNSIGNED SHORT INT_KEYWORD + { $$ = builtin_type_unsigned_short; } + | STRUCT name + { $$ = lookup_struct (copy_name ($2), + expression_context_block); } + | UNION name + { $$ = lookup_union (copy_name ($2), + expression_context_block); } + | ENUM name + { $$ = lookup_enum (copy_name ($2), + expression_context_block); } + | UNSIGNED typename + { $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); } + | UNSIGNED + { $$ = builtin_type_unsigned_int; } + | SIGNED typename + { $$ = $2.type; } + | SIGNED + { $$ = builtin_type_int; } + ; + +typename: TYPENAME + | INT_KEYWORD + { + $$.stoken.ptr = "int"; + $$.stoken.length = 3; + $$.type = builtin_type_int; + } + | LONG + { + $$.stoken.ptr = "long"; + $$.stoken.length = 4; + $$.type = builtin_type_long; + } + | SHORT + { + $$.stoken.ptr = "short"; + $$.stoken.length = 5; + $$.type = builtin_type_short; + } + ; + +nonempty_typelist + : type + { $$ = (struct type **)xmalloc (sizeof (struct type *) * 2); + $$[0] = (struct type *)0; + $$[1] = $1; + } + | nonempty_typelist ',' type + { int len = sizeof (struct type *) * ++($1[0]); + $$ = (struct type **)xrealloc ($1, len); + $$[$$[0]] = $3; + } + ; + +name : NAME { $$ = $1.stoken; } + | BLOCKNAME { $$ = $1.stoken; } + | TYPENAME { $$ = $1.stoken; } + | NAME_OR_INT { $$ = $1.stoken; } + | NAME_OR_UINT { $$ = $1.stoken; } + ; + +name_not_typename : NAME + | BLOCKNAME + | NAME_OR_INT + | NAME_OR_UINT + ; + +%% + +/* Begin counting arguments for a function call, + saving the data about any containing call. */ + +static void +start_arglist () +{ + register struct funcall *new = (struct funcall *) xmalloc (sizeof (struct funcall)); + + new->next = funcall_chain; + new->arglist_len = arglist_len; + arglist_len = 0; + funcall_chain = new; +} + +/* Return the number of arguments in a function call just terminated, + and restore the data for the containing function call. */ + +static int +end_arglist () +{ + register int val = arglist_len; + register struct funcall *call = funcall_chain; + funcall_chain = call->next; + arglist_len = call->arglist_len; + free (call); + return val; +} + +/* Free everything in the funcall chain. + Used when there is an error inside parsing. */ + +static void +free_funcalls () +{ + register struct funcall *call, *next; + + for (call = funcall_chain; call; call = next) + { + next = call->next; + free (call); + } +} + +/* This page contains the functions for adding data to the struct expression + being constructed. */ + +/* Add one element to the end of the expression. */ + +/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into + a register through here */ + +static void +write_exp_elt (expelt) + union exp_element expelt; +{ + if (expout_ptr >= expout_size) + { + expout_size *= 2; + expout = (struct expression *) xrealloc (expout, + sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + } + expout->elts[expout_ptr++] = expelt; +} + +static void +write_exp_elt_opcode (expelt) + enum exp_opcode expelt; +{ + union exp_element tmp; + + tmp.opcode = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_sym (expelt) + struct symbol *expelt; +{ + union exp_element tmp; + + tmp.symbol = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_longcst (expelt) + LONGEST expelt; +{ + union exp_element tmp; + + tmp.longconst = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_dblcst (expelt) + double expelt; +{ + union exp_element tmp; + + tmp.doubleconst = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_type (expelt) + struct type *expelt; +{ + union exp_element tmp; + + tmp.type = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_intern (expelt) + struct internalvar *expelt; +{ + union exp_element tmp; + + tmp.internalvar = expelt; + + write_exp_elt (tmp); +} + +/* Add a string constant to the end of the expression. + Follow it by its length in bytes, as a separate exp_element. */ + +static void +write_exp_string (str) + struct stoken str; +{ + register int len = str.length; + register int lenelt + = (len + sizeof (union exp_element)) / sizeof (union exp_element); + + expout_ptr += lenelt; + + if (expout_ptr >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + 10); + expout = (struct expression *) + xrealloc (expout, (sizeof (struct expression) + + (expout_size * sizeof (union exp_element)))); + } + bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len); + ((char *) &expout->elts[expout_ptr - lenelt])[len] = 0; + write_exp_elt_longcst ((LONGEST) len); +} + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +static char *lexptr; + +/* Tokens that refer to names do so with explicit pointer and length, + so they can share the storage that lexptr is parsing. + + When it is necessary to pass a name to a function that expects + a null-terminated string, the substring is copied out + into a block of storage that namecopy points to. + + namecopy is allocated once, guaranteed big enough, for each parsing. */ + +static char *namecopy; + +/* Current depth in parentheses within the expression. */ + +static int paren_depth; + +/* Nonzero means stop parsing on first comma (if not within parentheses). */ + +static int comma_terminates; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (p, len, parsed_float, putithere) + register char *p; + register int len; + int parsed_float; + YYSTYPE *putithere; +{ + register LONGEST n = 0; + register int i; + register int c; + register int base = input_radix; + int unsigned_p = 0; + + extern double atof (); + + if (parsed_float) + { + /* It's a float since it contains a point or an exponent. */ + putithere->dval = atof (p); + return FLOAT; + } + + /* Handle base-switching prefixes 0x, 0t, 0d, 0 */ + if (p[0] == '0') + switch (p[1]) + { + case 'x': + case 'X': + if (len >= 3) + { + p += 2; + base = 16; + len -= 2; + } + break; + + case 't': + case 'T': + case 'd': + case 'D': + if (len >= 3) + { + p += 2; + base = 10; + len -= 2; + } + break; + + default: + base = 8; + break; + } + + while (len-- > 0) + { + c = *p++; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != 'l' && c != 'u') + n *= base; + if (c >= '0' && c <= '9') + n += i = c - '0'; + else + { + if (base > 10 && c >= 'a' && c <= 'f') + n += i = c - 'a' + 10; + else if (len == 0 && c == 'l') + ; + else if (len == 0 && c == 'u') + unsigned_p = 1; + else + return ERROR; /* Char not a digit */ + } + if (i >= base) + return ERROR; /* Invalid digit in this base */ + } + + if (unsigned_p) + { + putithere->ulval = n; + return UINT; + } + else + { + putithere->lval = n; + return INT; + } +} + +struct token +{ + char *operator; + int token; + enum exp_opcode opcode; +}; + +static struct token tokentab3[] = + { + {">>=", ASSIGN_MODIFY, BINOP_RSH}, + {"<<=", ASSIGN_MODIFY, BINOP_LSH} + }; + +static struct token tokentab2[] = + { + {"+=", ASSIGN_MODIFY, BINOP_ADD}, + {"-=", ASSIGN_MODIFY, BINOP_SUB}, + {"*=", ASSIGN_MODIFY, BINOP_MUL}, + {"/=", ASSIGN_MODIFY, BINOP_DIV}, + {"%=", ASSIGN_MODIFY, BINOP_REM}, + {"|=", ASSIGN_MODIFY, BINOP_LOGIOR}, + {"&=", ASSIGN_MODIFY, BINOP_LOGAND}, + {"^=", ASSIGN_MODIFY, BINOP_LOGXOR}, + {"++", INCREMENT, BINOP_END}, + {"--", DECREMENT, BINOP_END}, + {"->", ARROW, BINOP_END}, + {"&&", AND, BINOP_END}, + {"||", OR, BINOP_END}, + {"::", COLONCOLON, BINOP_END}, + {"<<", LSH, BINOP_END}, + {">>", RSH, BINOP_END}, + {"==", EQUAL, BINOP_END}, + {"!=", NOTEQUAL, BINOP_END}, + {"<=", LEQ, BINOP_END}, + {">=", GEQ, BINOP_END} + }; + +/* assign machine-independent names to certain registers + * (unless overridden by the REGISTER_NAMES table) + */ +struct std_regs { + char *name; + int regnum; +} std_regs[] = { +#ifdef PC_REGNUM + { "pc", PC_REGNUM }, +#endif +#ifdef FP_REGNUM + { "fp", FP_REGNUM }, +#endif +#ifdef SP_REGNUM + { "sp", SP_REGNUM }, +#endif +#ifdef PS_REGNUM + { "ps", PS_REGNUM }, +#endif +}; + +#define NUM_STD_REGS (sizeof std_regs / sizeof std_regs[0]) + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + register int c; + register int namelen; + register unsigned i; + register char *tokstart; + + retry: + + tokstart = lexptr; + /* See if it is a special token of length 3. */ + for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) + if (!strncmp (tokstart, tokentab3[i].operator, 3)) + { + lexptr += 3; + yylval.opcode = tokentab3[i].opcode; + return tokentab3[i].token; + } + + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) + if (!strncmp (tokstart, tokentab2[i].operator, 2)) + { + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + yylval.lval = c; + c = *lexptr++; + if (c != '\'') + error ("Invalid character constant."); + return CHAR; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] < '0' || lexptr[1] > '9') + goto symbol; /* Nope, must be a symbol. */ + /* FALL THRU into number case. */ + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + /* It's a number. */ + int got_dot = 0, got_e = 0, toktype; + register char *p = tokstart; + int hex = input_radix > 10; + + if (c == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + hex = 1; + } + else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) + { + p += 2; + hex = 0; + } + + for (;; ++p) + { + if (!hex && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!hex && !got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + /* We will take any letters or digits. parse_number will + complain if past the radix, or if L or U are not final. */ + else if ((*p < '0' || *p > '9') + && ((*p < 'a' || *p > 'z') + && (*p < 'A' || *p > 'Z'))) + break; + } + toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval); + if (toktype == ERROR) + { + char *err_copy = (char *) alloca (p - tokstart + 1); + + bcopy (tokstart, err_copy, p - tokstart); + err_copy[p - tokstart] = 0; + error ("Invalid number \"%s\".", err_copy); + } + lexptr = p; + return toktype; + } + + case '+': + case '-': + case '*': + case '/': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + symbol: + lexptr++; + return c; + + case '"': + for (namelen = 1; (c = tokstart[namelen]) != '"'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + return STRING; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). + Make token type LAST, and put the number (the digits) in yylval. */ + + if (*tokstart == '$') + { + register int negate = 0; + c = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (namelen >= 2 && tokstart[1] == '$') + { + negate = 1; + c = 2; + } + if (c == namelen) + { + /* Just dollars (one or two) */ + yylval.lval = - negate; + return LAST; + } + /* Is the rest of the token digits? */ + for (; c < namelen; c++) + if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) + break; + if (c == namelen) + { + yylval.lval = atoi (tokstart + 1 + negate); + if (negate) + yylval.lval = - yylval.lval; + return LAST; + } + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + + if (*tokstart == '$') { + for (c = 0; c < NUM_REGS; c++) + if (namelen - 1 == strlen (reg_names[c]) + && !strncmp (tokstart + 1, reg_names[c], namelen - 1)) + { + yylval.lval = c; + return REGNAME; + } + for (c = 0; c < NUM_STD_REGS; c++) + if (namelen - 1 == strlen (std_regs[c].name) + && !strncmp (tokstart + 1, std_regs[c].name, namelen - 1)) + { + yylval.lval = std_regs[c].regnum; + return REGNAME; + } + } + /* Catch specific keywords. Should be done with a data structure. */ + switch (namelen) + { + case 8: + if (!strncmp (tokstart, "unsigned", 8)) + return UNSIGNED; + break; + case 6: + if (!strncmp (tokstart, "struct", 6)) + return STRUCT; + if (!strncmp (tokstart, "signed", 6)) + return SIGNED; + if (!strncmp (tokstart, "sizeof", 6)) + return SIZEOF; + break; + case 5: + if (!strncmp (tokstart, "union", 5)) + return UNION; + if (!strncmp (tokstart, "short", 5)) + return SHORT; + break; + case 4: + if (!strncmp (tokstart, "enum", 4)) + return ENUM; + if (!strncmp (tokstart, "long", 4)) + return LONG; + if (!strncmp (tokstart, "this", 4)) + { + static const char this_name[] = + { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' }; + + if (lookup_symbol (this_name, expression_context_block, + VAR_NAMESPACE, 0, NULL)) + return THIS; + } + break; + case 3: + if (!strncmp (tokstart, "int", 3)) + return INT_KEYWORD; + break; + default: + break; + } + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + /* Any other names starting in $ are debugger internal variables. */ + + if (*tokstart == '$') + { + yylval.ivar = lookup_internalvar (copy_name (yylval.sval) + 1); + return VARIABLE; + } + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions or symtabs. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + char *tmp = copy_name (yylval.sval); + struct symbol *sym; + int is_a_field_of_this = 0; + int hextype; + + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, &is_a_field_of_this, NULL); + if ((sym && SYMBOL_CLASS (sym) == LOC_BLOCK) || + lookup_partial_symtab (tmp)) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return BLOCKNAME; + } + if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + yylval.tsym.type = SYMBOL_TYPE (sym); + return TYPENAME; + } + if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) + return TYPENAME; + + /* Input names that aren't symbols but ARE valid hex numbers, + when the input radix permits them, can be names or numbers + depending on the parse. Note we support radixes > 16 here. */ + if (!sym && + ((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) || + (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10))) + { + YYSTYPE newlval; /* Its value is ignored. */ + hextype = parse_number (tokstart, namelen, 0, &newlval); + if (hextype == INT) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME_OR_INT; + } + if (hextype == UINT) + { + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME_OR_UINT; + } + } + + /* Any other kind of symbol */ + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = is_a_field_of_this; + return NAME; + } +} + +static void +yyerror (msg) + char *msg; +{ + error ("Invalid syntax in expression."); +} + +/* Return a null-terminated temporary copy of the name + of a string token. */ + +static char * +copy_name (token) + struct stoken token; +{ + bcopy (token.ptr, namecopy, token.length); + namecopy[token.length] = 0; + return namecopy; +} + +/* Reverse an expression from suffix form (in which it is constructed) + to prefix form (in which we can conveniently print or execute it). */ + +static void prefixify_subexp (); + +static void +prefixify_expression (expr) + register struct expression *expr; +{ + register int len = sizeof (struct expression) + + expr->nelts * sizeof (union exp_element); + register struct expression *temp; + register int inpos = expr->nelts, outpos = 0; + + temp = (struct expression *) alloca (len); + + /* Copy the original expression into temp. */ + bcopy (expr, temp, len); + + prefixify_subexp (temp, expr, inpos, outpos); +} + +/* Return the number of exp_elements in the subexpression of EXPR + whose last exp_element is at index ENDPOS - 1 in EXPR. */ + +static int +length_of_subexp (expr, endpos) + register struct expression *expr; + register int endpos; +{ + register int oplen = 1; + register int args = 0; + register int i; + + if (endpos < 0) + error ("?error in length_of_subexp"); + + i = (int) expr->elts[endpos - 1].opcode; + + switch (i) + { + /* C++ */ + case OP_SCOPE: + oplen = 4 + ((expr->elts[endpos - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case OP_LONG: + case OP_DOUBLE: + oplen = 4; + break; + + case OP_VAR_VALUE: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + expr->elts[endpos - 2].longconst; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + case OP_STRING: + oplen = 3 + ((expr->elts[endpos - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + (i < (int) BINOP_END); + } + + while (args > 0) + { + oplen += length_of_subexp (expr, endpos - oplen); + args--; + } + + return oplen; +} + +/* Copy the subexpression ending just before index INEND in INEXPR + into OUTEXPR, starting at index OUTBEG. + In the process, convert it from suffix to prefix form. */ + +static void +prefixify_subexp (inexpr, outexpr, inend, outbeg) + register struct expression *inexpr; + struct expression *outexpr; + register int inend; + int outbeg; +{ + register int oplen = 1; + register int args = 0; + register int i; + int *arglens; + enum exp_opcode opcode; + + /* Compute how long the last operation is (in OPLEN), + and also how many preceding subexpressions serve as + arguments for it (in ARGS). */ + + opcode = inexpr->elts[inend - 1].opcode; + switch (opcode) + { + /* C++ */ + case OP_SCOPE: + oplen = 4 + ((inexpr->elts[inend - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case OP_LONG: + case OP_DOUBLE: + oplen = 4; + break; + + case OP_VAR_VALUE: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + inexpr->elts[inend - 2].longconst; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + case OP_STRING: + oplen = 3 + ((inexpr->elts[inend - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + ((int) opcode < (int) BINOP_END); + } + + /* Copy the final operator itself, from the end of the input + to the beginning of the output. */ + inend -= oplen; + bcopy (&inexpr->elts[inend], &outexpr->elts[outbeg], + oplen * sizeof (union exp_element)); + outbeg += oplen; + + /* Find the lengths of the arg subexpressions. */ + arglens = (int *) alloca (args * sizeof (int)); + for (i = args - 1; i >= 0; i--) + { + oplen = length_of_subexp (inexpr, inend); + arglens[i] = oplen; + inend -= oplen; + } + + /* Now copy each subexpression, preserving the order of + the subexpressions, but prefixifying each one. + In this loop, inend starts at the beginning of + the expression this level is working on + and marches forward over the arguments. + outbeg does similarly in the output. */ + for (i = 0; i < args; i++) + { + oplen = arglens[i]; + inend += oplen; + prefixify_subexp (inexpr, outexpr, inend, outbeg); + outbeg += oplen; + } +} + +/* This page contains the two entry points to this file. */ + +/* Read a C expression from the string *STRINGPTR points to, + parse it, and return a pointer to a struct expression that we malloc. + Use block BLOCK as the lexical context for variable names; + if BLOCK is zero, use the block of the selected stack frame. + Meanwhile, advance *STRINGPTR to point after the expression, + at the first nonwhite character that is not part of the expression + (possibly a null character). + + If COMMA is nonzero, stop if a comma is reached. */ + +struct expression * +parse_c_1 (stringptr, block, comma) + char **stringptr; + struct block *block; + int comma; +{ + struct cleanup *old_chain; + + lexptr = *stringptr; + + paren_depth = 0; + type_stack_depth = 0; + + comma_terminates = comma; + + if (lexptr == 0 || *lexptr == 0) + error_no_arg ("expression to compute"); + + old_chain = make_cleanup (free_funcalls, 0); + funcall_chain = 0; + + expression_context_block = block ? block : get_selected_block (); + + namecopy = (char *) alloca (strlen (lexptr) + 1); + expout_size = 10; + expout_ptr = 0; + expout = (struct expression *) + xmalloc (sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + make_cleanup (free_current_contents, &expout); + if (yyparse ()) + yyerror (NULL); + discard_cleanups (old_chain); + expout->nelts = expout_ptr; + expout = (struct expression *) + xrealloc (expout, + sizeof (struct expression) + + expout_ptr * sizeof (union exp_element)); + prefixify_expression (expout); + *stringptr = lexptr; + return expout; +} + +/* Parse STRING as an expression, and complain if this fails + to use up all of the contents of STRING. */ + +struct expression * +parse_c_expression (string) + char *string; +{ + register struct expression *exp; + exp = parse_c_1 (&string, 0, 0); + if (*string) + error ("Junk after end of expression."); + return exp; +} + +static void +push_type (tp) + enum type_pieces tp; +{ + if (type_stack_depth == type_stack_size) + { + type_stack_size *= 2; + type_stack = (enum type_pieces *) + xrealloc (type_stack, type_stack_size * sizeof (enum type_pieces)); + } + type_stack[type_stack_depth++] = tp; +} + +static enum type_pieces +pop_type () +{ + if (type_stack_depth) + return type_stack[--type_stack_depth]; + return tp_end; +} + +void +_initialize_expread () +{ + type_stack_size = 80; + type_stack_depth = 0; + type_stack = (enum type_pieces *) + xmalloc (type_stack_size * sizeof (enum type_pieces)); +} diff --git a/gdb/getpagesize.h b/gdb/getpagesize.h new file mode 100755 index 00000000000..32adae61efa --- /dev/null +++ b/gdb/getpagesize.h @@ -0,0 +1,25 @@ +#ifdef BSD +#ifndef BSD4_1 +#define HAVE_GETPAGESIZE +#endif +#endif + +#ifndef HAVE_GETPAGESIZE + +#include + +#ifdef EXEC_PAGESIZE +#define getpagesize() EXEC_PAGESIZE +#else +#ifdef NBPG +#define getpagesize() NBPG * CLSIZE +#ifndef CLSIZE +#define CLSIZE 1 +#endif /* no CLSIZE */ +#else /* no NBPG */ +#define getpagesize() NBPC +#endif /* no NBPG */ +#endif /* no EXEC_PAGESIZE */ + +#endif /* not HAVE_GETPAGESIZE */ + diff --git a/gdb/gmalloc.c b/gdb/gmalloc.c new file mode 100755 index 00000000000..046855170cc --- /dev/null +++ b/gdb/gmalloc.c @@ -0,0 +1,1116 @@ + +/* gmalloc.c - THIS FILE IS AUTOMAGICALLY GENERATED SO DON'T EDIT IT. */ + +/* Single-file skeleton for GNU malloc. + Copyright 1989 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#define __ONEFILE + +/* DO NOT DELETE THIS LINE -- ansidecl.h INSERTED HERE. */ +/* Copyright (C) 1989 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU C Library; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macros + PTR - Generic pointer type + LONG_DOUBLE - `long double' type + CONST - `const' keyword + VOLATILE - `volatile' keyword + SIGNED - `signed' keyword + PTRCONST - Generic const pointer (void *const) + + EXFUN(name, prototype) - declare external function NAME + with prototype PROTOTYPE + DEFUN(name, arglist, args) - define function NAME with + args ARGLIST of types in ARGS + DEFUN_VOID(name) - define function NAME with no args + AND - argument separator for ARGS + NOARGS - null arglist + DOTS - `...' in args + + For example: + extern int EXFUN(printf, (CONST char *format DOTS)); + int DEFUN(fprintf, (stream, format), + FILE *stream AND CONST char *format DOTS) { ... } + void DEFUN_VOID(abort) { ... } +*/ + +#ifndef _ANSIDECL_H + +#define _ANSIDECL_H 1 + + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + + +#ifdef __STDC__ + +#define PTR void * +#define PTRCONST void *CONST +#define LONG_DOUBLE long double + +#define AND , +#define NOARGS void +#define CONST const +#define VOLATILE volatile +#define SIGNED signed +#define DOTS , ... + +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(NOARGS) + +#else /* Not ANSI C. */ + +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#define AND ; +#define NOARGS +#define CONST +#define VOLATILE +#define SIGNED +#define DOTS + +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() + +#endif /* ANSI C. */ + + +#endif /* ansidecl.h */ + +#ifdef __STDC__ +#include +#else +/* DO NOT DELETE THIS LINE -- limits.h INSERTED HERE. */ +/* Number of bits in a `char'. */ +#define CHAR_BIT 8 + +/* No multibyte characters supported yet. */ +#define MB_LEN_MAX 1 + +/* Minimum and maximum values a `signed char' can hold. */ +#define SCHAR_MIN -128 +#define SCHAR_MAX 127 + +/* Maximum value an `unsigned char' can hold. (Minimum is 0). */ +#define UCHAR_MAX 255U + +/* Minimum and maximum values a `char' can hold. */ +#ifdef __CHAR_UNSIGNED__ +#define CHAR_MIN 0 +#define CHAR_MAX 255U +#else +#define CHAR_MIN -128 +#define CHAR_MAX 127 +#endif + +/* Minimum and maximum values a `signed short int' can hold. */ +#define SHRT_MIN -32768 +#define SHRT_MAX 32767 + +/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */ +#define USHRT_MAX 65535U + +/* Minimum and maximum values a `signed int' can hold. */ +#define INT_MIN -2147483648 +#define INT_MAX 2147483647 + +/* Maximum value an `unsigned int' can hold. (Minimum is 0). */ +#define UINT_MAX 4294967295U + +/* Minimum and maximum values a `signed long int' can hold. + (Same as `int'). */ +#define LONG_MIN (-LONG_MAX-1) +#define LONG_MAX 2147483647 + +/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */ +#define ULONG_MAX 4294967295U +#endif + +#ifdef __STDC__ +#include +#else +/* DO NOT DELETE THIS LINE -- stddef.h INSERTED HERE. */ +#ifndef _STDDEF_H +#define _STDDEF_H + +/* Signed type of difference of two pointers. */ + +typedef long ptrdiff_t; + +/* Unsigned type of `sizeof' something. */ + +#ifndef _SIZE_T /* in case has defined it. */ +#define _SIZE_T +typedef unsigned long size_t; +#endif /* _SIZE_T */ + +/* A null pointer constant. */ + +#undef NULL /* in case has defined it. */ +#define NULL 0 + +/* Offset of member MEMBER in a struct of type TYPE. */ + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif /* _STDDEF_H */ +#endif + +/* DO NOT DELETE THIS LINE -- stdlib.h INSERTED HERE. */ +/* Fake stdlib.h supplying the stuff needed by malloc. */ + +#ifndef __ONEFILE +#include +#endif + +extern void EXFUN(abort, (void)); +extern void EXFUN(free, (PTR)); +extern PTR EXFUN(malloc, (size_t)); +extern PTR EXFUN(realloc, (PTR, size_t)); + +/* DO NOT DELETE THIS LINE -- string.h INSERTED HERE. */ +/* Fake string.h supplying stuff used by malloc. */ +#ifndef __ONEFILE +#include +#endif + +extern PTR EXFUN(memcpy, (PTR, PTR, size_t)); +extern PTR EXFUN(memset, (PTR, int, size_t)); +#define memmove memcpy + +#define _MALLOC_INTERNAL +/* DO NOT DELETE THIS LINE -- malloc.h INSERTED HERE. */ +/* Declarations for `malloc' and friends. + Copyright 1990 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_H + +#define _MALLOC_H 1 + +#ifndef __ONEFILE +#define __need_NULL +#define __need_size_t +#define __need_ptrdiff_t +#include +#endif + +#ifdef _MALLOC_INTERNAL + +#ifndef __ONEFILE +#include +#endif + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Where to start searching the free list when looking for new memory. + The two possible values are 0 and _heapindex. Starting at 0 seems + to reduce total memory usage, while starting at _heapindex seems to + run faster. */ +#define MALLOC_SEARCH_START _heapindex + +/* Data structure giving per-block information. */ +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large block, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + size_t nfree; /* Free fragments in a fragmented block. */ + size_t first; /* First free fragment of the block. */ + } frag; + /* Size (in blocks) of a large cluster. */ + size_t size; + } info; + } busy; + /* Heap information for a free block (that may be the first of + a free cluster). */ + struct + { + size_t size; /* Size (in blocks) of a free cluster. */ + size_t next; /* Index of next free cluster. */ + size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern malloc_info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((PTR) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern size_t _heapindex; + +/* Limit of valid info table indices. */ +extern size_t _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list + { + struct list *next; + struct list *prev; + }; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* Instrumentation. */ +extern size_t _chunks_used; +extern size_t _bytes_used; +extern size_t _chunks_free; +extern size_t _bytes_free; + +/* Internal version of free() used in morecore(). */ +extern void EXFUN(__free, (PTR __ptr)); + +#endif /* _MALLOC_INTERNAL. */ + +/* Underlying allocation function; successive calls should + return contiguous pieces of memory. */ +extern PTR EXFUN((*__morecore), (ptrdiff_t __size)); + +/* Default value of previous. */ +extern PTR EXFUN(__default_morecore, (ptrdiff_t __size)); + +/* Flag whether malloc has been called. */ +extern int __malloc_initialized; + +/* Hooks for debugging versions. */ +extern void EXFUN((*__free_hook), (PTR __ptr)); +extern PTR EXFUN((*__malloc_hook), (size_t __size)); +extern PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size)); + +/* Activate a standard collection of debugging hooks. */ +extern void EXFUN(mcheck, (void EXFUN((*func), (void)))); + +/* Statistics available to the user. */ +struct mstats + { + size_t bytes_total; /* Total size of the heap. */ + size_t chunks_used; /* Chunks allocated by the user. */ + size_t bytes_used; /* Byte total of user-allocated chunks. */ + size_t chunks_free; /* Chunks in the free list. */ + size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Pick up the current statistics. */ +extern struct mstats EXFUN(mstats, (NOARGS)); + +#endif /* malloc.h */ + +/* DO NOT DELETE THIS LINE -- free.c INSERTED HERE. */ +/* Free a block of memory allocated by `malloc'. + Copyright 1990 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef __ONEFILE +#include "ansidecl.h" +#include +#include + +#define _MALLOC_INTERNAL +#include "malloc.h" +#endif /* __ONEFILE */ + +/* Debugging hook for free. */ +void EXFUN((*__free_hook), (PTR __ptr)); + +/* Return memory to the heap. Like free() but don't call a __free_hook + if there is one. */ +void +DEFUN(__free, (ptr), PTR ptr) +{ + int type; + size_t block, blocks; + register size_t i; + struct list *prev, *next; + + block = BLOCK(ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Get as many statistics as early as we can. */ + --_chunks_used; + _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; + _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; + + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = _heapindex; + if (i > block) + while (i > block) + i = _heapinfo[i].free.prev; + else + { + do + i = _heapinfo[i].free.next; + while (i > 0 && i < block); + i = _heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + _heapinfo[i].free.size) + { + /* Coalesce this block with its predecessor. */ + _heapinfo[i].free.size += _heapinfo[block].busy.info.size; + block = i; + } + else + { + /* Really link this block back into the free list. */ + _heapinfo[block].free.size = _heapinfo[block].busy.info.size; + _heapinfo[block].free.next = _heapinfo[i].free.next; + _heapinfo[block].free.prev = i; + _heapinfo[i].free.next = block; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + ++_chunks_free; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) + { + _heapinfo[block].free.size + += _heapinfo[_heapinfo[block].free.next].free.size; + _heapinfo[block].free.next + = _heapinfo[_heapinfo[block].free.next].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + --_chunks_free; + } + + /* Now see if we can return stuff to the system. */ + blocks = _heapinfo[block].free.size; + if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit + && (*__morecore)(0) == ADDRESS(block + blocks)) + { + register size_t bytes = blocks * BLOCKSIZE; + _heaplimit -= blocks; + (*__morecore)(- bytes); + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[block].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + block = _heapinfo[block].free.prev; + --_chunks_free; + _bytes_free -= bytes; + } + + /* Set the next search to begin at this block. */ + _heapindex = block; + break; + + default: + /* Do some of the statistics. */ + --_chunks_used; + _bytes_used -= 1 << type; + ++_chunks_free; + _bytes_free += 1 << type; + + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) ((char *) ADDRESS(block) + + (_heapinfo[block].busy.info.frag.first << type)); + + if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1) + { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + next = prev; + for (i = 1; i < BLOCKSIZE >> type; ++i) + next = next->next; + prev->prev->next = next; + if (next != NULL) + next->prev = prev->prev; + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = 1; + + /* Keep the statistics accurate. */ + ++_chunks_used; + _bytes_used += BLOCKSIZE; + _chunks_free -= BLOCKSIZE >> type; + _bytes_free -= BLOCKSIZE; + + free(ADDRESS(block)); + } + else if (_heapinfo[block].busy.info.frag.nfree != 0) + { + /* If some fragments of this block are free, link this + fragment into the fragment list after the first free + fragment of this block. */ + next = (struct list *) ptr; + next->next = prev->next; + next->prev = prev; + prev->next = next; + if (next->next != NULL) + next->next->prev = next; + ++_heapinfo[block].busy.info.frag.nfree; + } + else + { + /* No fragments of this block are free, so link this + fragment into the fragment list and announce that + it is the first free fragment of this block. */ + prev = (struct list *) ptr; + _heapinfo[block].busy.info.frag.nfree = 1; + _heapinfo[block].busy.info.frag.first = (unsigned int) + (((char *) ptr - (char *) NULL) % BLOCKSIZE >> type); + prev->next = _fraghead[type].next; + prev->prev = &_fraghead[type]; + prev->prev->next = prev; + if (prev->next != NULL) + prev->next->prev = prev; + } + break; + } +} + +/* Return memory to the heap. */ +void +DEFUN(free, (ptr), PTR ptr) +{ + if (ptr == NULL) + return; + + if (__free_hook != NULL) + (*__free_hook)(ptr); + else + __free (ptr); +} + +/* DO NOT DELETE THIS LINE -- malloc.c INSERTED HERE. */ +/* Memory allocator `malloc'. + Copyright 1990 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef __ONEFILE +#include "ansidecl.h" +#include +#include +#include + +#define _MALLOC_INTERNAL +#include "malloc.h" +#endif /* __ONEFILE */ + +/* How to really get more memory. */ +PTR EXFUN((*__morecore), (ptrdiff_t __size)) = __default_morecore; + +/* Debugging hook for `malloc'. */ +PTR EXFUN((*__malloc_hook), (size_t __size)); + +/* Pointer to the base of the first block. */ +char *_heapbase; + +/* Block information table. Allocated with align/__free (not malloc/free). */ +malloc_info *_heapinfo; + +/* Number of info entries. */ +static size_t heapsize; + +/* Search index in the info table. */ +size_t _heapindex; + +/* Limit of valid info table indices. */ +size_t _heaplimit; + +/* Free lists for each fragment size. */ +struct list _fraghead[BLOCKLOG]; + +/* Instrumentation. */ +size_t _chunks_used; +size_t _bytes_used; +size_t _chunks_free; +size_t _bytes_free; + +/* Are you experienced? */ +int __malloc_initialized; + +/* Aligned allocation. */ +static PTR +DEFUN(align, (size), size_t size) +{ + PTR result; + unsigned int adj; + + result = (*__morecore)(size); + adj = (unsigned int) ((char *) result - (char *) NULL) % BLOCKSIZE; + if (adj != 0) + { + adj = BLOCKSIZE - adj; + (void) (*__morecore)(adj); + result = (char *) result + adj; + } + return result; +} + +/* Set everything up and remember that we have. */ +static int +DEFUN_VOID(initialize) +{ + heapsize = HEAP / BLOCKSIZE; + _heapinfo = (malloc_info *) align(heapsize * sizeof(malloc_info)); + if (_heapinfo == NULL) + return 0; + memset(_heapinfo, 0, heapsize * sizeof(malloc_info)); + _heapinfo[0].free.size = 0; + _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; + _heapindex = 0; + _heapbase = (char *) _heapinfo; + __malloc_initialized = 1; + return 1; +} + +/* Get neatly aligned memory, initializing or + growing the heap info table as necessary. */ +static PTR +DEFUN(morecore, (size), size_t size) +{ + PTR result; + malloc_info *newinfo, *oldinfo; + size_t newsize; + + result = align(size); + if (result == NULL) + return NULL; + + /* Check if we need to grow the info table. */ + if (BLOCK((char *) result + size) > heapsize) + { + newsize = heapsize; + while (BLOCK((char *) result + size) > newsize) + newsize *= 2; + newinfo = (malloc_info *) align(newsize * sizeof(malloc_info)); + if (newinfo == NULL) + { + (*__morecore)(- size); + return NULL; + } + memset(newinfo, 0, newsize * sizeof(malloc_info)); + memcpy(newinfo, _heapinfo, heapsize * sizeof(malloc_info)); + oldinfo = _heapinfo; + newinfo[BLOCK(oldinfo)].busy.type = 0; + newinfo[BLOCK(oldinfo)].busy.info.size + = BLOCKIFY(heapsize * sizeof(malloc_info)); + _heapinfo = newinfo; + __free(oldinfo); + heapsize = newsize; + } + + _heaplimit = BLOCK((char *) result + size); + return result; +} + +/* Allocate memory from the heap. */ +PTR +DEFUN(malloc, (size), size_t size) +{ + PTR result; + size_t block, blocks, lastblocks, start; + register size_t i; + struct list *next; + + if (size == 0) + return NULL; + + if (__malloc_hook != NULL) + return (*__malloc_hook)(size); + + if (!__malloc_initialized) + if (!initialize()) + return NULL; + + if (size < sizeof(struct list)) + size = sizeof(struct list); + + /* Determine the allocation policy based on the request size. */ + if (size <= BLOCKSIZE / 2) + { + /* Small allocation to receive a fragment of a block. + Determine the logarithm to base two of the fragment size. */ + register size_t log = 1; + --size; + while ((size /= 2) != 0) + ++log; + + /* Look in the fragment lists for a + free fragment of the desired size. */ + next = _fraghead[log].next; + if (next != NULL) + { + /* There are free fragments of this size. + Pop a fragment out of the fragment list and return it. + Update the block's nfree and first counters. */ + result = (PTR) next; + next->prev->next = next->next; + if (next->next != NULL) + next->next->prev = next->prev; + block = BLOCK(result); + if (--_heapinfo[block].busy.info.frag.nfree != 0) + _heapinfo[block].busy.info.frag.first = (unsigned int) + (((char *) next->next - (char *) NULL) % BLOCKSIZE) >> log; + + /* Update the statistics. */ + ++_chunks_used; + _bytes_used += 1 << log; + --_chunks_free; + _bytes_free -= 1 << log; + } + else + { + /* No free fragments of the desired size, so get a new block + and break it into fragments, returning the first. */ + result = malloc(BLOCKSIZE); + if (result == NULL) + return NULL; + + /* Link all fragments but the first into the free list. */ + for (i = 1; i < BLOCKSIZE >> log; ++i) + { + next = (struct list *) ((char *) result + (i << log)); + next->next = _fraghead[log].next; + next->prev = &_fraghead[log]; + next->prev->next = next; + if (next->next != NULL) + next->next->prev = next; + } + + /* Initialize the nfree and first counters for this block. */ + block = BLOCK(result); + _heapinfo[block].busy.type = log; + _heapinfo[block].busy.info.frag.nfree = i - 1; + _heapinfo[block].busy.info.frag.first = i - 1; + + _chunks_free += (BLOCKSIZE >> log) - 1; + _bytes_free += BLOCKSIZE - (1 << log); + } + } + else + { + /* Large allocation to receive one or more blocks. + Search the free list in a circle starting at the last place visited. + If we loop completely around without finding a large enough + space we will have to get more memory from the system. */ + blocks = BLOCKIFY(size); + start = block = MALLOC_SEARCH_START; + while (_heapinfo[block].free.size < blocks) + { + block = _heapinfo[block].free.next; + if (block == start) + { + /* Need to get more from the system. Check to see if + the new core will be contiguous with the final free + block; if so we don't need to get as much. */ + block = _heapinfo[0].free.prev; + lastblocks = _heapinfo[block].free.size; + if (_heaplimit != 0 && block + lastblocks == _heaplimit && + (*__morecore)(0) == ADDRESS(block + lastblocks) && + (morecore((blocks - lastblocks) * BLOCKSIZE)) != NULL) + { + _heapinfo[block].free.size = blocks; + _bytes_free += (blocks - lastblocks) * BLOCKSIZE; + continue; + } + result = morecore(blocks * BLOCKSIZE); + if (result == NULL) + return NULL; + block = BLOCK(result); + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + ++_chunks_used; + _bytes_used += blocks * BLOCKSIZE; + return result; + } + } + + /* At this point we have found a suitable free list entry. + Figure out how to remove what we need from the list. */ + result = ADDRESS(block); + if (_heapinfo[block].free.size > blocks) + { + /* The block we found has a bit left over, + so relink the tail end back into the free list. */ + _heapinfo[block + blocks].free.size + = _heapinfo[block].free.size - blocks; + _heapinfo[block + blocks].free.next + = _heapinfo[block].free.next; + _heapinfo[block + blocks].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[_heapinfo[block].free.next].free.prev + = _heapindex = block + blocks; + } + else + { + /* The block exactly matches our requirements, + so just remove it from the list. */ + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapindex = _heapinfo[block].free.next; + --_chunks_free; + } + + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + ++_chunks_used; + _bytes_used += blocks * BLOCKSIZE; + _bytes_free -= blocks * BLOCKSIZE; + } + + return result; +} + +/* DO NOT DELETE THIS LINE -- realloc.c INSERTED HERE. */ +/* Change the size of a block allocated by `malloc'. + Copyright 1990 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef __ONEFILE +#include "ansidecl.h" +#include +#include + +#define _MALLOC_INTERNAL +#include "malloc.h" +#endif /* __ONEFILE */ + +#define MIN(A, B) ((A) < (B) ? (A) : (B)) + +/* Debugging hook for realloc. */ +PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size)); + +/* Resize the given region to the new size, returning a pointer + to the (possibly moved) region. This is optimized for speed; + some benchmarks seem to indicate that greater compactness is + achieved by unconditionally allocating and copying to a + new region. This module has incestuous knowledge of the + internals of both free and malloc. */ +PTR +DEFUN(realloc, (ptr, size), PTR ptr AND size_t size) +{ + PTR result; + int type; + size_t block, blocks, oldlimit; + + if (size == 0) + { + free(ptr); + return NULL; + } + else if (ptr == NULL) + return malloc(size); + + if (__realloc_hook != NULL) + return (*__realloc_hook)(ptr, size); + + block = BLOCK(ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Maybe reallocate a large block to a small fragment. */ + if (size <= BLOCKSIZE / 2) + { + result = malloc(size); + if (result != NULL) + { + memcpy(result, ptr, size); + free(ptr); + return result; + } + } + + /* The new size is a large allocation as well; + see if we can hold it in place. */ + blocks = BLOCKIFY(size); + if (blocks < _heapinfo[block].busy.info.size) + { + /* The new size is smaller; return + excess memory to the free list. */ + _heapinfo[block + blocks].busy.type = 0; + _heapinfo[block + blocks].busy.info.size + = _heapinfo[block].busy.info.size - blocks; + _heapinfo[block].busy.info.size = blocks; + free(ADDRESS(block + blocks)); + result = ptr; + } + else if (blocks == _heapinfo[block].busy.info.size) + /* No size change necessary. */ + result = ptr; + else + { + /* Won't fit, so allocate a new region that will. + Free the old region first in case there is sufficient + adjacent free space to grow without moving. */ + blocks = _heapinfo[block].busy.info.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = _heaplimit; + _heaplimit = 0; + free(ptr); + _heaplimit = oldlimit; + result = malloc(size); + if (result == NULL) + { + (void) malloc(blocks * BLOCKSIZE); + return NULL; + } + if (ptr != result) + memmove(result, ptr, blocks * BLOCKSIZE); + } + break; + + default: + /* Old size is a fragment; type is logarithm + to base two of the fragment size. */ + if (size > 1 << (type - 1) && size <= 1 << type) + /* The new size is the same kind of fragment. */ + result = ptr; + else + { + /* The new size is different; allocate a new space, + and copy the lesser of the new size and the old. */ + result = malloc(size); + if (result == NULL) + return NULL; + memcpy(result, ptr, MIN(size, 1 << type)); + free(ptr); + } + break; + } + + return result; +} + +/* DO NOT DELETE THIS LINE -- unix.c INSERTED HERE. */ +/* unix.c - get more memory with a UNIX system call. + Copyright 1990 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef __ONEFILE +#include "ansidecl.h" +#include + +#define _MALLOC_INTERNAL +#include "malloc.h" +#endif /* __ONEFILE */ + +extern PTR EXFUN(sbrk, (ptrdiff_t size)); + +PTR +DEFUN(__default_morecore, (size), ptrdiff_t size) +{ + PTR result; + + result = sbrk(size); + if (result == (PTR) -1) + return NULL; + return result; +} + +#define __getpagesize getpagesize +/* DO NOT DELETE THIS LINE -- valloc.c INSERTED HERE. */ +/* Allocate memory on a page boundary. + Copyright 1990 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef __ONEFILE +#include "ansidecl.h" +#include +#endif /* __ONEFILE */ + +extern size_t EXFUN(__getpagesize, (NOARGS)); + +static size_t pagesize; + +PTR +DEFUN(valloc, (size), size_t size) +{ + PTR result; + unsigned int adj; + + if (pagesize == 0) + pagesize = __getpagesize(); + + result = malloc(size + pagesize); + if (result == NULL) + return NULL; + adj = (unsigned int) ((char *) result - (char *) NULL) % pagesize; + if (adj != 0) + result = (char *) result + pagesize - adj; + return result; +} diff --git a/gdb/gmalloc.h b/gdb/gmalloc.h new file mode 100755 index 00000000000..8718e80d1af --- /dev/null +++ b/gdb/gmalloc.h @@ -0,0 +1,161 @@ +/* Declarations for `malloc' and friends. + Copyright 1990 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_H + +#define _MALLOC_H 1 + +#ifndef __ONEFILE +#define __need_NULL +#define __need_size_t +#define __need_ptrdiff_t +#include +#endif + +#ifdef _MALLOC_INTERNAL + +#ifndef __ONEFILE +#include +#endif + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Where to start searching the free list when looking for new memory. + The two possible values are 0 and _heapindex. Starting at 0 seems + to reduce total memory usage, while starting at _heapindex seems to + run faster. */ +#define MALLOC_SEARCH_START _heapindex + +/* Data structure giving per-block information. */ +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large block, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + size_t nfree; /* Free fragments in a fragmented block. */ + size_t first; /* First free fragment of the block. */ + } frag; + /* Size (in blocks) of a large cluster. */ + size_t size; + } info; + } busy; + /* Heap information for a free block (that may be the first of + a free cluster). */ + struct + { + size_t size; /* Size (in blocks) of a free cluster. */ + size_t next; /* Index of next free cluster. */ + size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern malloc_info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((PTR) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern size_t _heapindex; + +/* Limit of valid info table indices. */ +extern size_t _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list + { + struct list *next; + struct list *prev; + }; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* Instrumentation. */ +extern size_t _chunks_used; +extern size_t _bytes_used; +extern size_t _chunks_free; +extern size_t _bytes_free; + +/* Internal version of free() used in morecore(). */ +extern void EXFUN(__free, (PTR __ptr)); + +#endif /* _MALLOC_INTERNAL. */ + +/* Underlying allocation function; successive calls should + return contiguous pieces of memory. */ +extern PTR EXFUN((*__morecore), (ptrdiff_t __size)); + +/* Default value of previous. */ +extern PTR EXFUN(__default_morecore, (ptrdiff_t __size)); + +/* Flag whether malloc has been called. */ +extern int __malloc_initialized; + +/* Hooks for debugging versions. */ +extern void EXFUN((*__free_hook), (PTR __ptr)); +extern PTR EXFUN((*__malloc_hook), (size_t __size)); +extern PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size)); + +/* Activate a standard collection of debugging hooks. */ +extern void EXFUN(mcheck, (void EXFUN((*func), (void)))); + +/* Statistics available to the user. */ +struct mstats + { + size_t bytes_total; /* Total size of the heap. */ + size_t chunks_used; /* Chunks allocated by the user. */ + size_t bytes_used; /* Byte total of user-allocated chunks. */ + size_t chunks_free; /* Chunks in the free list. */ + size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Pick up the current statistics. */ +extern struct mstats EXFUN(mstats, (NOARGS)); + +#endif /* malloc.h */ diff --git a/gdb/gould-pinsn.c b/gdb/gould-pinsn.c new file mode 100644 index 00000000000..b655f26dc9c --- /dev/null +++ b/gdb/gould-pinsn.c @@ -0,0 +1,294 @@ +/* Print GOULD RISC instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "gdbcore.h" + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#if defined GOULD_PN +#include "pn-opcode.h" +#else +#include "np1-opcode.h" +#endif + +/* GOULD RISC instructions are never longer than this many bytes. */ +#define MAXLEN 4 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof gld_opcodes / sizeof gld_opcodes[0]) + + +/* Print the GOULD 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 char *d; + register int bestmask; + unsigned best; + int temp, index, bestlen; + + read_memory (memaddr, buffer, MAXLEN); + + bestmask = 0; + index = -1; + best = 0xffffffff; + for (i = 0; i < NOPCODES; i++) + { + register unsigned int opcode = gld_opcodes[i].opcode; + register unsigned int mask = gld_opcodes[i].mask; + register unsigned int len = gld_opcodes[i].length; + register unsigned int test; + + /* Get possible opcode bytes into integer */ + test = buffer[0] << 24; + test |= buffer[1] << 16; + test |= buffer[2] << 8; + test |= buffer[3]; + + /* Mask with opcode and see if match */ + if ((opcode & mask) == (test & mask)) + { + /* See if second or third match */ + if (index >= 0) + { + /* Take new one if it looks good */ + if (bestlen == MAXLEN && len == MAXLEN) + { + /* See if lower bits matched */ + if (((bestmask & 3) == 0) && + ((mask & 3) != 0)) + { + bestmask = mask; + bestlen = len; + best = test; + index = i; + } + } + } + else + { + /* First match, save it */ + bestmask = mask; + bestlen = len; + best = test; + index = i; + } + } + } + + /* Handle undefined instructions. */ + if (index < 0) + { + fprintf (stream, "undefined 0%o",(buffer[0]<<8)+buffer[1]); + return 2; + } + + /* Print instruction name */ + fprintf (stream, "%-12s", gld_opcodes[index].name); + + /* Adjust if short instruction */ + if (gld_opcodes[index].length < 4) + { + best >>= 16; + i = 0; + } + else + { + i = 16; + } + + /* Dump out instruction arguments */ + for (d = gld_opcodes[index].args; *d; ++d) + { + switch (*d) + { + case 'f': + fprintf (stream, "%d", (best >> (7 + i)) & 7); + break; + case 'r': + fprintf (stream, "r%d", (best >> (7 + i)) & 7); + break; + case 'R': + fprintf (stream, "r%d", (best >> (4 + i)) & 7); + break; + case 'b': + fprintf (stream, "b%d", (best >> (7 + i)) & 7); + break; + case 'B': + fprintf (stream, "b%d", (best >> (4 + i)) & 7); + break; + case 'v': + fprintf (stream, "b%d", (best >> (7 + i)) & 7); + break; + case 'V': + fprintf (stream, "b%d", (best >> (4 + i)) & 7); + break; + case 'X': + temp = (best >> 20) & 7; + if (temp) + fprintf (stream, "r%d", temp); + else + putc ('0', stream); + break; + case 'A': + temp = (best >> 16) & 7; + if (temp) + fprintf (stream, "(b%d)", temp); + break; + case 'S': + fprintf (stream, "#%d", best & 0x1f); + break; + case 'I': + fprintf (stream, "#%x", best & 0xffff); + break; + case 'O': + fprintf (stream, "%x", best & 0xffff); + break; + case 'h': + fprintf (stream, "%d", best & 0xfffe); + break; + case 'd': + fprintf (stream, "%d", best & 0xfffc); + break; + case 'T': + fprintf (stream, "%d", (best >> 8) & 0xff); + break; + case 'N': + fprintf (stream, "%d", best & 0xff); + break; + default: + putc (*d, stream); + break; + } + } + + /* Return length of instruction */ + return (gld_opcodes[index].length); +} + +/* + * Find the number of arguments to a function. + */ +findarg(frame) + struct frame_info *frame; +{ + register struct symbol *func; + register unsigned pc; + +#ifdef notdef + /* find starting address of frame function */ + pc = get_pc_function_start (frame->pc); + + /* find function symbol info */ + func = find_pc_function (pc); + + /* call blockframe code to look for match */ + if (func != NULL) + return (func->value.block->nsyms / sizeof(int)); +#endif + + return (-1); +} + +/* + * In the case of the NPL, the frame's norminal address is Br2 and the + * previous routines frame is up the stack X bytes. Finding out what + * 'X' is can be tricky. + * + * 1.) stored in the code function header xA(Br1). + * 2.) must be careful of recurssion. + */ +FRAME_ADDR +findframe(thisframe) + FRAME thisframe; +{ + register FRAME_ADDR pointer; + FRAME_ADDR framechain(); +#if 0 + struct frame_info *frame; + + /* Setup toplevel frame structure */ + frame->pc = read_pc(); + frame->next_frame = 0; + frame->frame = read_register (SP_REGNUM); /* Br2 */ + + /* Search for this frame (start at current Br2) */ + do + { + pointer = framechain(frame); + frame->next_frame = frame->frame; + frame->frame = pointer; + frame->pc = FRAME_SAVED_PC(frame); + } + while (frame->next_frame != thisframe); +#endif + + pointer = framechain (thisframe); + + /* stop gap for now, end at __base3 */ + if (thisframe->pc == 0) + return 0; + + return pointer; +} + +/* + * Gdb front-end and internal framechain routine. + * Go back up stack one level. Tricky... + */ +FRAME_ADDR +framechain(frame) + register struct frame_info *frame; +{ + register CORE_ADDR func, prevsp; + register unsigned value; + + /* Get real function start address from internal frame address */ + func = get_pc_function_start(frame->pc); + + /* If no stack given, read register Br1 "(sp)" */ + if (!frame->frame) + prevsp = read_register (SP_REGNUM); + else + prevsp = frame->frame; + + /* Check function header, case #2 */ + value = read_memory_integer (func, 4); + if (value) + { + /* 32bit call push value stored in function header */ + prevsp += value; + } + else + { + /* read half-word from suabr at start of function */ + prevsp += read_memory_integer (func + 10, 2); + } + + return (prevsp); +} diff --git a/gdb/gould-xdep.c b/gdb/gould-xdep.c new file mode 100644 index 00000000000..c3aec0d9c67 --- /dev/null +++ b/gdb/gould-xdep.c @@ -0,0 +1,132 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include + +#include "gdbcore.h" + +#include +#include + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +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) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name (filename); + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; + + /* I don't know where to find this info. + So, for now, mark it as not available. */ + core_aouthdr.a_magic = 0; + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0) + perror_with_name (filename); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} diff --git a/gdb/hp300hpux-xdep.c b/gdb/hp300hpux-xdep.c new file mode 100755 index 00000000000..f7f1cf08102 --- /dev/null +++ b/gdb/hp300hpux-xdep.c @@ -0,0 +1,230 @@ +/* HP/UX interface for HP 300's, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +/* Defining this means some system include files define some extra stuff. */ +#define WOPR +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gdbcore.h" + +#include +#include + +#define INFERIOR_AR0(u) \ + ((ptrace \ + (PT_RUAREA, inferior_pid, ((char *) &u.u_ar0 - (char *) &u), 0)) \ + - KERNEL_U_ADDR) + +static void +fetch_inferior_register (regno, regaddr) + register int regno; + register unsigned int regaddr; +{ +#ifndef HPUX_VERSION_5 + if (regno == PS_REGNUM) + { + union { int i; short s[2]; } ps_val; + int regval; + + ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0)); + regval = ps_val.s[0]; + supply_register (regno, ®val); + } + else +#endif /* not HPUX_VERSION_5 */ + { + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (PT_RUAREA, inferior_pid, regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } + return; +} + +static void +store_inferior_register_1 (regno, regaddr, value) + int regno; + unsigned int regaddr; + int value; +{ + errno = 0; + ptrace (PT_WUAREA, inferior_pid, regaddr, value); +#if 0 + /* HP-UX randomly sets errno to non-zero for regno == 25. + However, the value is correctly written, so ignore errno. */ + if (errno != 0) + { + char string_buf[64]; + + sprintf (string_buf, "writing register number %d", regno); + perror_with_name (string_buf); + } +#endif + return; +} + +static void +store_inferior_register (regno, regaddr) + register int regno; + register unsigned int regaddr; +{ +#ifndef HPUX_VERSION_5 + if (regno == PS_REGNUM) + { + union { int i; short s[2]; } ps_val; + + ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0)); + ps_val.s[0] = (read_register (regno)); + store_inferior_register_1 (regno, regaddr, ps_val.i); + } + else +#endif /* not HPUX_VERSION_5 */ + { + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + extern char registers[]; + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + store_inferior_register_1 + (regno, regaddr, + (*(int *) ®isters[(REGISTER_BYTE (regno)) + i])); + regaddr += sizeof (int); + } + } + return; +} + +void +fetch_inferior_registers (regno) + int regno; +{ + struct user u; + register int regno; + register unsigned int ar0_offset; + + ar0_offset = (INFERIOR_AR0 (u)); + if (regno == -1) + { + for (regno = 0; (regno < FP0_REGNUM); regno++) + fetch_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + for (; (regno < NUM_REGS); regno++) + fetch_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); + } + else + fetch_inferior_register (regno, + (regno < FP0_REGNUM + ? REGISTER_ADDR (ar0_offset, regno) + : FP_REGISTER_ADDR (u, regno))); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + register int regno; +{ + struct user u; + register unsigned int ar0_offset; + extern char registers[]; + + if (regno >= FP0_REGNUM) + { + store_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); + return; + } + + ar0_offset = (INFERIOR_AR0 (u)); + if (regno >= 0) + { + store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + return; + } + + for (regno = 0; (regno < FP0_REGNUM); regno++) + store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno))); + for (; (regno < NUM_REGS); regno++) + store_inferior_register (regno, (FP_REGISTER_ADDR (u, regno))); + return; +} + + +/* Take the register values out of a core file and store + them where `read_register' will find them. */ + +#ifdef HPUX_VERSION_5 +#define e_PS e_regs[PS] +#define e_PC e_regs[PC] +#endif /* HPUX_VERSION_5 */ + +void +fetch_core_registers (core_reg_sect, core_reg_size, which) + char *core_reg_sect; + int core_reg_size; + int which; +{ + int val, regno; + struct user u; + struct exception_stack *pes = (struct exception_stack *) core_reg_sect; +#define es (*pes) + char *buf; + + if (which == 0) { + if (core_reg_size < + ((char *) &es.e_offset - (char *) &es.e_regs[R0])) + error ("Not enough registers in core file"); + for (regno = 0; (regno < PS_REGNUM); regno++) + supply_register (regno, &es.e_regs[regno + R0]); + val = es.e_PS; + supply_register (regno++, &val); + supply_register (regno++, &es.e_PC); + + } else if (which == 2) { + + /* FIXME: This may not work if the float regs and control regs are + discontinuous. */ + for (regno = FP0_REGNUM, buf = core_reg_sect; + (regno < NUM_REGS); + buf += REGISTER_RAW_SIZE (regno), regno++) + { + supply_register (regno, buf); + } + } +} diff --git a/gdb/i386-pinsn.c b/gdb/i386-pinsn.c new file mode 100644 index 00000000000..50cf14bd937 --- /dev/null +++ b/gdb/i386-pinsn.c @@ -0,0 +1,1834 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#include +#include + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 +#define Mp OP_E, 0 /* ? */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rw OP_rm, w_mode +#define Rd OP_rm, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#define ONE OP_ONE, 0 +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, lptr +#define Av OP_DIR, v_mode +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSSI, b_mode +#define Xv OP_DSSI, v_mode +#define Yb OP_ESDI, b_mode +#define Yv OP_ESDI, v_mode + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG(); +int OP_J(), OP_SEG(); +int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C(); +int OP_D(), OP_T(), OP_rm(); + + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 +#define eAX_reg 107 +#define eCX_reg 108 +#define eDX_reg 109 +#define eBX_reg 110 +#define eSP_reg 111 +#define eBP_reg 112 +#define eSI_reg 113 +#define eDI_reg 114 + +#define lptr 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define GRP1b NULL, NULL, 0 +#define GRP1S NULL, NULL, 1 +#define GRP1Ss NULL, NULL, 2 +#define GRP2b NULL, NULL, 3 +#define GRP2S NULL, NULL, 4 +#define GRP2b_one NULL, NULL, 5 +#define GRP2S_one NULL, NULL, 6 +#define GRP2b_cl NULL, NULL, 7 +#define GRP2S_cl NULL, NULL, 8 +#define GRP3b NULL, NULL, 9 +#define GRP3S NULL, NULL, 10 +#define GRP4 NULL, NULL, 11 +#define GRP5 NULL, NULL, 12 +#define GRP6 NULL, NULL, 13 +#define GRP7 NULL, NULL, 14 +#define GRP8 NULL, NULL, 15 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE + +struct dis386 { + char *name; + int (*op1)(); + int bytemode1; + int (*op2)(); + int bytemode2; + int (*op3)(); + int bytemode3; +}; + +struct dis386 dis386[] = { + /* 00 */ + { "addb", Eb, Gb }, + { "addS", Ev, Gv }, + { "addb", Gb, Eb }, + { "addS", Gv, Ev }, + { "addb", AL, Ib }, + { "addS", eAX, Iv }, + { "pushl", es }, + { "popl", es }, + /* 08 */ + { "orb", Eb, Gb }, + { "orS", Ev, Gv }, + { "orb", Gb, Eb }, + { "orS", Gv, Ev }, + { "orb", AL, Ib }, + { "orS", eAX, Iv }, + { "pushl", cs }, + { "(bad)" }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcb", Eb, Gb }, + { "adcS", Ev, Gv }, + { "adcb", Gb, Eb }, + { "adcS", Gv, Ev }, + { "adcb", AL, Ib }, + { "adcS", eAX, Iv }, + { "pushl", ss }, + { "popl", ss }, + /* 18 */ + { "sbbb", Eb, Gb }, + { "sbbS", Ev, Gv }, + { "sbbb", Gb, Eb }, + { "sbbS", Gv, Ev }, + { "sbbb", AL, Ib }, + { "sbbS", eAX, Iv }, + { "pushl", ds }, + { "popl", ds }, + /* 20 */ + { "andb", Eb, Gb }, + { "andS", Ev, Gv }, + { "andb", Gb, Eb }, + { "andS", Gv, Ev }, + { "andb", AL, Ib }, + { "andS", eAX, Iv }, + { "(bad)" }, /* SEG ES prefix */ + { "daa" }, + /* 28 */ + { "subb", Eb, Gb }, + { "subS", Ev, Gv }, + { "subb", Gb, Eb }, + { "subS", Gv, Ev }, + { "subb", AL, Ib }, + { "subS", eAX, Iv }, + { "(bad)" }, /* SEG CS prefix */ + { "das" }, + /* 30 */ + { "xorb", Eb, Gb }, + { "xorS", Ev, Gv }, + { "xorb", Gb, Eb }, + { "xorS", Gv, Ev }, + { "xorb", AL, Ib }, + { "xorS", eAX, Iv }, + { "(bad)" }, /* SEG SS prefix */ + { "aaa" }, + /* 38 */ + { "cmpb", Eb, Gb }, + { "cmpS", Ev, Gv }, + { "cmpb", Gb, Eb }, + { "cmpS", Gv, Ev }, + { "cmpb", AL, Ib }, + { "cmpS", eAX, Iv }, + { "(bad)" }, /* SEG DS prefix */ + { "aas" }, + /* 40 */ + { "incS", eAX }, + { "incS", eCX }, + { "incS", eDX }, + { "incS", eBX }, + { "incS", eSP }, + { "incS", eBP }, + { "incS", eSI }, + { "incS", eDI }, + /* 48 */ + { "decS", eAX }, + { "decS", eCX }, + { "decS", eDX }, + { "decS", eBX }, + { "decS", eSP }, + { "decS", eBP }, + { "decS", eSI }, + { "decS", eDI }, + /* 50 */ + { "pushS", eAX }, + { "pushS", eCX }, + { "pushS", eDX }, + { "pushS", eBX }, + { "pushS", eSP }, + { "pushS", eBP }, + { "pushS", eSI }, + { "pushS", eDI }, + /* 58 */ + { "popS", eAX }, + { "popS", eCX }, + { "popS", eDX }, + { "popS", eBX }, + { "popS", eSP }, + { "popS", eBP }, + { "popS", eSI }, + { "popS", eDI }, + /* 60 */ + { "pusha" }, + { "popa" }, + { "boundS", Gv, Ma }, + { "arpl", Ew, Gw }, + { "(bad)" }, /* seg fs */ + { "(bad)" }, /* seg gs */ + { "(bad)" }, /* op size prefix */ + { "(bad)" }, /* adr size prefix */ + /* 68 */ + { "pushS", Iv }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushl", sIb }, /* push of byte really pushes 4 bytes */ + { "imulS", Gv, Ev, Ib }, + { "insb", Yb, indirDX }, + { "insS", Yv, indirDX }, + { "outsb", indirDX, Xb }, + { "outsS", indirDX, Xv }, + /* 70 */ + { "jo", Jb }, + { "jno", Jb }, + { "jb", Jb }, + { "jae", Jb }, + { "je", Jb }, + { "jne", Jb }, + { "jbe", Jb }, + { "ja", Jb }, + /* 78 */ + { "js", Jb }, + { "jns", Jb }, + { "jp", Jb }, + { "jnp", Jb }, + { "jl", Jb }, + { "jnl", Jb }, + { "jle", Jb }, + { "jg", Jb }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)" }, + { GRP1Ss }, + { "testb", Eb, Gb }, + { "testS", Ev, Gv }, + { "xchgb", Eb, Gb }, + { "xchgS", Ev, Gv }, + /* 88 */ + { "movb", Eb, Gb }, + { "movS", Ev, Gv }, + { "movb", Gb, Eb }, + { "movS", Gv, Ev }, + { "movw", Ew, Sw }, + { "leaS", Gv, M }, + { "movw", Sw, Ew }, + { "popS", Ev }, + /* 90 */ + { "nop" }, + { "xchgS", eCX, eAX }, + { "xchgS", eDX, eAX }, + { "xchgS", eBX, eAX }, + { "xchgS", eSP, eAX }, + { "xchgS", eBP, eAX }, + { "xchgS", eSI, eAX }, + { "xchgS", eDI, eAX }, + /* 98 */ + { "cwtl" }, + { "cltd" }, + { "lcall", Ap }, + { "(bad)" }, /* fwait */ + { "pushf" }, + { "popf" }, + { "sahf" }, + { "lahf" }, + /* a0 */ + { "movb", AL, Ob }, + { "movS", eAX, Ov }, + { "movb", Ob, AL }, + { "movS", Ov, eAX }, + { "movsb", Yb, Xb }, + { "movsS", Yv, Xv }, + { "cmpsb", Yb, Xb }, + { "cmpsS", Yv, Xv }, + /* a8 */ + { "testb", AL, Ib }, + { "testS", eAX, Iv }, + { "stosb", Yb, AL }, + { "stosS", Yv, eAX }, + { "lodsb", AL, Xb }, + { "lodsS", eAX, Xv }, + { "scasb", AL, Xb }, + { "scasS", eAX, Xv }, + /* b0 */ + { "movb", AL, Ib }, + { "movb", CL, Ib }, + { "movb", DL, Ib }, + { "movb", BL, Ib }, + { "movb", AH, Ib }, + { "movb", CH, Ib }, + { "movb", DH, Ib }, + { "movb", BH, Ib }, + /* b8 */ + { "movS", eAX, Iv }, + { "movS", eCX, Iv }, + { "movS", eDX, Iv }, + { "movS", eBX, Iv }, + { "movS", eSP, Iv }, + { "movS", eBP, Iv }, + { "movS", eSI, Iv }, + { "movS", eDI, Iv }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw }, + { "ret" }, + { "lesS", Gv, Mp }, + { "ldsS", Gv, Mp }, + { "movb", Eb, Ib }, + { "movS", Ev, Iv }, + /* c8 */ + { "enter", Iw, Ib }, + { "leave" }, + { "lret", Iw }, + { "lret" }, + { "int3" }, + { "int", Ib }, + { "into" }, + { "iret" }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", Ib }, + { "aad", Ib }, + { "(bad)" }, + { "xlat" }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb }, + { "loope", Jb }, + { "loop", Jb }, + { "jCcxz", Jb }, + { "inb", AL, Ib }, + { "inS", eAX, Ib }, + { "outb", Ib, AL }, + { "outS", Ib, eAX }, + /* e8 */ + { "call", Av }, + { "jmp", Jv }, + { "ljmp", Ap }, + { "jmp", Jb }, + { "inb", AL, indirDX }, + { "inS", eAX, indirDX }, + { "outb", indirDX, AL }, + { "outS", indirDX, eAX }, + /* f0 */ + { "(bad)" }, /* lock prefix */ + { "(bad)" }, + { "(bad)" }, /* repne */ + { "(bad)" }, /* repz */ + { "hlt" }, + { "cmc" }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc" }, + { "stc" }, + { "cli" }, + { "sti" }, + { "cld" }, + { "std" }, + { GRP4 }, + { GRP5 }, +}; + +struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew }, + { "lslS", Gv, Ew }, + { "(bad)" }, + { "(bad)" }, + { "clts" }, + { "(bad)" }, + /* 08 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 10 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 18 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movl", Rd, Cd }, + { "movl", Rd, Dd }, + { "movl", Cd, Rd }, + { "movl", Dd, Rd }, + { "movl", Rd, Td }, + { "(bad)" }, + { "movl", Td, Rd }, + { "(bad)" }, + /* 28 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 30 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 38 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 40 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 48 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 50 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 58 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 60 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 68 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 70 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 78 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 80 */ + { "jo", Jv }, + { "jno", Jv }, + { "jb", Jv }, + { "jae", Jv }, + { "je", Jv }, + { "jne", Jv }, + { "jbe", Jv }, + { "ja", Jv }, + /* 88 */ + { "js", Jv }, + { "jns", Jv }, + { "jp", Jv }, + { "jnp", Jv }, + { "jl", Jv }, + { "jge", Jv }, + { "jle", Jv }, + { "jg", Jv }, + /* 90 */ + { "seto", Eb }, + { "setno", Eb }, + { "setb", Eb }, + { "setae", Eb }, + { "sete", Eb }, + { "setne", Eb }, + { "setbe", Eb }, + { "seta", Eb }, + /* 98 */ + { "sets", Eb }, + { "setns", Eb }, + { "setp", Eb }, + { "setnp", Eb }, + { "setl", Eb }, + { "setge", Eb }, + { "setle", Eb }, + { "setg", Eb }, + /* a0 */ + { "pushl", fs }, + { "popl", fs }, + { "(bad)" }, + { "btS", Ev, Gv }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)" }, + { "(bad)" }, + /* a8 */ + { "pushl", gs }, + { "popl", gs }, + { "(bad)" }, + { "btsS", Ev, Gv }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { "(bad)" }, + { "imulS", Gv, Ev }, + /* b0 */ + { "(bad)" }, + { "(bad)" }, + { "lssS", Gv, Mp }, /* 386 lists only Mp */ + { "btrS", Ev, Gv }, + { "lfsS", Gv, Mp }, /* 386 lists only Mp */ + { "lgsS", Gv, Mp }, /* 386 lists only Mp */ + { "movzbS", Gv, Eb }, + { "movzwS", Gv, Ew }, + /* b8 */ + { "(bad)" }, + { "(bad)" }, + { GRP8 }, + { "btcS", Ev, Gv }, + { "bsfS", Gv, Ev }, + { "bsrS", Gv, Ev }, + { "movsbS", Gv, Eb }, + { "movswS", Gv, Ew }, + /* c0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* c8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* d0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* d8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *codep; +static int mod; +static int rm; +static int reg; +static void oappend (); + +static char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; + +struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addb", Eb, Ib }, + { "orb", Eb, Ib }, + { "adcb", Eb, Ib }, + { "sbbb", Eb, Ib }, + { "andb", Eb, Ib }, + { "subb", Eb, Ib }, + { "xorb", Eb, Ib }, + { "cmpb", Eb, Ib } + }, + /* GRP1S */ + { + { "addS", Ev, Iv }, + { "orS", Ev, Iv }, + { "adcS", Ev, Iv }, + { "sbbS", Ev, Iv }, + { "andS", Ev, Iv }, + { "subS", Ev, Iv }, + { "xorS", Ev, Iv }, + { "cmpS", Ev, Iv } + }, + /* GRP1Ss */ + { + { "addS", Ev, sIb }, + { "orS", Ev, sIb }, + { "adcS", Ev, sIb }, + { "sbbS", Ev, sIb }, + { "andS", Ev, sIb }, + { "subS", Ev, sIb }, + { "xorS", Ev, sIb }, + { "cmpS", Ev, sIb } + }, + /* GRP2b */ + { + { "rolb", Eb, Ib }, + { "rorb", Eb, Ib }, + { "rclb", Eb, Ib }, + { "rcrb", Eb, Ib }, + { "shlb", Eb, Ib }, + { "shrb", Eb, Ib }, + { "(bad)" }, + { "sarb", Eb, Ib }, + }, + /* GRP2S */ + { + { "rolS", Ev, Ib }, + { "rorS", Ev, Ib }, + { "rclS", Ev, Ib }, + { "rcrS", Ev, Ib }, + { "shlS", Ev, Ib }, + { "shrS", Ev, Ib }, + { "(bad)" }, + { "sarS", Ev, Ib }, + }, + /* GRP2b_one */ + { + { "rolb", Eb }, + { "rorb", Eb }, + { "rclb", Eb }, + { "rcrb", Eb }, + { "shlb", Eb }, + { "shrb", Eb }, + { "(bad)" }, + { "sarb", Eb }, + }, + /* GRP2S_one */ + { + { "rolS", Ev }, + { "rorS", Ev }, + { "rclS", Ev }, + { "rcrS", Ev }, + { "shlS", Ev }, + { "shrS", Ev }, + { "(bad)" }, + { "sarS", Ev }, + }, + /* GRP2b_cl */ + { + { "rolb", Eb, CL }, + { "rorb", Eb, CL }, + { "rclb", Eb, CL }, + { "rcrb", Eb, CL }, + { "shlb", Eb, CL }, + { "shrb", Eb, CL }, + { "(bad)" }, + { "sarb", Eb, CL }, + }, + /* GRP2S_cl */ + { + { "rolS", Ev, CL }, + { "rorS", Ev, CL }, + { "rclS", Ev, CL }, + { "rcrS", Ev, CL }, + { "shlS", Ev, CL }, + { "shrS", Ev, CL }, + { "(bad)" }, + { "sarS", Ev, CL } + }, + /* GRP3b */ + { + { "testb", Eb, Ib }, + { "(bad)", Eb }, + { "notb", Eb }, + { "negb", Eb }, + { "mulb", AL, Eb }, + { "imulb", AL, Eb }, + { "divb", AL, Eb }, + { "idivb", AL, Eb } + }, + /* GRP3S */ + { + { "testS", Ev, Iv }, + { "(bad)" }, + { "notS", Ev }, + { "negS", Ev }, + { "mulS", eAX, Ev }, + { "imulS", eAX, Ev }, + { "divS", eAX, Ev }, + { "idivS", eAX, Ev }, + }, + /* GRP4 */ + { + { "incb", Eb }, + { "decb", Eb }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP5 */ + { + { "incS", Ev }, + { "decS", Ev }, + { "call", indirEv }, + { "lcall", indirEv }, + { "jmp", indirEv }, + { "ljmp", indirEv }, + { "pushS", Ev }, + { "(bad)" }, + }, + /* GRP6 */ + { + { "sldt", Ew }, + { "str", Ew }, + { "lldt", Ew }, + { "ltr", Ew }, + { "verr", Ew }, + { "verw", Ew }, + { "(bad)" }, + { "(bad)" } + }, + /* GRP7 */ + { + { "sgdt", Ew }, + { "sidt", Ew }, + { "lgdt", Ew }, + { "lidt", Ew }, + { "smsw", Ew }, + { "(bad)" }, + { "lmsw", Ew }, + { "(bad)" }, + }, + /* GRP8 */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "btS", Ev, Ib }, + { "btsS", Ev, Ib }, + { "btrS", Ev, Ib }, + { "btcS", Ev, Ib }, + } +}; + +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 + +static int prefixes; + +ckprefix () +{ + prefixes = 0; + while (1) + { + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADR; + break; + case 0x9b: + prefixes |= PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +static int dflag; +static int aflag; + +static char op1out[100], op2out[100], op3out[100]; +static int op_address[3], op_ad, op_index[3]; +static int start_pc; +extern void fputs_filtered (); + +/* + * disassemble the first instruction in 'inbuf'. You have to make + * sure all of the bytes of the instruction are filled in. + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * 'outbuf' gets filled in with the disassembled instruction. it should + * be long enough to hold the longest disassembled instruction. + * 100 bytes is certainly enough, unless symbol printing is added later + * The function returns the length of this instruction in bytes. + */ +i386dis (pc, inbuf, stream) + int pc; + unsigned char *inbuf; + FILE *stream; +{ + struct dis386 *dp; + char *p; + int i; + int enter_instruction; + char *first, *second, *third; + int needcomma; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + + ckprefix (); + + if (*codep == 0xc8) + enter_instruction = 1; + else + enter_instruction = 0; + + obufp = obuf; + + if (prefixes & PREFIX_REPZ) + oappend ("repz "); + if (prefixes & PREFIX_REPNZ) + oappend ("repnz "); + if (prefixes & PREFIX_LOCK) + oappend ("lock "); + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + /* fwait not followed by floating point instruction */ + fputs_filtered ("fwait", stream); + return (1); + } + + /* these would be initialized to 0 if disassembling for 8086 or 286 */ + dflag = 1; + aflag = 1; + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + + if (prefixes & PREFIX_ADR) + { + aflag ^= 1; + oappend ("addr16 "); + } + + if (*codep == 0x0f) + dp = &dis386_twobyte[*++codep]; + else + dp = &dis386[*codep]; + codep++; + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (); + } + else + { + if (dp->name == NULL) + dp = &grps[dp->bytemode1][reg]; + + putop (dp->name); + + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + fputs_filtered (obuf, stream); + + /* enter instruction is printed with operands in the + * same order as the intel book; everything else + * is printed in reverse order + */ + if (enter_instruction) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1) + print_address (op_address[op_index[0]], stream); + else + fputs_filtered (first, stream); + needcomma = 1; + } + if (*second) + { + if (needcomma) + fputs_filtered (",", stream); + if (op_index[1] != -1) + print_address (op_address[op_index[1]], stream); + else + fputs_filtered (second, stream); + needcomma = 1; + } + if (*third) + { + if (needcomma) + fputs_filtered (",", stream); + if (op_index[2] != -1) + print_address (op_address[op_index[2]], stream); + else + fputs_filtered (third, stream); + } + return (codep - inbuf); +} + +char *float_mem[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 +int OP_ST(), OP_STi(); + +#define FGRPd9_2 NULL, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1 +#define FGRPd9_5 NULL, NULL, 2 +#define FGRPd9_6 NULL, NULL, 3 +#define FGRPd9_7 NULL, NULL, 4 +#define FGRPda_5 NULL, NULL, 5 +#define FGRPdb_4 NULL, NULL, 6 +#define FGRPde_3 NULL, NULL, 7 +#define FGRPdf_4 NULL, NULL, 8 + +struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi }, + { "fmul", ST, STi }, + { "fcom", STi }, + { "fcomp", STi }, + { "fsub", ST, STi }, + { "fsubr", ST, STi }, + { "fdiv", ST, STi }, + { "fdivr", ST, STi }, + }, + /* d9 */ + { + { "fld", STi }, + { "fxch", STi }, + { FGRPd9_2 }, + { "(bad)" }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPda_5 }, + { "(bad)" }, + { "(bad)" }, + }, + /* db */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdb_4 }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* dc */ + { + { "fadd", STi, ST }, + { "fmul", STi, ST }, + { "(bad)" }, + { "(bad)" }, + { "fsub", STi, ST }, + { "fsubr", STi, ST }, + { "fdiv", STi, ST }, + { "fdivr", STi, ST }, + }, + /* dd */ + { + { "ffree", STi }, + { "(bad)" }, + { "fst", STi }, + { "fstp", STi }, + { "fucom", STi }, + { "fucomp", STi }, + { "(bad)" }, + { "(bad)" }, + }, + /* de */ + { + { "faddp", STi, ST }, + { "fmulp", STi, ST }, + { "(bad)" }, + { FGRPde_3 }, + { "fsubp", STi, ST }, + { "fsubrp", STi, ST }, + { "fdivp", STi, ST }, + { "fdivrp", STi, ST }, + }, + /* df */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdf_4 }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, +}; + + +char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + + +dofloat () +{ + struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + putop (float_mem[(floatop - 0xd8) * 8 + reg]); + obufp = op1out; + OP_E (v_mode); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm]); + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf && *codep == 0xe0) + strcpy (op1out, "%eax"); + } + else + { + putop (dp->name); + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + } +} + +/* ARGSUSED */ +OP_ST (ignore) +{ + oappend ("%st"); +} + +/* ARGSUSED */ +OP_STi (ignore) +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); +} + + +/* capital letters in template are macros */ +putop (template) + char *template; +{ + char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'C': /* For jcxz/jecxz */ + if (aflag == 0) + *obufp++ = 'e'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + break; + case 'S': + /* operand size flag */ + if (dflag) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + break; + } + } + *obufp = 0; +} + +static void +oappend (s) +char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); + *obufp = 0; +} + +append_prefix () +{ + if (prefixes & PREFIX_CS) + oappend ("%cs:"); + if (prefixes & PREFIX_DS) + oappend ("%ds:"); + if (prefixes & PREFIX_SS) + oappend ("%ss:"); + if (prefixes & PREFIX_ES) + oappend ("%es:"); + if (prefixes & PREFIX_FS) + oappend ("%fs:"); + if (prefixes & PREFIX_GS) + oappend ("%gs:"); +} + +OP_indirE (bytemode) +{ + oappend ("*"); + OP_E (bytemode); +} + +OP_E (bytemode) +{ + int disp; + int havesib; + int didoutput = 0; + int base; + int index; + int scale; + int havebase; + + /* skip mod/rm byte */ + codep++; + + havesib = 0; + havebase = 0; + disp = 0; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case v_mode: + if (dflag) + oappend (names32[rm]); + else + oappend (names16[rm]); + break; + default: + oappend (""); + break; + } + return; + } + + append_prefix (); + if (rm == 4) + { + havesib = 1; + havebase = 1; + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + switch (rm) + { + case 4: + /* implies havesib and havebase */ + if (base == 5) { + havebase = 0; + disp = get32 (); + } + break; + case 5: + disp = get32 (); + break; + default: + havebase = 1; + base = rm; + break; + } + break; + case 1: + disp = *(char *)codep++; + if (rm != 4) + { + havebase = 1; + base = rm; + } + break; + case 2: + disp = get32 (); + if (rm != 4) + { + havebase = 1; + base = rm; + } + break; + } + + if (mod != 0 || rm == 5 || (havesib && base == 5)) + { + sprintf (scratchbuf, "%d", disp); + oappend (scratchbuf); + } + + if (havebase || havesib) + { + oappend ("("); + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + sprintf (scratchbuf, ",%d", 1 << scale); + oappend (scratchbuf); + } + oappend (")"); + } +} + +OP_G (bytemode) +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (dflag) + oappend (names32[reg]); + else + oappend (names16[reg]); + break; + default: + oappend (""); + break; + } +} + +get32 () +{ + int x = 0; + + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return (x); +} + +get16 () +{ + int x = 0; + + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return (x); +} + +set_op (op) +int op; +{ + op_index[op_ad] = op_ad; + op_address[op_ad] = op; +} + +OP_REG (code) +{ + char *s; + + switch (code) + { + case indir_dx_reg: s = "(%dx)"; break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (dflag) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + break; + default: + s = ""; + break; + } + oappend (s); +} + +OP_I (bytemode) +{ + int op; + + switch (bytemode) + { + case b_mode: + op = *codep++ & 0xff; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = get16 (); + break; + case w_mode: + op = get16 (); + break; + default: + oappend (""); + return; + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); +} + +OP_sI (bytemode) +{ + int op; + + switch (bytemode) + { + case b_mode: + op = *(char *)codep++; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = (short)get16(); + break; + case w_mode: + op = (short)get16 (); + break; + default: + oappend (""); + return; + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); +} + +OP_J (bytemode) +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + disp = *(char *)codep++; + break; + case v_mode: + if (dflag) + disp = get32 (); + else + { + disp = (short)get16 (); + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + break; + default: + oappend (""); + return; + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp); + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_SEG (dummy) +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); +} + +OP_DIR (size) +{ + int seg, offset; + + switch (size) + { + case lptr: + if (aflag) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + oappend (scratchbuf); + break; + case v_mode: + if (aflag) + offset = get32 (); + else + offset = (short)get16 (); + + offset = start_pc + codep - start_codep + offset; + set_op (offset); + sprintf (scratchbuf, "0x%x", offset); + oappend (scratchbuf); + break; + default: + oappend (""); + break; + } +} + +/* ARGSUSED */ +OP_OFF (bytemode) +{ + int off; + + if (aflag) + off = get32 (); + else + off = get16 (); + + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_ESDI (dummy) +{ + oappend ("%es:("); + oappend (aflag ? "%edi" : "%di"); + oappend (")"); +} + +/* ARGSUSED */ +OP_DSSI (dummy) +{ + oappend ("%ds:("); + oappend (aflag ? "%esi" : "%si"); + oappend (")"); +} + +/* ARGSUSED */ +OP_ONE (dummy) +{ + oappend ("1"); +} + +/* ARGSUSED */ +OP_C (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_D (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_T (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); +} + +OP_rm (bytemode) +{ + switch (bytemode) + { + case d_mode: + oappend (names32[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + } +} + +/* GDB interface */ +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.h" + +#define MAXLEN 20 +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + + read_memory (memaddr, buffer, MAXLEN); + + return (i386dis ((int)memaddr, buffer, stream)); +} + diff --git a/gdb/i386-xdep.c b/gdb/i386-xdep.c new file mode 100644 index 00000000000..dddf22d2e19 --- /dev/null +++ b/gdb/i386-xdep.c @@ -0,0 +1,357 @@ +/* Intel 386 stuff. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* this table must line up with REGISTER_NAMES in m-i386.h */ +/* symbols like 'EAX' come from */ +static int regmap[] = +{ + EAX, ECX, EDX, EBX, + UESP, EBP, ESI, EDI, + EIP, EFL, CS, SS, + DS, ES, FS, GS, +}; + +/* blockend is the value of u.u_ar0, and points to the + * place where GS is stored + */ +i386_register_u_addr (blockend, regnum) +{ +#if 0 + /* this will be needed if fp registers are reinstated */ + /* for now, you can look at them with 'info float' + * sys5 wont let you change them with ptrace anyway + */ + if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) + { + int ubase, fpstate; + struct user u; + ubase = blockend + 4 * (SS + 1) - KSTKSZ; + fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u); + return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM)); + } + else +#endif + return (blockend + 4 * regmap[regnum]); + +} + +/* This is broken for cross debugging. Possible solutions are: + +1. Don't worry about whether the thing compiles for cross-debugging. +Go ahead and call them from i386-tdep.c. +1a. Same thing but use some macros in xm-i386.h so that gdb will +compile for cross-debugging but just give an error (or some such behavior) +when you attempt to convert floats. + +2. Write a portable (in the sense of running on any machine; it would +always be for i387 floating-point formats) extended<->double converter +(which just deals with the values as arrays of char). + +3. Assume the host machine has *some* IEEE chip. However, IEEE does +not standardize formats for extended floats (387 is 10 bytes, 68881 is +12 bytes), so this won't work. */ + +i387_to_double (from, to) + char *from; + char *to; +{ + long *lp; + /* push extended mode on 387 stack, then pop in double mode + * + * first, set exception masks so no error is generated - + * number will be rounded to inf or 0, if necessary + */ + asm ("pushl %eax"); /* grab a stack slot */ + asm ("fstcw (%esp)"); /* get 387 control word */ + asm ("movl (%esp),%eax"); /* save old value */ + asm ("orl $0x3f,%eax"); /* mask all exceptions */ + asm ("pushl %eax"); + asm ("fldcw (%esp)"); /* load new value into 387 */ + + asm ("movl 8(%ebp),%eax"); + asm ("fldt (%eax)"); /* push extended number on 387 stack */ + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpl (%eax)"); /* pop double */ + asm ("fwait"); + + asm ("popl %eax"); /* flush modified control word */ + asm ("fnclex"); /* clear exceptions */ + asm ("fldcw (%esp)"); /* restore original control word */ + asm ("popl %eax"); /* flush saved copy */ +} + +double_to_i387 (from, to) + char *from; + char *to; +{ + /* push double mode on 387 stack, then pop in extended mode + * no errors are possible because every 64-bit pattern + * can be converted to an extended + */ + asm ("movl 8(%ebp),%eax"); + asm ("fldl (%eax)"); + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpt (%eax)"); + asm ("fwait"); +} + +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; + +static +print_387_control_word (control) +unsigned short control; +{ + printf ("control 0x%04x: ", control); + printf ("compute to "); + switch ((control >> 8) & 3) + { + case 0: printf ("24 bits; "); break; + case 1: printf ("(bad); "); break; + case 2: printf ("53 bits; "); break; + case 3: printf ("64 bits; "); break; + } + printf ("round "); + switch ((control >> 10) & 3) + { + case 0: printf ("NEAREST; "); break; + case 1: printf ("DOWN; "); break; + case 2: printf ("UP; "); break; + case 3: printf ("CHOP; "); break; + } + if (control & 0x3f) + { + printf ("mask:"); + if (control & 0x0001) printf (" INVALID"); + if (control & 0x0002) printf (" DENORM"); + if (control & 0x0004) printf (" DIVZ"); + if (control & 0x0008) printf (" OVERF"); + if (control & 0x0010) printf (" UNDERF"); + if (control & 0x0020) printf (" LOS"); + printf (";"); + } + printf ("\n"); + if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n", + control & 0xe080); +} + +static +print_387_status_word (status) + unsigned short status; +{ + printf ("status 0x%04x: ", status); + if (status & 0xff) + { + printf ("exceptions:"); + if (status & 0x0001) printf (" INVALID"); + if (status & 0x0002) printf (" DENORM"); + if (status & 0x0004) printf (" DIVZ"); + if (status & 0x0008) printf (" OVERF"); + if (status & 0x0010) printf (" UNDERF"); + if (status & 0x0020) printf (" LOS"); + if (status & 0x0040) printf (" FPSTACK"); + printf ("; "); + } + printf ("flags: %d%d%d%d; ", + (status & 0x4000) != 0, + (status & 0x0400) != 0, + (status & 0x0200) != 0, + (status & 0x0100) != 0); + + printf ("top %d\n", (status >> 11) & 7); +} + +static +print_387_status (status, ep) + unsigned short status; + struct env387 *ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + bothstatus = ((status != 0) && (ep->status != 0)); + if (status != 0) + { + if (bothstatus) + printf ("u: "); + print_387_status_word (status); + } + + if (ep->status != 0) + { + if (bothstatus) + printf ("e: "); + print_387_status_word (ep->status); + } + + print_387_control_word (ep->control); + printf ("last exception: "); + printf ("opcode 0x%x; ", ep->opcode); + printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip); + printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand); + + top = (ep->status >> 11) & 7; + + printf ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep->tag >> (fpreg * 2)) & 3) + { + case 0: printf ("valid "); break; + case 1: printf ("zero "); break; + case 2: printf ("trap "); break; + case 3: printf ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf ("%02x", ep->regs[fpreg][i]); + + i387_to_double (ep->regs[fpreg], (char *)&val); + printf (" %g\n", val); + } + if (ep->r0) + printf ("warning: reserved0 is 0x%x\n", ep->r0); + if (ep->r1) + printf ("warning: reserved1 is 0x%x\n", ep->r1); + if (ep->r2) + printf ("warning: reserved2 is 0x%x\n", ep->r2); + if (ep->r3) + printf ("warning: reserved3 is 0x%x\n", ep->r3); +} + +#ifndef U_FPSTATE +#define U_FPSTATE(u) u.u_fpstate +#endif + +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; + /* fpstate defined in */ + struct fpstate *fpstatep; + char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; + unsigned int uaddr; + char fpvalid; + unsigned int rounded_addr; + unsigned int rounded_size; + extern int corechan; + int skip; + + uaddr = (char *)&u.u_fpvalid - (char *)&u; + if (have_inferior_p()) + { + unsigned int data; + unsigned int mask; + + rounded_addr = uaddr & -sizeof (int); + data = ptrace (3, inferior_pid, rounded_addr, 0); + mask = 0xff << ((uaddr - rounded_addr) * 8); + + fpvalid = ((data & mask) != 0); + } + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror ("seek on core file"); + if (myread (corechan, &fpvalid, 1) < 0) + perror ("read on core file"); + + } + + if (fpvalid == 0) + { + printf ("no floating point status saved\n"); + return; + } + + uaddr = (char *)&U_FPSTATE(u) - (char *)&u; + if (have_inferior_p ()) + { + int *ip; + + rounded_addr = uaddr & -sizeof (int); + rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + + sizeof (int) - 1) / sizeof (int); + skip = uaddr - rounded_addr; + + ip = (int *)buf; + for (i = 0; i < rounded_size; i++) + { + *ip++ = ptrace (3, inferior_pid, rounded_addr, 0); + rounded_addr += sizeof (int); + } + } + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror_with_name ("seek on core file"); + if (myread (corechan, buf, sizeof (struct fpstate)) < 0) + perror_with_name ("read from core file"); + skip = 0; + } + + fpstatep = (struct fpstate *)(buf + skip); + print_387_status (fpstatep->status, (struct env387 *)fpstatep->state); +} + diff --git a/gdb/i960-pinsn.c b/gdb/i960-pinsn.c new file mode 100644 index 00000000000..ea3fa64c90b --- /dev/null +++ b/gdb/i960-pinsn.c @@ -0,0 +1,847 @@ +/* Disassemble i80960 instructions. + */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +extern char *reg_names[]; + +static FILE *stream; /* Output goes here */ +static void print_addr(); +static void ctrl(); +static void cobr(); +static void reg(); +static int mem(); +static void ea(); +static void dstop(); +static void regop(); +static void invalid(); +static int pinsn(); +static void put_abs(); + + +/* Print the i960 instruction at address 'memaddr' in debugged memory, + on stream 's'. Returns length of the instruction, in bytes. */ +int +print_insn( memaddr, s ) + CORE_ADDR memaddr; + FILE *s; +{ + unsigned int word1, word2; + + stream = s; + word1 = read_memory_integer( memaddr, 4 ); + word2 = read_memory_integer( memaddr+4, 4 ); + return pinsn( memaddr, word1, word2 ); +} + + +/* Read the i960 instruction at 'memaddr' and return the address of + the next instruction after that, or 0 if 'memaddr' is not the + address of a valid instruction. The first word of the instruction + is stored at 'pword1', and the second word, if any, is stored at + 'pword2'. */ + +CORE_ADDR +next_insn (memaddr, pword1, pword2) + unsigned long *pword1, *pword2; + CORE_ADDR memaddr; +{ + int len; + unsigned long buf[2]; + + /* Read the two (potential) words of the instruction at once, + to eliminate the overhead of two calls to read_memory (). + TODO: read more instructions at once and cache them. */ + + read_memory (memaddr, buf, sizeof (buf)); + *pword1 = buf[0]; + SWAP_TARGET_AND_HOST (pword1, sizeof (long)); + *pword2 = buf[1]; + SWAP_TARGET_AND_HOST (pword2, sizeof (long)); + + /* Divide instruction set into classes based on high 4 bits of opcode*/ + + switch ((*pword1 >> 28) & 0xf) + { + case 0x0: + case 0x1: /* ctrl */ + + case 0x2: + case 0x3: /* cobr */ + + case 0x5: + case 0x6: + case 0x7: /* reg */ + len = 4; + break; + + case 0x8: + case 0x9: + case 0xa: + case 0xb: + case 0xc: + len = mem (memaddr, *pword1, *pword2, 1); + break; + + default: /* invalid instruction */ + len = 0; + break; + } + + if (len) + return memaddr + len; + else + return 0; +} + +#define IN_GDB + +/***************************************************************************** + * All code below this point should be identical with that of + * the disassembler in gdmp960. + *****************************************************************************/ + +struct tabent { + char *name; + char numops; +}; + +static int +pinsn( memaddr, word1, word2 ) + unsigned long memaddr; + unsigned long word1, word2; +{ + int instr_len; + + instr_len = 4; + put_abs( word1, word2 ); + + /* Divide instruction set into classes based on high 4 bits of opcode*/ + + switch ( (word1 >> 28) & 0xf ){ + case 0x0: + case 0x1: + ctrl( memaddr, word1, word2 ); + break; + case 0x2: + case 0x3: + cobr( memaddr, word1, word2 ); + break; + case 0x5: + case 0x6: + case 0x7: + reg( word1 ); + break; + case 0x8: + case 0x9: + case 0xa: + case 0xb: + case 0xc: + instr_len = mem( memaddr, word1, word2, 0 ); + break; + default: + /* invalid instruction, print as data word */ + invalid( word1 ); + break; + } + return instr_len; +} + +/****************************************/ +/* CTRL format */ +/****************************************/ +static void +ctrl( memaddr, word1, word2 ) + unsigned long memaddr; + unsigned long word1, word2; +{ + int i; + static struct tabent ctrl_tab[] = { + NULL, 0, /* 0x00 */ + NULL, 0, /* 0x01 */ + NULL, 0, /* 0x02 */ + NULL, 0, /* 0x03 */ + NULL, 0, /* 0x04 */ + NULL, 0, /* 0x05 */ + NULL, 0, /* 0x06 */ + NULL, 0, /* 0x07 */ + "b", 1, /* 0x08 */ + "call", 1, /* 0x09 */ + "ret", 0, /* 0x0a */ + "bal", 1, /* 0x0b */ + NULL, 0, /* 0x0c */ + NULL, 0, /* 0x0d */ + NULL, 0, /* 0x0e */ + NULL, 0, /* 0x0f */ + "bno", 1, /* 0x10 */ + "bg", 1, /* 0x11 */ + "be", 1, /* 0x12 */ + "bge", 1, /* 0x13 */ + "bl", 1, /* 0x14 */ + "bne", 1, /* 0x15 */ + "ble", 1, /* 0x16 */ + "bo", 1, /* 0x17 */ + "faultno", 0, /* 0x18 */ + "faultg", 0, /* 0x19 */ + "faulte", 0, /* 0x1a */ + "faultge", 0, /* 0x1b */ + "faultl", 0, /* 0x1c */ + "faultne", 0, /* 0x1d */ + "faultle", 0, /* 0x1e */ + "faulto", 0, /* 0x1f */ + }; + + i = (word1 >> 24) & 0xff; + if ( (ctrl_tab[i].name == NULL) || ((word1 & 1) != 0) ){ + invalid( word1 ); + return; + } + + fputs( ctrl_tab[i].name, stream ); + if ( word1 & 2 ){ /* Predicts branch not taken */ + fputs( ".f", stream ); + } + + if ( ctrl_tab[i].numops == 1 ){ + /* EXTRACT DISPLACEMENT AND CONVERT TO ADDRESS */ + word1 &= 0x00ffffff; + if ( word1 & 0x00800000 ){ /* Sign bit is set */ + word1 |= (-1 & ~0xffffff); /* Sign extend */ + } + putc( '\t', stream ); + print_addr( word1 + memaddr ); + } +} + +/****************************************/ +/* COBR format */ +/****************************************/ +static void +cobr( memaddr, word1, word2 ) + unsigned long memaddr; + unsigned long word1, word2; +{ + int src1; + int src2; + int i; + + static struct tabent cobr_tab[] = { + "testno", 1, /* 0x20 */ + "testg", 1, /* 0x21 */ + "teste", 1, /* 0x22 */ + "testge", 1, /* 0x23 */ + "testl", 1, /* 0x24 */ + "testne", 1, /* 0x25 */ + "testle", 1, /* 0x26 */ + "testo", 1, /* 0x27 */ + NULL, 0, /* 0x28 */ + NULL, 0, /* 0x29 */ + NULL, 0, /* 0x2a */ + NULL, 0, /* 0x2b */ + NULL, 0, /* 0x2c */ + NULL, 0, /* 0x2d */ + NULL, 0, /* 0x2e */ + NULL, 0, /* 0x2f */ + "bbc", 3, /* 0x30 */ + "cmpobg", 3, /* 0x31 */ + "cmpobe", 3, /* 0x32 */ + "cmpobge", 3, /* 0x33 */ + "cmpobl", 3, /* 0x34 */ + "cmpobne", 3, /* 0x35 */ + "cmpoble", 3, /* 0x36 */ + "bbs", 3, /* 0x37 */ + "cmpibno", 3, /* 0x38 */ + "cmpibg", 3, /* 0x39 */ + "cmpibe", 3, /* 0x3a */ + "cmpibge", 3, /* 0x3b */ + "cmpibl", 3, /* 0x3c */ + "cmpibne", 3, /* 0x3d */ + "cmpible", 3, /* 0x3e */ + "cmpibo", 3, /* 0x3f */ + }; + + i = ((word1 >> 24) & 0xff) - 0x20; + if ( cobr_tab[i].name == NULL ){ + invalid( word1 ); + return; + } + + fputs( cobr_tab[i].name, stream ); + if ( word1 & 2 ){ /* Predicts branch not taken */ + fputs( ".f", stream ); + } + putc( '\t', stream ); + + src1 = (word1 >> 19) & 0x1f; + src2 = (word1 >> 14) & 0x1f; + + if ( word1 & 0x02000 ){ /* M1 is 1 */ + fprintf( stream, "%d", src1 ); + } else { /* M1 is 0 */ + fputs( reg_names[src1], stream ); + } + + if ( cobr_tab[i].numops > 1 ){ + if ( word1 & 1 ){ /* S2 is 1 */ + fprintf( stream, ",sf%d,", src2 ); + } else { /* S1 is 0 */ + fprintf( stream, ",%s,", reg_names[src2] ); + } + + /* Extract displacement and convert to address + */ + word1 &= 0x00001ffc; + if ( word1 & 0x00001000 ){ /* Negative displacement */ + word1 |= (-1 & ~0x1fff); /* Sign extend */ + } + print_addr( memaddr + word1 ); + } +} + +/****************************************/ +/* MEM format */ +/****************************************/ +static int /* returns instruction length: 4 or 8 */ +mem( memaddr, word1, word2, noprint ) + unsigned long memaddr; + unsigned long word1, word2; + int noprint; /* If TRUE, return instruction length, but + don't output any text. */ +{ + int i, j; + int len; + int mode; + int offset; + char *reg1, *reg2, *reg3; + + /* This lookup table is too sparse to make it worth typing in, but not + * so large as to make a sparse array necessary. We allocate the + * table at runtime, initialize all entries to empty, and copy the + * real ones in from an initialization table. + * + * NOTE: In this table, the meaning of 'numops' is: + * 1: single operand + * 2: 2 operands, load instruction + * -2: 2 operands, store instruction + */ + static struct tabent *mem_tab = NULL; + static struct { int opcode; char *name; char numops; } mem_init[] = { +#define MEM_MIN 0x80 + 0x80, "ldob", 2, + 0x82, "stob", -2, + 0x84, "bx", 1, + 0x85, "balx", 2, + 0x86, "callx", 1, + 0x88, "ldos", 2, + 0x8a, "stos", -2, + 0x8c, "lda", 2, + 0x90, "ld", 2, + 0x92, "st", -2, + 0x98, "ldl", 2, + 0x9a, "stl", -2, + 0xa0, "ldt", 2, + 0xa2, "stt", -2, + 0xb0, "ldq", 2, + 0xb2, "stq", -2, + 0xc0, "ldib", 2, + 0xc2, "stib", -2, + 0xc8, "ldis", 2, + 0xca, "stis", -2, +#define MEM_MAX 0xca +#define MEM_SIZ ((MEM_MAX-MEM_MIN+1) * sizeof(struct tabent)) + 0, NULL, 0 + }; + + if ( mem_tab == NULL ){ + mem_tab = (struct tabent *) xmalloc( MEM_SIZ ); + bzero( mem_tab, MEM_SIZ ); + for ( i = 0; mem_init[i].opcode != 0; i++ ){ + j = mem_init[i].opcode - MEM_MIN; + mem_tab[j].name = mem_init[i].name; + mem_tab[j].numops = mem_init[i].numops; + } + } + + i = ((word1 >> 24) & 0xff) - MEM_MIN; + mode = (word1 >> 10) & 0xf; + + if ( (mem_tab[i].name != NULL) /* Valid instruction */ + && ((mode == 5) || (mode >=12)) ){ /* With 32-bit displacement */ + len = 8; + } else { + len = 4; + } + + if ( noprint ){ + return len; + } + + if ( (mem_tab[i].name == NULL) || (mode == 6) ){ + invalid( word1 ); + return len; + } + + fprintf( stream, "%s\t", mem_tab[i].name ); + + reg1 = reg_names[ (word1 >> 19) & 0x1f ]; /* MEMB only */ + reg2 = reg_names[ (word1 >> 14) & 0x1f ]; + reg3 = reg_names[ word1 & 0x1f ]; /* MEMB only */ + offset = word1 & 0xfff; /* MEMA only */ + + switch ( mem_tab[i].numops ){ + + case 2: /* LOAD INSTRUCTION */ + if ( mode & 4 ){ /* MEMB FORMAT */ + ea( memaddr, mode, reg2, reg3, word1, word2 ); + fprintf( stream, ",%s", reg1 ); + } else { /* MEMA FORMAT */ + fprintf( stream, "0x%x", offset ); + if (mode & 8) { + fprintf( stream, "(%s)", reg2 ); + } + fprintf( stream, ",%s", reg1 ); + } + break; + + case -2: /* STORE INSTRUCTION */ + if ( mode & 4 ){ /* MEMB FORMAT */ + fprintf( stream, "%s,", reg1 ); + ea( memaddr, mode, reg2, reg3, word1, word2 ); + } else { /* MEMA FORMAT */ + fprintf( stream, "%s,0x%x", reg1, offset ); + if (mode & 8) { + fprintf( stream, "(%s)", reg2 ); + } + } + break; + + case 1: /* BX/CALLX INSTRUCTION */ + if ( mode & 4 ){ /* MEMB FORMAT */ + ea( memaddr, mode, reg2, reg3, word1, word2 ); + } else { /* MEMA FORMAT */ + fprintf( stream, "0x%x", offset ); + if (mode & 8) { + fprintf( stream, "(%s)", reg2 ); + } + } + break; + } + + return len; +} + +/****************************************/ +/* REG format */ +/****************************************/ +static void +reg( word1 ) + unsigned long word1; +{ + int i, j; + int opcode; + int fp; + int m1, m2, m3; + int s1, s2; + int src, src2, dst; + char *mnemp; + + /* This lookup table is too sparse to make it worth typing in, but not + * so large as to make a sparse array necessary. We allocate the + * table at runtime, initialize all entries to empty, and copy the + * real ones in from an initialization table. + * + * NOTE: In this table, the meaning of 'numops' is: + * 1: single operand, which is NOT a destination. + * -1: single operand, which IS a destination. + * 2: 2 operands, the 2nd of which is NOT a destination. + * -2: 2 operands, the 2nd of which IS a destination. + * 3: 3 operands + * + * If an opcode mnemonic begins with "F", it is a floating-point + * opcode (the "F" is not printed). + */ + + static struct tabent *reg_tab = NULL; + static struct { int opcode; char *name; char numops; } reg_init[] = { +#define REG_MIN 0x580 + 0x580, "notbit", 3, + 0x581, "and", 3, + 0x582, "andnot", 3, + 0x583, "setbit", 3, + 0x584, "notand", 3, + 0x586, "xor", 3, + 0x587, "or", 3, + 0x588, "nor", 3, + 0x589, "xnor", 3, + 0x58a, "not", -2, + 0x58b, "ornot", 3, + 0x58c, "clrbit", 3, + 0x58d, "notor", 3, + 0x58e, "nand", 3, + 0x58f, "alterbit", 3, + 0x590, "addo", 3, + 0x591, "addi", 3, + 0x592, "subo", 3, + 0x593, "subi", 3, + 0x598, "shro", 3, + 0x59a, "shrdi", 3, + 0x59b, "shri", 3, + 0x59c, "shlo", 3, + 0x59d, "rotate", 3, + 0x59e, "shli", 3, + 0x5a0, "cmpo", 2, + 0x5a1, "cmpi", 2, + 0x5a2, "concmpo", 2, + 0x5a3, "concmpi", 2, + 0x5a4, "cmpinco", 3, + 0x5a5, "cmpinci", 3, + 0x5a6, "cmpdeco", 3, + 0x5a7, "cmpdeci", 3, + 0x5ac, "scanbyte", 2, + 0x5ae, "chkbit", 2, + 0x5b0, "addc", 3, + 0x5b2, "subc", 3, + 0x5cc, "mov", -2, + 0x5d8, "eshro", 3, + 0x5dc, "movl", -2, + 0x5ec, "movt", -2, + 0x5fc, "movq", -2, + 0x600, "synmov", 2, + 0x601, "synmovl", 2, + 0x602, "synmovq", 2, + 0x603, "cmpstr", 3, + 0x604, "movqstr", 3, + 0x605, "movstr", 3, + 0x610, "atmod", 3, + 0x612, "atadd", 3, + 0x613, "inspacc", -2, + 0x614, "ldphy", -2, + 0x615, "synld", -2, + 0x617, "fill", 3, + 0x630, "sdma", 3, + 0x631, "udma", 0, + 0x640, "spanbit", -2, + 0x641, "scanbit", -2, + 0x642, "daddc", 3, + 0x643, "dsubc", 3, + 0x644, "dmovt", -2, + 0x645, "modac", 3, + 0x646, "condrec", -2, + 0x650, "modify", 3, + 0x651, "extract", 3, + 0x654, "modtc", 3, + 0x655, "modpc", 3, + 0x656, "receive", -2, + 0x659, "sysctl", 3, + 0x660, "calls", 1, + 0x662, "send", 3, + 0x663, "sendserv", 1, + 0x664, "resumprcs", 1, + 0x665, "schedprcs", 1, + 0x666, "saveprcs", 0, + 0x668, "condwait", 1, + 0x669, "wait", 1, + 0x66a, "signal", 1, + 0x66b, "mark", 0, + 0x66c, "fmark", 0, + 0x66d, "flushreg", 0, + 0x66f, "syncf", 0, + 0x670, "emul", 3, + 0x671, "ediv", 3, + 0x673, "ldtime", -1, + 0x674, "Fcvtir", -2, + 0x675, "Fcvtilr", -2, + 0x676, "Fscalerl", 3, + 0x677, "Fscaler", 3, + 0x680, "Fatanr", 3, + 0x681, "Flogepr", 3, + 0x682, "Flogr", 3, + 0x683, "Fremr", 3, + 0x684, "Fcmpor", 2, + 0x685, "Fcmpr", 2, + 0x688, "Fsqrtr", -2, + 0x689, "Fexpr", -2, + 0x68a, "Flogbnr", -2, + 0x68b, "Froundr", -2, + 0x68c, "Fsinr", -2, + 0x68d, "Fcosr", -2, + 0x68e, "Ftanr", -2, + 0x68f, "Fclassr", 1, + 0x690, "Fatanrl", 3, + 0x691, "Flogeprl", 3, + 0x692, "Flogrl", 3, + 0x693, "Fremrl", 3, + 0x694, "Fcmporl", 2, + 0x695, "Fcmprl", 2, + 0x698, "Fsqrtrl", -2, + 0x699, "Fexprl", -2, + 0x69a, "Flogbnrl", -2, + 0x69b, "Froundrl", -2, + 0x69c, "Fsinrl", -2, + 0x69d, "Fcosrl", -2, + 0x69e, "Ftanrl", -2, + 0x69f, "Fclassrl", 1, + 0x6c0, "Fcvtri", -2, + 0x6c1, "Fcvtril", -2, + 0x6c2, "Fcvtzri", -2, + 0x6c3, "Fcvtzril", -2, + 0x6c9, "Fmovr", -2, + 0x6d9, "Fmovrl", -2, + 0x6e1, "Fmovre", -2, + 0x6e2, "Fcpysre", 3, + 0x6e3, "Fcpyrsre", 3, + 0x701, "mulo", 3, + 0x708, "remo", 3, + 0x70b, "divo", 3, + 0x741, "muli", 3, + 0x748, "remi", 3, + 0x749, "modi", 3, + 0x74b, "divi", 3, + 0x78b, "Fdivr", 3, + 0x78c, "Fmulr", 3, + 0x78d, "Fsubr", 3, + 0x78f, "Faddr", 3, + 0x79b, "Fdivrl", 3, + 0x79c, "Fmulrl", 3, + 0x79d, "Fsubrl", 3, + 0x79f, "Faddrl", 3, +#define REG_MAX 0x79f +#define REG_SIZ ((REG_MAX-REG_MIN+1) * sizeof(struct tabent)) + 0, NULL, 0 + }; + + if ( reg_tab == NULL ){ + reg_tab = (struct tabent *) xmalloc( REG_SIZ ); + bzero( reg_tab, REG_SIZ ); + for ( i = 0; reg_init[i].opcode != 0; i++ ){ + j = reg_init[i].opcode - REG_MIN; + reg_tab[j].name = reg_init[i].name; + reg_tab[j].numops = reg_init[i].numops; + } + } + + opcode = ((word1 >> 20) & 0xff0) | ((word1 >> 7) & 0xf); + i = opcode - REG_MIN; + + if ( (opcodeREG_MAX) || (reg_tab[i].name==NULL) ){ + invalid( word1 ); + return; + } + + mnemp = reg_tab[i].name; + if ( *mnemp == 'F' ){ + fp = 1; + mnemp++; + } else { + fp = 0; + } + + fputs( mnemp, stream ); + + s1 = (word1 >> 5) & 1; + s2 = (word1 >> 6) & 1; + m1 = (word1 >> 11) & 1; + m2 = (word1 >> 12) & 1; + m3 = (word1 >> 13) & 1; + src = word1 & 0x1f; + src2 = (word1 >> 14) & 0x1f; + dst = (word1 >> 19) & 0x1f; + + if ( reg_tab[i].numops != 0 ){ + putc( '\t', stream ); + + switch ( reg_tab[i].numops ){ + case 1: + regop( m1, s1, src, fp ); + break; + case -1: + dstop( m3, dst, fp ); + break; + case 2: + regop( m1, s1, src, fp ); + putc( ',', stream ); + regop( m2, s2, src2, fp ); + break; + case -2: + regop( m1, s1, src, fp ); + putc( ',', stream ); + dstop( m3, dst, fp ); + break; + case 3: + regop( m1, s1, src, fp ); + putc( ',', stream ); + regop( m2, s2, src2, fp ); + putc( ',', stream ); + dstop( m3, dst, fp ); + break; + } + } +} + + +/* + * Print out effective address for memb instructions. + */ +static void +ea( memaddr, mode, reg2, reg3, word1, word2 ) + unsigned long memaddr; + int mode; + char *reg2, *reg3; + unsigned int word2; +{ + int scale; + static int scale_tab[] = { 1, 2, 4, 8, 16 }; + + scale = (word1 >> 7) & 0x07; + if ( (scale > 4) || ((word1 >> 5) & 0x03 != 0) ){ + invalid( word1 ); + return; + } + scale = scale_tab[scale]; + + switch (mode) { + case 4: /* (reg) */ + fprintf( stream, "(%s)", reg2 ); + break; + case 5: /* displ+8(ip) */ + print_addr( word2+8+memaddr ); + break; + case 7: /* (reg)[index*scale] */ + if (scale == 1) { + fprintf( stream, "(%s)[%s]", reg2, reg3 ); + } else { + fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale); + } + break; + case 12: /* displacement */ + print_addr( word2 ); + break; + case 13: /* displ(reg) */ + print_addr( word2 ); + fprintf( stream, "(%s)", reg2 ); + break; + case 14: /* displ[index*scale] */ + print_addr( word2 ); + if (scale == 1) { + fprintf( stream, "[%s]", reg3 ); + } else { + fprintf( stream, "[%s*%d]", reg3, scale ); + } + break; + case 15: /* displ(reg)[index*scale] */ + print_addr( word2 ); + if (scale == 1) { + fprintf( stream, "(%s)[%s]", reg2, reg3 ); + } else { + fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale ); + } + break; + default: + invalid( word1 ); + return; + } +} + + +/************************************************/ +/* Register Instruction Operand */ +/************************************************/ +static void +regop( mode, spec, reg, fp ) + int mode, spec, reg, fp; +{ + if ( fp ){ /* FLOATING POINT INSTRUCTION */ + if ( mode == 1 ){ /* FP operand */ + switch ( reg ){ + case 0: fputs( "fp0", stream ); break; + case 1: fputs( "fp1", stream ); break; + case 2: fputs( "fp2", stream ); break; + case 3: fputs( "fp3", stream ); break; + case 16: fputs( "0f0.0", stream ); break; + case 22: fputs( "0f1.0", stream ); break; + default: putc( '?', stream ); break; + } + } else { /* Non-FP register */ + fputs( reg_names[reg], stream ); + } + } else { /* NOT FLOATING POINT */ + if ( mode == 1 ){ /* Literal */ + fprintf( stream, "%d", reg ); + } else { /* Register */ + if ( spec == 0 ){ + fputs( reg_names[reg], stream ); + } else { + fprintf( stream, "sf%d", reg ); + } + } + } +} + +/************************************************/ +/* Register Instruction Destination Operand */ +/************************************************/ +static void +dstop( mode, reg, fp ) + int mode, reg, fp; +{ + /* 'dst' operand can't be a literal. On non-FP instructions, register + * mode is assumed and "m3" acts as if were "s3"; on FP-instructions, + * sf registers are not allowed so m3 acts normally. + */ + if ( fp ){ + regop( mode, 0, reg, fp ); + } else { + regop( 0, mode, reg, fp ); + } +} + + +static void +invalid( word1 ) + int word1; +{ + fprintf( stream, ".word\t0x%08x", word1 ); +} + +static void +print_addr(a) +{ + fprintf( stream, "0x%x", a ); +} + +static void +put_abs( word1, word2 ) + unsigned long word1, word2; +{ +#ifdef IN_GDB + return; +#else + int len; + + switch ( (word1 >> 28) & 0xf ){ + case 0x8: + case 0x9: + case 0xa: + case 0xb: + case 0xc: + /* MEM format instruction */ + len = mem( 0, word1, word2, 1 ); + break; + default: + len = 4; + break; + } + + if ( len == 8 ){ + fprintf( stream, "%08x %08x\t", word1, word2 ); + } else { + fprintf( stream, "%08x \t", word1 ); + } +; + +#endif +} diff --git a/gdb/i960-tdep.c b/gdb/i960-tdep.c new file mode 100644 index 00000000000..a82328a2e5e --- /dev/null +++ b/gdb/i960-tdep.c @@ -0,0 +1,646 @@ +/* Target-machine dependent code for the Intel 960 + Copyright (C) 1991 Free Software Foundation, Inc. + Contributed by Intel Corporation. + examine_prologue and other parts contributed by Wind River Systems. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Miscellaneous i80960-dependent routines. + Most are called from macros defined in "tm-i960.h". */ + +#include +#include +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "value.h" +#include "frame.h" +#include "signame.h" +#include "ieee-float.h" + +/* Structure of i960 extended floating point format. */ + +const struct ext_format ext_format_i960 [] = { +/* tot sbyte smask expbyte manbyte */ + { 12, 9, 0x80, 9,8, 4,0 }, /* i960 */ +}; + +/* gdb960 is always running on a non-960 host. Check its characteristics. + This routine must be called as part of gdb initialization. */ + +static void +check_host() +{ + int i; + + static struct typestruct { + int hostsize; /* Size of type on host */ + int i960size; /* Size of type on i960 */ + char *typename; /* Name of type, for error msg */ + } types[] = { + { sizeof(short), 2, "short" }, + { sizeof(int), 4, "int" }, + { sizeof(long), 4, "long" }, + { sizeof(float), 4, "float" }, + { sizeof(double), 8, "double" }, + { sizeof(char *), 4, "pointer" }, + }; +#define TYPELEN (sizeof(types) / sizeof(struct typestruct)) + + /* Make sure that host type sizes are same as i960 + */ + for ( i = 0; i < TYPELEN; i++ ){ + if ( types[i].hostsize != types[i].i960size ){ + printf("sizeof(%s) != %d: PROCEED AT YOUR OWN RISK!\n", + types[i].typename, types[i].i960size ); + } + + } +} + +/* Examine an i960 function prologue, recording the addresses at which + registers are saved explicitly by the prologue code, and returning + the address of the first instruction after the prologue (but not + after the instruction at address LIMIT, as explained below). + + LIMIT places an upper bound on addresses of the instructions to be + examined. If the prologue code scan reaches LIMIT, the scan is + aborted and LIMIT is returned. This is used, when examining the + prologue for the current frame, to keep examine_prologue () from + claiming that a given register has been saved when in fact the + instruction that saves it has not yet been executed. LIMIT is used + at other times to stop the scan when we hit code after the true + function prologue (e.g. for the first source line) which might + otherwise be mistaken for function prologue. + + The format of the function prologue matched by this routine is + derived from examination of the source to gcc960 1.21, particularly + the routine i960_function_prologue (). A "regular expression" for + the function prologue is given below: + + (lda LRn, g14 + mov g14, g[0-7] + (mov 0, g14) | (lda 0, g14))? + + (mov[qtl]? g[0-15], r[4-15])* + ((addo [1-31], sp, sp) | (lda n(sp), sp))? + (st[qtl]? g[0-15], n(fp))* + + (cmpobne 0, g14, LFn + mov sp, g14 + lda 0x30(sp), sp + LFn: stq g0, (g14) + stq g4, 0x10(g14) + stq g8, 0x20(g14))? + + (st g14, n(fp))? + (mov g13,r[4-15])? +*/ + +/* Macros for extracting fields from i960 instructions. */ + +#define BITMASK(pos, width) (((0x1 << (width)) - 1) << (pos)) +#define EXTRACT_FIELD(val, pos, width) ((val) >> (pos) & BITMASK (0, width)) + +#define REG_SRC1(insn) EXTRACT_FIELD (insn, 0, 5) +#define REG_SRC2(insn) EXTRACT_FIELD (insn, 14, 5) +#define REG_SRCDST(insn) EXTRACT_FIELD (insn, 19, 5) +#define MEM_SRCDST(insn) EXTRACT_FIELD (insn, 19, 5) +#define MEMA_OFFSET(insn) EXTRACT_FIELD (insn, 0, 12) + +/* Fetch the instruction at ADDR, returning 0 if ADDR is beyond LIM or + is not the address of a valid instruction, the address of the next + instruction beyond ADDR otherwise. *PWORD1 receives the first word + of the instruction, and (for two-word instructions), *PWORD2 receives + the second. */ + +#define NEXT_PROLOGUE_INSN(addr, lim, pword1, pword2) \ + (((addr) < (lim)) ? next_insn (addr, pword1, pword2) : 0) + +static CORE_ADDR +examine_prologue (ip, limit, frame_addr, fsr) + register CORE_ADDR ip; + register CORE_ADDR limit; + FRAME_ADDR frame_addr; + struct frame_saved_regs *fsr; +{ + register CORE_ADDR next_ip; + register int src, dst; + register unsigned int *pcode; + unsigned int insn1, insn2; + int size; + int within_leaf_prologue; + CORE_ADDR save_addr; + static unsigned int varargs_prologue_code [] = + { + 0x3507a00c, /* cmpobne 0x0, g14, LFn */ + 0x5cf01601, /* mov sp, g14 */ + 0x8c086030, /* lda 0x30(sp), sp */ + 0xb2879000, /* LFn: stq g0, (g14) */ + 0xb2a7a010, /* stq g4, 0x10(g14) */ + 0xb2c7a020 /* stq g8, 0x20(g14) */ + }; + + /* Accept a leaf procedure prologue code fragment if present. + Note that ip might point to either the leaf or non-leaf + entry point; we look for the non-leaf entry point first: */ + + within_leaf_prologue = 0; + if ((next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2)) + && ((insn1 & 0xfffff000) == 0x8cf00000 /* lda LRx, g14 (MEMA) */ + || (insn1 & 0xfffffc60) == 0x8cf03000)) /* lda LRx, g14 (MEMB) */ + { + within_leaf_prologue = 1; + next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn1, &insn2); + } + + /* Now look for the prologue code at a leaf entry point: */ + + if (next_ip + && (insn1 & 0xff87ffff) == 0x5c80161e /* mov g14, gx */ + && REG_SRCDST (insn1) <= G0_REGNUM + 7) + { + within_leaf_prologue = 1; + if ((next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn1, &insn2)) + && (insn1 == 0x8cf00000 /* lda 0, g14 */ + || insn1 == 0x5cf01e00)) /* mov 0, g14 */ + { + ip = next_ip; + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); + within_leaf_prologue = 0; + } + } + + /* If something that looks like the beginning of a leaf prologue + has been seen, but the remainder of the prologue is missing, bail. + We don't know what we've got. */ + + if (within_leaf_prologue) + return (ip); + + /* Accept zero or more instances of "mov[qtl]? gx, ry", where y >= 4. + This may cause us to mistake the moving of a register + parameter to a local register for the saving of a callee-saved + register, but that can't be helped, since with the + "-fcall-saved" flag, any register can be made callee-saved. */ + + while (next_ip + && (insn1 & 0xfc802fb0) == 0x5c000610 + && (dst = REG_SRCDST (insn1)) >= (R0_REGNUM + 4)) + { + src = REG_SRC1 (insn1); + size = EXTRACT_FIELD (insn1, 24, 2) + 1; + save_addr = frame_addr + ((dst - R0_REGNUM) * 4); + while (size--) + { + fsr->regs[src++] = save_addr; + save_addr += 4; + } + ip = next_ip; + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); + } + + /* Accept an optional "addo n, sp, sp" or "lda n(sp), sp". */ + + if (next_ip && + ((insn1 & 0xffffffe0) == 0x59084800 /* addo n, sp, sp */ + || (insn1 & 0xfffff000) == 0x8c086000 /* lda n(sp), sp (MEMA) */ + || (insn1 & 0xfffffc60) == 0x8c087400)) /* lda n(sp), sp (MEMB) */ + { + ip = next_ip; + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); + } + + /* Accept zero or more instances of "st[qtl]? gx, n(fp)". + This may cause us to mistake the copying of a register + parameter to the frame for the saving of a callee-saved + register, but that can't be helped, since with the + "-fcall-saved" flag, any register can be made callee-saved. + We can, however, refuse to accept a save of register g14, + since that is matched explicitly below. */ + + while (next_ip && + ((insn1 & 0xf787f000) == 0x9287e000 /* stl? gx, n(fp) (MEMA) */ + || (insn1 & 0xf787fc60) == 0x9287f400 /* stl? gx, n(fp) (MEMB) */ + || (insn1 & 0xef87f000) == 0xa287e000 /* st[tq] gx, n(fp) (MEMA) */ + || (insn1 & 0xef87fc60) == 0xa287f400) /* st[tq] gx, n(fp) (MEMB) */ + && ((src = MEM_SRCDST (insn1)) != G14_REGNUM)) + { + save_addr = frame_addr + ((insn1 & BITMASK (12, 1)) + ? insn2 : MEMA_OFFSET (insn1)); + size = (insn1 & BITMASK (29, 1)) ? ((insn1 & BITMASK (28, 1)) ? 4 : 3) + : ((insn1 & BITMASK (27, 1)) ? 2 : 1); + while (size--) + { + fsr->regs[src++] = save_addr; + save_addr += 4; + } + ip = next_ip; + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); + } + + /* Accept the varargs prologue code if present. */ + + size = sizeof (varargs_prologue_code) / sizeof (int); + pcode = varargs_prologue_code; + while (size-- && next_ip && *pcode++ == insn1) + { + ip = next_ip; + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); + } + + /* Accept an optional "st g14, n(fp)". */ + + if (next_ip && + ((insn1 & 0xfffff000) == 0x92f7e000 /* st g14, n(fp) (MEMA) */ + || (insn1 & 0xfffffc60) == 0x92f7f400)) /* st g14, n(fp) (MEMB) */ + { + fsr->regs[G14_REGNUM] = frame_addr + ((insn1 & BITMASK (12, 1)) + ? insn2 : MEMA_OFFSET (insn1)); + ip = next_ip; + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); + } + + /* Accept zero or one instance of "mov g13, ry", where y >= 4. + This is saving the address where a struct should be returned. */ + + if (next_ip + && (insn1 & 0xff802fbf) == 0x5c00061d + && (dst = REG_SRCDST (insn1)) >= (R0_REGNUM + 4)) + { + save_addr = frame_addr + ((dst - R0_REGNUM) * 4); + fsr->regs[G0_REGNUM+13] = save_addr; + ip = next_ip; +#if 0 /* We'll need this once there is a subsequent instruction examined. */ + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); +#endif + } + + return (ip); +} + +/* Given an ip value corresponding to the start of a function, + return the ip of the first instruction after the function + prologue. */ + +CORE_ADDR +skip_prologue (ip) + CORE_ADDR (ip); +{ + struct frame_saved_regs saved_regs_dummy; + struct symtab_and_line sal; + CORE_ADDR limit; + + sal = find_pc_line (ip, 0); + limit = (sal.end) ? sal.end : 0xffffffff; + + return (examine_prologue (ip, limit, (FRAME_ADDR) 0, &saved_regs_dummy)); +} + +/* 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. + + We cache the result of doing this in the frame_cache_obstack, since + it is fairly expensive. */ + +void +frame_find_saved_regs (fi, fsr) + struct frame_info *fi; + struct frame_saved_regs *fsr; +{ + register CORE_ADDR next_addr; + register CORE_ADDR *saved_regs; + register int regnum; + register struct frame_saved_regs *cache_fsr; + extern struct obstack frame_cache_obstack; + CORE_ADDR ip; + struct symtab_and_line sal; + CORE_ADDR limit; + + if (!fi->fsr) + { + cache_fsr = (struct frame_saved_regs *) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_saved_regs)); + bzero (cache_fsr, sizeof (struct frame_saved_regs)); + fi->fsr = cache_fsr; + + /* Find the start and end of the function prologue. If the PC + is in the function prologue, we only consider the part that + has executed already. */ + + ip = get_pc_function_start (fi->pc); + sal = find_pc_line (ip, 0); + limit = (sal.end && sal.end < fi->pc) ? sal.end: fi->pc; + + examine_prologue (ip, limit, fi->frame, cache_fsr); + + /* Record the addresses at which the local registers are saved. + Strictly speaking, we should only do this for non-leaf procedures, + but no one will ever look at these values if it is a leaf procedure, + since local registers are always caller-saved. */ + + next_addr = (CORE_ADDR) fi->frame; + saved_regs = cache_fsr->regs; + for (regnum = R0_REGNUM; regnum <= R15_REGNUM; regnum++) + { + *saved_regs++ = next_addr; + next_addr += 4; + } + + cache_fsr->regs[FP_REGNUM] = cache_fsr->regs[PFP_REGNUM]; + } + + *fsr = *fi->fsr; + + /* Fetch the value of the sp from memory every time, since it + is conceivable that it has changed since the cache was flushed. + This unfortunately undoes much of the savings from caching the + saved register values. I suggest adding an argument to + get_frame_saved_regs () specifying the register number we're + interested in (or -1 for all registers). This would be passed + through to FRAME_FIND_SAVED_REGS (), permitting more efficient + computation of saved register addresses (e.g., on the i960, + we don't have to examine the prologue to find local registers). + -- markf@wrs.com + FIXME, we don't need to refetch this, since the cache is cleared + every time the child process is restarted. If GDB itself + modifies SP, it has to clear the cache by hand (does it?). -gnu */ + + fsr->regs[SP_REGNUM] = read_memory_integer (fsr->regs[SP_REGNUM], 4); +} + +/* Return the address of the argument block for the frame + described by FI. Returns 0 if the address is unknown. */ + +CORE_ADDR +frame_args_address (fi, must_be_correct) + struct frame_info *fi; +{ + register FRAME frame; + struct frame_saved_regs fsr; + CORE_ADDR ap; + + /* If g14 was saved in the frame by the function prologue code, return + the saved value. If the frame is current and we are being sloppy, + return the value of g14. Otherwise, return zero. */ + + frame = FRAME_INFO_ID (fi); + get_frame_saved_regs (fi, &fsr); + if (fsr.regs[G14_REGNUM]) + ap = read_memory_integer (fsr.regs[G14_REGNUM],4); + else { + if (must_be_correct) + return 0; /* Don't cache this result */ + if (get_next_frame (frame)) + ap = 0; + else + ap = read_register (G14_REGNUM); + } + fi->arg_pointer = ap; /* Cache it for next time */ + return ap; +} + +/* Return the address of the return struct for the frame + described by FI. Returns 0 if the address is unknown. */ + +CORE_ADDR +frame_struct_result_address (fi) + struct frame_info *fi; +{ + register FRAME frame; + struct frame_saved_regs fsr; + CORE_ADDR ap; + + /* If the frame is non-current, check to see if g14 was saved in the + frame by the function prologue code; return the saved value if so, + zero otherwise. If the frame is current, return the value of g14. + + FIXME, shouldn't this use the saved value as long as we are past + the function prologue, and only use the current value if we have + no saved value and are at TOS? -- gnu@cygnus.com */ + + frame = FRAME_INFO_ID (fi); + if (get_next_frame (frame)) { + get_frame_saved_regs (fi, &fsr); + if (fsr.regs[G13_REGNUM]) + ap = read_memory_integer (fsr.regs[G13_REGNUM],4); + else + ap = 0; + } else { + ap = read_register (G13_REGNUM); + } + return ap; +} + +/* Return address to which the currently executing leafproc will return, + or 0 if ip is not in a leafproc (or if we can't tell if it is). + + Do this by finding the starting address of the routine in which ip lies. + If the instruction there is "mov g14, gx" (where x is in [0,7]), this + is a leafproc and the return address is in register gx. Well, this is + true unless the return address points at a RET instruction in the current + procedure, which indicates that we have a 'dual entry' routine that + has been entered through the CALL entry point. */ + +CORE_ADDR +leafproc_return (ip) + CORE_ADDR ip; /* ip from currently executing function */ +{ + int i; + register struct misc_function *mf; + char *p; + int dst; + unsigned int insn1, insn2; + CORE_ADDR return_addr; + char *index (); + + if ((i = find_pc_misc_function (ip)) >= 0) + { + mf = &misc_function_vector[i]; + if ((p = index (mf->name, '.')) && !strcmp (p, ".lf")) + { + if (next_insn (mf->address, &insn1, &insn2) + && (insn1 & 0xff87ffff) == 0x5c80161e /* mov g14, gx */ + && (dst = REG_SRCDST (insn1)) <= G0_REGNUM + 7) + { + /* Get the return address. If the "mov g14, gx" + instruction hasn't been executed yet, read + the return address from g14; otherwise, read it + from the register into which g14 was moved. */ + + return_addr = read_register ((ip == mf->address) + ? G14_REGNUM : dst); + + /* We know we are in a leaf procedure, but we don't know + whether the caller actually did a "bal" to the ".lf" + entry point, or a normal "call" to the non-leaf entry + point one instruction before. In the latter case, the + return address will be the address of a "ret" + instruction within the procedure itself. We test for + this below. */ + + if (!next_insn (return_addr, &insn1, &insn2) + || (insn1 & 0xff000000) != 0xa000000 /* ret */ + || find_pc_misc_function (return_addr) != i) + return (return_addr); + } + } + } + + return (0); +} + +/* 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 i960, the frame *is* set up immediately after the call, + unless the function is a leaf procedure. */ + +CORE_ADDR +saved_pc_after_call (frame) + FRAME frame; +{ + CORE_ADDR saved_pc; + CORE_ADDR get_frame_pc (); + + saved_pc = leafproc_return (get_frame_pc (frame)); + if (!saved_pc) + saved_pc = FRAME_SAVED_PC (frame); + + return (saved_pc); +} + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +pop_frame () +{ + register struct frame_info *current_fi, *prev_fi; + register int i; + CORE_ADDR save_addr; + CORE_ADDR leaf_return_addr; + struct frame_saved_regs fsr; + char local_regs_buf[16 * 4]; + + current_fi = get_frame_info (get_current_frame ()); + + /* First, undo what the hardware does when we return. + If this is a non-leaf procedure, restore local registers from + the save area in the calling frame. Otherwise, load the return + address obtained from leafproc_return () into the rip. */ + + leaf_return_addr = leafproc_return (current_fi->pc); + if (!leaf_return_addr) + { + /* Non-leaf procedure. Restore local registers, incl IP. */ + prev_fi = get_frame_info (get_prev_frame (FRAME_INFO_ID (current_fi))); + read_memory (prev_fi->frame, local_regs_buf, sizeof (local_regs_buf)); + write_register_bytes (REGISTER_BYTE (R0_REGNUM), local_regs_buf, + sizeof (local_regs_buf)); + + /* Restore frame pointer. */ + write_register (FP_REGNUM, prev_fi->frame); + } + else + { + /* Leaf procedure. Just restore the return address into the IP. */ + write_register (RIP_REGNUM, leaf_return_addr); + } + + /* Now restore any global regs that the current function had saved. */ + get_frame_saved_regs (current_fi, &fsr); + for (i = G0_REGNUM; i < G14_REGNUM; i++) + { + if (save_addr = fsr.regs[i]) + write_register (i, read_memory_integer (save_addr, 4)); + } + + /* Flush the frame cache, create a frame for the new innermost frame, + and make it the current frame. */ + + flush_cached_frames (); + set_current_frame (create_new_frame (read_register (FP_REGNUM), read_pc ())); +} + +/* Print out text describing a "signal number" with which the i80960 halted. + + See the file "fault.c" in the nindy monitor source code for a list + of stop codes. */ + +void +print_fault( siggnal ) + int siggnal; /* Signal number, as returned by target_wait() */ +{ + static char unknown[] = "Unknown fault or trace"; + static char *sigmsgs[] = { + /* FAULTS */ + "parallel fault", /* 0x00 */ + unknown, /* 0x01 */ + "operation fault", /* 0x02 */ + "arithmetic fault", /* 0x03 */ + "floating point fault", /* 0x04 */ + "constraint fault", /* 0x05 */ + "virtual memory fault", /* 0x06 */ + "protection fault", /* 0x07 */ + "machine fault", /* 0x08 */ + "structural fault", /* 0x09 */ + "type fault", /* 0x0a */ + "reserved (0xb) fault", /* 0x0b */ + "process fault", /* 0x0c */ + "descriptor fault", /* 0x0d */ + "event fault", /* 0x0e */ + "reserved (0xf) fault", /* 0x0f */ + + /* TRACES */ + "single-step trace", /* 0x10 */ + "branch trace", /* 0x11 */ + "call trace", /* 0x12 */ + "return trace", /* 0x13 */ + "pre-return trace", /* 0x14 */ + "supervisor call trace",/* 0x15 */ + "breakpoint trace", /* 0x16 */ + }; +# define NUMMSGS ((int)( sizeof(sigmsgs) / sizeof(sigmsgs[0]) )) + + if (siggnal < NSIG) { + printf ("\nProgram received signal %d, %s\n", + siggnal, + sys_siglist[siggnal]); + } else { + /* The various target_wait()s bias the 80960 "signal number" + by adding NSIG to it, so it won't get confused with any + of the Unix signals elsewhere in GDB. We need to + "unbias" it before using it. */ + siggnal -= NSIG; + + printf("Program stopped for reason #%d: %s.\n", siggnal, + (siggnal < NUMMSGS && siggnal >= 0)? + sigmsgs[siggnal] : unknown ); + } +} + +/* Initialization stub */ + +_initialize_i960_tdep () +{ + check_host (); +} diff --git a/gdb/ieee-float.c b/gdb/ieee-float.c new file mode 100644 index 00000000000..7b7f9f1fd0f --- /dev/null +++ b/gdb/ieee-float.c @@ -0,0 +1,141 @@ +/* IEEE floating point support routines, for GDB, the GNU Debugger. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "param.h" +#include "ieee-float.h" +#include /* ldexp */ + +/* Convert an IEEE extended float to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +void +ieee_extended_to_double (ext_format, from, to) + struct ext_format *ext_format; + char *from; + double *to; +{ + unsigned char *ufrom = (unsigned char *)from; + double dto; + unsigned long mant0, mant1, exp; + + bcopy (&from[MANBYTE_H], &mant0, 4); + bcopy (&from[MANBYTE_L], &mant1, 4); + exp = ((ufrom[EXPBYTE_H] & (unsigned char)~SIGNMASK) << 8) | ufrom[EXPBYTE_L]; + + if (exp == EXT_EXP_NAN) { + /* We have a NaN source. */ + dto = 0.123456789; /* Not much else useful to do */ + } else if (exp == 0 && mant0 == 0 && mant1 == 0) { + dto = 0; + } else { + /* Build the result algebraically. Might go infinite, underflow, etc; + who cares. */ + mant0 |= 0x80000000; + dto = ldexp ((double)mant0, exp - EXT_EXP_BIAS - 31); + dto += ldexp ((double)mant1, exp - EXT_EXP_BIAS - 31 - 32); + } + *to = dto; +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. */ + +void +double_to_ieee_extended (ext_format, from, to) + struct ext_format *ext_format; + double *from; + char *to; +{ + double dfrom = *from; + unsigned long twolongs[2]; + unsigned long mant0, mant1, exp; + unsigned char twobytes[2]; + + bzero (to, TOTALSIZE); + if (dfrom == 0) + return; /* Result is zero */ + if (dfrom != dfrom) { + /* From is NaN */ + to[EXPBYTE_H] = (unsigned char)(EXT_EXP_NAN >> 8); + to[EXPBYTE_L] = (unsigned char)EXT_EXP_NAN; + to[MANBYTE_H] = 1; /* Be sure it's not infinity, but NaN value is irrel */ + return; /* Result is NaN */ + } + if (dfrom < 0) + to[SIGNBYTE] |= SIGNMASK; /* Set negative sign */ + /* How to tell an infinity from an ordinary number? FIXME-someday */ + + /* The following code assumes that the host has IEEE doubles. FIXME-someday. + It also assumes longs are 32 bits! FIXME-someday. */ + bcopy (from, twolongs, 8); + bcopy (from, twobytes, 2); +#if HOST_BYTE_ORDER == BIG_ENDIAN + exp = ((twobytes[1] & 0xF0) >> 4) | (twobytes[0] & 0x7F) << 4; + mant0 = (twolongs[0] << 11) | twolongs[1] >> 21; + mant1 = (twolongs[1] << 11); +#else + exp = ((twobytes[0] & 0xF0) >> 4) | (twobytes[1] & 0x7F) << 4; + mant0 = (twolongs[1] << 11) | twolongs[0] >> 21; + mant1 = (twolongs[0] << 11); +#endif + + /* Fiddle with leading 1-bit, implied in double, explicit in extended. */ + if (exp == 0) + mant0 &= 0x7FFFFFFF; + else + mant0 |= 0x80000000; + + exp -= DBL_EXP_BIAS; /* Get integer exp */ + exp += EXT_EXP_BIAS; /* Offset for extended *&/ + + /* OK, now store it in extended format. */ + to[EXPBYTE_H] |= (unsigned char)(exp >> 8); /* Retain sign */ + to[EXPBYTE_L] = (unsigned char) exp; + + bcopy (&mant0, &to[MANBYTE_H], 4); + bcopy (&mant1, &to[MANBYTE_L], 4); +} + + +#ifdef DEBUG + +/* Test some numbers to see that extended/double conversion works for them. */ + +ieee_test (n) + int n; +{ + union { double d; int i[2]; } di; + double result; + int i; + char exten[16]; + extern struct ext_format ext_format_68881; + + for (i = 0; i < n; i++) { + di.i[0] = random(); + di.i[1] = random(); + double_to_ieee_extended (ext_format_68881, &di.d, exten); + ieee_extended_to_double (ext_format_68881, exten, &result); + if (di.d != result) + printf ("Differ: %x %x %g => %x %x %g\n", di.d, di.d, result, result); + } +} + +#endif diff --git a/gdb/ieee-float.h b/gdb/ieee-float.h new file mode 100644 index 00000000000..93255183d5a --- /dev/null +++ b/gdb/ieee-float.h @@ -0,0 +1,66 @@ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Parameters for extended float format: */ + +struct ext_format { + unsigned totalsize; /* Total size of extended number */ + unsigned signbyte; /* Byte number of sign bit */ + unsigned char signmask; /* Mask for sign bit */ + unsigned expbyte_h; /* High byte of exponent */ + unsigned expbyte_l; /* Low byte of exponent */ + unsigned manbyte_h; /* High byte of mantissa */ + unsigned manbyte_l; /* Low byte of mantissa */ +}; + +#define TOTALSIZE ext_format->totalsize +#define SIGNBYTE ext_format->signbyte +#define SIGNMASK ext_format->signmask +#define EXPBYTE_H ext_format->expbyte_h +#define EXPBYTE_L ext_format->expbyte_l +#define MANBYTE_H ext_format->manbyte_h +#define MANBYTE_L ext_format->manbyte_l + +/* Actual ext_format structs for various machines are in the *-tdep.c file + for each machine. */ + +#define EXT_EXP_NAN 0x7FFF /* Exponent value that indicates NaN */ +#define EXT_EXP_BIAS 0x3FFF /* Amount added to "true" exponent for ext */ +#define DBL_EXP_BIAS 0x3FF /* Ditto, for doubles */ + +/* Convert an IEEE extended float to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +ieee_extended_to_double ( +#ifdef __STDC__ + struct ext_format *ext_format, char *from, double *to +#endif +); + +/* The converse: convert the double *FROM to an extended float + and store where TO points. */ + +void +double_to_ieee_extended ( +#ifdef __STDC__ + struct ext_format *ext_format, double *from, char *to +#endif +); diff --git a/gdb/kdb-start.c b/gdb/kdb-start.c new file mode 100644 index 00000000000..cbc69fd874a --- /dev/null +++ b/gdb/kdb-start.c @@ -0,0 +1,40 @@ +/* Main loop for the standalone kernel debugger. + Copyright (C) 1989, Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "param.h" + +static char *args[] = {"kdb", "kdb-symbols", 0}; + +static char *environment[] = {0}; + +char **environ; + +start () +{ +#ifdef NAMES_HAVE_UNDERSCORE + INIT_STACK (_kdb_stack_beg, _kdb_stack_end); +#else /* not NAMES_HAVE_UNDERSCORE */ + INIT_STACK (kdb_stack_beg, kdb_stack_end); +#endif /* not NAMES_HAVE_UNDERSCORE */ + + environ = environment; + + main (2, args, environment); +} diff --git a/gdb/m68k-opcode.h b/gdb/m68k-opcode.h new file mode 100755 index 00000000000..a0961f6c1c5 --- /dev/null +++ b/gdb/m68k-opcode.h @@ -0,0 +1,1680 @@ +/* Opcode table for m68000/m68020 and m68881. + Copyright (C) 1989, Free Software Foundation. + +This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler. + +Both GDB and GAS are free software; you can redistribute and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB and GAS are distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB or GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +struct m68k_opcode +{ + char *name; + unsigned long opcode; + unsigned long match; + char *args; +}; + +/* We store four bytes of opcode for all opcodes because that + is the most any of them need. The actual length of an instruction + is always at least 2 bytes, and is as much longer as necessary to + hold the operands it has. + + The match component is a mask saying which bits must match + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing two characters + for each operand of the instruction. The first specifies + the kind of operand; the second, the place it is stored. */ + +/* Kinds of operands: + D data register only. Stored as 3 bits. + A address register only. Stored as 3 bits. + R either kind of register. Stored as 4 bits. + F floating point coprocessor register only. Stored as 3 bits. + O an offset (or width): immediate data 0-31 or data register. + Stored as 6 bits in special format for BF... insns. + + autoincrement only. Stored as 3 bits (number of the address register). + - autodecrement only. Stored as 3 bits (number of the address register). + Q quick immediate data. Stored as 3 bits. + This matches an immediate operand only when value is in range 1 .. 8. + M moveq immediate data. Stored as 8 bits. + This matches an immediate operand only when value is in range -128..127 + T trap vector immediate data. Stored as 4 bits. + + k K-factor for fmove.p instruction. Stored as a 7-bit constant or + a three bit register offset, depending on the field type. + + # immediate data. Stored in special places (b, w or l) + which say how many bits to store. + ^ immediate data for floating point instructions. Special places + are offset by 2 bytes from '#'... + B pc-relative address, converted to an offset + that is treated as immediate data. + d displacement and register. Stores the register as 3 bits + and stores the displacement in the entire second word. + + C the CCR. No need to store it; this is just for filtering validity. + S the SR. No need to store, just as with CCR. + U the USP. No need to store, just as with CCR. + + I Coprocessor ID. Not printed if 1. The Coprocessor ID is always + extracted from the 'd' field of word one, which means that an extended + coprocessor opcode can be skipped using the 'i' place, if needed. + + s System Control register for the floating point coprocessor. + S List of system control registers for floating point coprocessor. + + J Misc register for movec instruction, stored in 'j' format. + Possible values: + 000 SFC Source Function Code reg + 001 DFC Data Function Code reg + 002 CACR Cache Control Register + 800 USP User Stack Pointer + 801 VBR Vector Base reg + 802 CAAR Cache Address Register + 803 MSP Master Stack Pointer + 804 ISP Interrupt Stack Pointer + + L Register list of the type d0-d7/a0-a7 etc. + (New! Improved! Can also hold fp0-fp7, as well!) + The assembler tries to see if the registers match the insn by + looking at where the insn wants them stored. + + l Register list like L, but with all the bits reversed. + Used for going the other way. . . + + They are all stored as 6 bits using an address mode and a register number; + they differ in which addressing modes they match. + + * all (modes 0-6,7.*) + ~ alterable memory (modes 2-6,7.0,7.1)(not 0,1,7.~) + % alterable (modes 0-6,7.0,7.1)(not 7.~) + ; data (modes 0,2-6,7.*)(not 1) + @ data, but not immediate (modes 0,2-6,7.? ? ?)(not 1,7.?) This may really be ;, the 68020 book says it is + ! control (modes 2,5,6,7.*-)(not 0,1,3,4,7.4) + & alterable control (modes 2,5,6,7.0,7.1)(not 0,1,7.? ? ?) + $ alterable data (modes 0,2-6,7.0,7.1)(not 1,7.~) + ? alterable control, or data register (modes 0,2,5,6,7.0,7.1)(not 1,3,4,7.~) + / control, or data register (modes 0,2,5,6,7.0,7.1,7.2,7.3)(not 1,3,4,7.4) +*/ + +/* JF: for the 68851 */ +/* + I didn't use much imagination in choosing the + following codes, so many of them aren't very + mnemonic. -rab + + P pmmu register + Possible values: + 000 TC Translation Control reg + 100 CAL Current Access Level + 101 VAL Validate Access Level + 110 SCC Stack Change Control + 111 AC Access Control + + W wide pmmu registers + Possible values: + 001 DRP Dma Root Pointer + 010 SRP Supervisor Root Pointer + 011 CRP Cpu Root Pointer + + f function code register + 0 SFC + 1 DFC + + V VAL register only + + X BADx, BACx + 100 BAD Breakpoint Acknowledge Data + 101 BAC Breakpoint Acknowledge Control + + Y PSR + Z PCSR + + | memory (modes 2-6, 7.*) + +*/ + +/* Places to put an operand, for non-general operands: + s source, low bits of first word. + d dest, shifted 9 in first word + 1 second word, shifted 12 + 2 second word, shifted 6 + 3 second word, shifted 0 + 4 third word, shifted 12 + 5 third word, shifted 6 + 6 third word, shifted 0 + 7 second word, shifted 7 + 8 second word, shifted 10 + D store in both place 1 and place 3; for divul and divsl. + b second word, low byte + w second word (entire) + l second and third word (entire) + g branch offset for bra and similar instructions. + The place to store depends on the magnitude of offset. + t store in both place 7 and place 8; for floating point operations + c branch offset for cpBcc operations. + The place to store is word two if bit six of word one is zero, + and words two and three if bit six of word one is one. + i Increment by two, to skip over coprocessor extended operands. Only + works with the 'I' format. + k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number. + Also used for dynamic fmovem instruction. + C floating point coprocessor constant - 7 bits. Also used for static + K-factors... + j Movec register #, stored in 12 low bits of second word. + + Places to put operand, for general operands: + d destination, shifted 6 bits in first word + b source, at low bit of first word, and immediate uses one byte + w source, at low bit of first word, and immediate uses two bytes + l source, at low bit of first word, and immediate uses four bytes + s source, at low bit of first word. + Used sometimes in contexts where immediate is not allowed anyway. + f single precision float, low bit of 1st word, immediate uses 4 bytes + F double precision float, low bit of 1st word, immediate uses 8 bytes + x extended precision float, low bit of 1st word, immediate uses 12 bytes + p packed float, low bit of 1st word, immediate uses 12 bytes +*/ + +#define one(x) ((x) << 16) +#define two(x, y) (((x) << 16) + y) + +/* + *** DANGER WILL ROBINSON *** + + The assembler requires that all instances of the same mnemonic must be + consecutive. If they aren't, the assembler will bomb at runtime + */ +struct m68k_opcode m68k_opcodes[] = +{ +{"abcd", one(0140400), one(0170770), "DsDd"}, +{"abcd", one(0140410), one(0170770), "-s-d"}, + + /* Add instructions */ +{"addal", one(0150700), one(0170700), "*lAd"}, +{"addaw", one(0150300), one(0170700), "*wAd"}, +{"addib", one(0003000), one(0177700), "#b$b"}, +{"addil", one(0003200), one(0177700), "#l$l"}, +{"addiw", one(0003100), one(0177700), "#w$w"}, +{"addqb", one(0050000), one(0170700), "Qd$b"}, +{"addql", one(0050200), one(0170700), "Qd%l"}, +{"addqw", one(0050100), one(0170700), "Qd%w"}, + +{"addb", one(0050000), one(0170700), "Qd$b"}, /* addq written as add */ +{"addb", one(0003000), one(0177700), "#b$b"}, /* addi written as add */ +{"addb", one(0150000), one(0170700), ";bDd"}, /* addb , Dd */ +{"addb", one(0150400), one(0170700), "Dd~b"}, /* addb Dd, */ + +{"addw", one(0050100), one(0170700), "Qd%w"}, /* addq written as add */ +{"addw", one(0003100), one(0177700), "#w$w"}, /* addi written as add */ +{"addw", one(0150300), one(0170700), "*wAd"}, /* adda written as add */ +{"addw", one(0150100), one(0170700), "*wDd"}, /* addw , Dd */ +{"addw", one(0150500), one(0170700), "Dd~w"}, /* addw Dd, */ + +{"addl", one(0050200), one(0170700), "Qd%l"}, /* addq written as add */ +{"addl", one(0003200), one(0177700), "#l$l"}, /* addi written as add */ +{"addl", one(0150700), one(0170700), "*lAd"}, /* adda written as add */ +{"addl", one(0150200), one(0170700), "*lDd"}, /* addl , Dd */ +{"addl", one(0150600), one(0170700), "Dd~l"}, /* addl Dd, */ + +{"addxb", one(0150400), one(0170770), "DsDd"}, +{"addxb", one(0150410), one(0170770), "-s-d"}, +{"addxl", one(0150600), one(0170770), "DsDd"}, +{"addxl", one(0150610), one(0170770), "-s-d"}, +{"addxw", one(0150500), one(0170770), "DsDd"}, +{"addxw", one(0150510), one(0170770), "-s-d"}, + +{"andib", one(0001000), one(0177700), "#b$b"}, +{"andib", one(0001074), one(0177777), "#bCb"}, /* andi to ccr */ +{"andiw", one(0001100), one(0177700), "#w$w"}, +{"andiw", one(0001174), one(0177777), "#wSw"}, /* andi to sr */ +{"andil", one(0001200), one(0177700), "#l$l"}, + +{"andb", one(0001000), one(0177700), "#b$b"}, /* andi written as or */ +{"andb", one(0001074), one(0177777), "#bCb"}, /* andi to ccr */ +{"andb", one(0140000), one(0170700), ";bDd"}, /* memory to register */ +{"andb", one(0140400), one(0170700), "Dd~b"}, /* register to memory */ +{"andw", one(0001100), one(0177700), "#w$w"}, /* andi written as or */ +{"andw", one(0001174), one(0177777), "#wSw"}, /* andi to sr */ +{"andw", one(0140100), one(0170700), ";wDd"}, /* memory to register */ +{"andw", one(0140500), one(0170700), "Dd~w"}, /* register to memory */ +{"andl", one(0001200), one(0177700), "#l$l"}, /* andi written as or */ +{"andl", one(0140200), one(0170700), ";lDd"}, /* memory to register */ +{"andl", one(0140600), one(0170700), "Dd~l"}, /* register to memory */ + +{"aslb", one(0160400), one(0170770), "QdDs"}, +{"aslb", one(0160440), one(0170770), "DdDs"}, +{"asll", one(0160600), one(0170770), "QdDs"}, +{"asll", one(0160640), one(0170770), "DdDs"}, +{"aslw", one(0160500), one(0170770), "QdDs"}, +{"aslw", one(0160540), one(0170770), "DdDs"}, +{"aslw", one(0160700), one(0177700), "~s"}, /* Shift memory */ +{"asrb", one(0160000), one(0170770), "QdDs"}, +{"asrb", one(0160040), one(0170770), "DdDs"}, +{"asrl", one(0160200), one(0170770), "QdDs"}, +{"asrl", one(0160240), one(0170770), "DdDs"}, +{"asrw", one(0160100), one(0170770), "QdDs"}, +{"asrw", one(0160140), one(0170770), "DdDs"}, +{"asrw", one(0160300), one(0177700), "~s"}, /* Shift memory */ + +{"bhi", one(0061000), one(0177400), "Bg"}, +{"bls", one(0061400), one(0177400), "Bg"}, +{"bcc", one(0062000), one(0177400), "Bg"}, +{"bcs", one(0062400), one(0177400), "Bg"}, +{"bne", one(0063000), one(0177400), "Bg"}, +{"beq", one(0063400), one(0177400), "Bg"}, +{"bvc", one(0064000), one(0177400), "Bg"}, +{"bvs", one(0064400), one(0177400), "Bg"}, +{"bpl", one(0065000), one(0177400), "Bg"}, +{"bmi", one(0065400), one(0177400), "Bg"}, +{"bge", one(0066000), one(0177400), "Bg"}, +{"blt", one(0066400), one(0177400), "Bg"}, +{"bgt", one(0067000), one(0177400), "Bg"}, +{"ble", one(0067400), one(0177400), "Bg"}, + +{"bchg", one(0000500), one(0170700), "Dd$s"}, +{"bchg", one(0004100), one(0177700), "#b$s"}, +{"bclr", one(0000600), one(0170700), "Dd$s"}, +{"bclr", one(0004200), one(0177700), "#b$s"}, +{"bfchg", two(0165300, 0), two(0177700, 0170000), "?sO2O3"}, +{"bfclr", two(0166300, 0), two(0177700, 0170000), "?sO2O3"}, +{"bfexts", two(0165700, 0), two(0177700, 0100000), "/sO2O3D1"}, +{"bfextu", two(0164700, 0), two(0177700, 0100000), "/sO2O3D1"}, +{"bfffo", two(0166700, 0), two(0177700, 0100000), "/sO2O3D1"}, +{"bfins", two(0167700, 0), two(0177700, 0100000), "D1?sO2O3"}, +{"bfset", two(0167300, 0), two(0177700, 0170000), "?sO2O3"}, +{"bftst", two(0164300, 0), two(0177700, 0170000), "/sO2O3"}, +{"bset", one(0000700), one(0170700), "Dd$s"}, +{"bset", one(0004300), one(0177700), "#b$s"}, +{"btst", one(0000400), one(0170700), "Dd@s"}, +{"btst", one(0004000), one(0177700), "#b@s"}, + +{"bkpt", one(0044110), one(0177770), "Qs"}, +{"bra", one(0060000), one(0177400), "Bg"}, +{"bras", one(0060000), one(0177400), "Bw"}, +{"bsr", one(0060400), one(0177400), "Bg"}, +{"bsrs", one(0060400), one(0177400), "Bw"}, + +{"callm", one(0003300), one(0177700), "#b!s"}, +{"cas2l", two(0007374, 0), two(0177777, 0107070), "D3D6D2D5R1R4"}, /* JF FOO this is really a 3 word ins */ +{"cas2w", two(0006374, 0), two(0177777, 0107070), "D3D6D2D5R1R4"}, /* JF ditto */ +{"casb", two(0005300, 0), two(0177700, 0177070), "D3D2~s"}, +{"casl", two(0007300, 0), two(0177700, 0177070), "D3D2~s"}, +{"casw", two(0006300, 0), two(0177700, 0177070), "D3D2~s"}, + +/* {"chk", one(0040600), one(0170700), ";wDd"}, JF FOO this looks wrong */ +{"chk2b", two(0000300, 0004000), two(0177700, 07777), "!sR1"}, +{"chk2l", two(0002300, 0004000), two(0177700, 07777), "!sR1"}, +{"chk2w", two(0001300, 0004000), two(0177700, 07777), "!sR1"}, +{"chkl", one(0040400), one(0170700), ";lDd"}, +{"chkw", one(0040600), one(0170700), ";wDd"}, +{"clrb", one(0041000), one(0177700), "$s"}, +{"clrl", one(0041200), one(0177700), "$s"}, +{"clrw", one(0041100), one(0177700), "$s"}, + +{"cmp2b", two(0000300, 0), two(0177700, 07777), "!sR1"}, +{"cmp2l", two(0002300, 0), two(0177700, 07777), "!sR1"}, +{"cmp2w", two(0001300, 0), two(0177700, 07777), "!sR1"}, +{"cmpal", one(0130700), one(0170700), "*lAd"}, +{"cmpaw", one(0130300), one(0170700), "*wAd"}, +{"cmpib", one(0006000), one(0177700), "#b;b"}, +{"cmpil", one(0006200), one(0177700), "#l;l"}, +{"cmpiw", one(0006100), one(0177700), "#w;w"}, +{"cmpb", one(0006000), one(0177700), "#b;b"}, /* cmpi written as cmp */ +{"cmpb", one(0130000), one(0170700), ";bDd"}, +{"cmpw", one(0006100), one(0177700), "#w;w"}, +{"cmpw", one(0130100), one(0170700), "*wDd"}, +{"cmpw", one(0130300), one(0170700), "*wAd"}, /* cmpa written as cmp */ +{"cmpl", one(0006200), one(0177700), "#l;l"}, +{"cmpl", one(0130200), one(0170700), "*lDd"}, +{"cmpl", one(0130700), one(0170700), "*lAd"}, +{"cmpmb", one(0130410), one(0170770), "+s+d"}, +{"cmpml", one(0130610), one(0170770), "+s+d"}, +{"cmpmw", one(0130510), one(0170770), "+s+d"}, + +{"dbcc", one(0052310), one(0177770), "DsBw"}, +{"dbcs", one(0052710), one(0177770), "DsBw"}, +{"dbeq", one(0053710), one(0177770), "DsBw"}, +{"dbf", one(0050710), one(0177770), "DsBw"}, +{"dbge", one(0056310), one(0177770), "DsBw"}, +{"dbgt", one(0057310), one(0177770), "DsBw"}, +{"dbhi", one(0051310), one(0177770), "DsBw"}, +{"dble", one(0057710), one(0177770), "DsBw"}, +{"dbls", one(0051710), one(0177770), "DsBw"}, +{"dblt", one(0056710), one(0177770), "DsBw"}, +{"dbmi", one(0055710), one(0177770), "DsBw"}, +{"dbne", one(0053310), one(0177770), "DsBw"}, +{"dbpl", one(0055310), one(0177770), "DsBw"}, +{"dbra", one(0050710), one(0177770), "DsBw"}, +{"dbt", one(0050310), one(0177770), "DsBw"}, +{"dbvc", one(0054310), one(0177770), "DsBw"}, +{"dbvs", one(0054710), one(0177770), "DsBw"}, + +{"divsl", two(0046100, 0006000), two(0177700, 0107770), ";lD3D1"}, +{"divsl", two(0046100, 0004000), two(0177700, 0107770), ";lDD"}, +{"divsll", two(0046100, 0004000), two(0177700, 0107770), ";lD3D1"}, +{"divsw", one(0100700), one(0170700), ";wDd"}, +{"divs", one(0100700), one(0170700), ";wDd"}, +{"divul", two(0046100, 0002000), two(0177700, 0107770), ";lD3D1"}, +{"divul", two(0046100, 0000000), two(0177700, 0107770), ";lDD"}, +{"divull", two(0046100, 0000000), two(0177700, 0107770), ";lD3D1"}, +{"divuw", one(0100300), one(0170700), ";wDd"}, +{"divu", one(0100300), one(0170700), ";wDd"}, +{"eorb", one(0005000), one(0177700), "#b$s"}, /* eori written as or */ +{"eorb", one(0005074), one(0177777), "#bCs"}, /* eori to ccr */ +{"eorb", one(0130400), one(0170700), "Dd$s"}, /* register to memory */ +{"eorib", one(0005000), one(0177700), "#b$s"}, +{"eorib", one(0005074), one(0177777), "#bCs"}, /* eori to ccr */ +{"eoril", one(0005200), one(0177700), "#l$s"}, +{"eoriw", one(0005100), one(0177700), "#w$s"}, +{"eoriw", one(0005174), one(0177777), "#wSs"}, /* eori to sr */ +{"eorl", one(0005200), one(0177700), "#l$s"}, +{"eorl", one(0130600), one(0170700), "Dd$s"}, +{"eorw", one(0005100), one(0177700), "#w$s"}, +{"eorw", one(0005174), one(0177777), "#wSs"}, /* eori to sr */ +{"eorw", one(0130500), one(0170700), "Dd$s"}, + +{"exg", one(0140500), one(0170770), "DdDs"}, +{"exg", one(0140510), one(0170770), "AdAs"}, +{"exg", one(0140610), one(0170770), "DdAs"}, +{"exg", one(0140610), one(0170770), "AsDd"}, + +{"extw", one(0044200), one(0177770), "Ds"}, +{"extl", one(0044300), one(0177770), "Ds"}, +{"extbl", one(0044700), one(0177770), "Ds"}, +{"extb.l", one(0044700), one(0177770), "Ds"}, /* Not sure we should support this one*/ + +{"illegal", one(0045374), one(0177777), ""}, +{"jmp", one(0047300), one(0177700), "!s"}, +{"jsr", one(0047200), one(0177700), "!s"}, +{"lea", one(0040700), one(0170700), "!sAd"}, +{"linkw", one(0047120), one(0177770), "As#w"}, +{"linkl", one(0044010), one(0177770), "As#l"}, +{"link", one(0047120), one(0177770), "As#w"}, +{"link", one(0044010), one(0177770), "As#l"}, + +{"lslb", one(0160410), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lslb", one(0160450), one(0170770), "DdDs"}, /* lsrb Dd, Ds */ +{"lslw", one(0160510), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lslw", one(0160550), one(0170770), "DdDs"}, /* lsrb Dd, Ds */ +{"lslw", one(0161700), one(0177700), "~s"}, /* Shift memory */ +{"lsll", one(0160610), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lsll", one(0160650), one(0170770), "DdDs"}, /* lsrb Dd, Ds */ + +{"lsrb", one(0160010), one(0170770), "QdDs"} /* lsrb #Q, Ds */, +{"lsrb", one(0160050), one(0170770), "DdDs"}, /* lsrb Dd, Ds */ +{"lsrl", one(0160210), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lsrl", one(0160250), one(0170770), "DdDs"}, /* lsrb #Q, Ds */ +{"lsrw", one(0160110), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lsrw", one(0160150), one(0170770), "DdDs"}, /* lsrb #Q, Ds */ +{"lsrw", one(0161300), one(0177700), "~s"}, /* Shift memory */ + +{"moveal", one(0020100), one(0170700), "*lAd"}, +{"moveaw", one(0030100), one(0170700), "*wAd"}, +{"moveb", one(0010000), one(0170000), ";b$d"}, /* move */ +{"movel", one(0070000), one(0170400), "MsDd"}, /* moveq written as move */ +{"movel", one(0020000), one(0170000), "*l$d"}, +{"movel", one(0020100), one(0170700), "*lAd"}, +{"movel", one(0047140), one(0177770), "AsUd"}, /* move to USP */ +{"movel", one(0047150), one(0177770), "UdAs"}, /* move from USP */ + +{"movec", one(0047173), one(0177777), "R1Jj"}, +{"movec", one(0047173), one(0177777), "R1#j"}, +{"movec", one(0047172), one(0177777), "JjR1"}, +{"movec", one(0047172), one(0177777), "#jR1"}, + +/* JF added these next four for the assembler */ +{"moveml", one(0044300), one(0177700), "Lw&s"}, /* movem reg to mem. */ +{"moveml", one(0044340), one(0177770), "lw-s"}, /* movem reg to autodecrement. */ +{"moveml", one(0046300), one(0177700), "!sLw"}, /* movem mem to reg. */ +{"moveml", one(0046330), one(0177770), "+sLw"}, /* movem autoinc to reg. */ + +{"moveml", one(0044300), one(0177700), "#w&s"}, /* movem reg to mem. */ +{"moveml", one(0044340), one(0177770), "#w-s"}, /* movem reg to autodecrement. */ +{"moveml", one(0046300), one(0177700), "!s#w"}, /* movem mem to reg. */ +{"moveml", one(0046330), one(0177770), "+s#w"}, /* movem autoinc to reg. */ + +/* JF added these next four for the assembler */ +{"movemw", one(0044200), one(0177700), "Lw&s"}, /* movem reg to mem. */ +{"movemw", one(0044240), one(0177770), "lw-s"}, /* movem reg to autodecrement. */ +{"movemw", one(0046200), one(0177700), "!sLw"}, /* movem mem to reg. */ +{"movemw", one(0046230), one(0177770), "+sLw"}, /* movem autoinc to reg. */ + +{"movemw", one(0044200), one(0177700), "#w&s"}, /* movem reg to mem. */ +{"movemw", one(0044240), one(0177770), "#w-s"}, /* movem reg to autodecrement. */ +{"movemw", one(0046200), one(0177700), "!s#w"}, /* movem mem to reg. */ +{"movemw", one(0046230), one(0177770), "+s#w"}, /* movem autoinc to reg. */ + +{"movepl", one(0000510), one(0170770), "dsDd"}, /* memory to register */ +{"movepl", one(0000710), one(0170770), "Ddds"}, /* register to memory */ +{"movepw", one(0000410), one(0170770), "dsDd"}, /* memory to register */ +{"movepw", one(0000610), one(0170770), "Ddds"}, /* register to memory */ +{"moveq", one(0070000), one(0170400), "MsDd"}, +{"movew", one(0030000), one(0170000), "*w$d"}, +{"movew", one(0030100), one(0170700), "*wAd"}, /* movea, written as move */ +{"movew", one(0040300), one(0177700), "Ss$s"}, /* Move from sr */ +{"movew", one(0041300), one(0177700), "Cs$s"}, /* Move from ccr */ +{"movew", one(0042300), one(0177700), ";wCd"}, /* move to ccr */ +{"movew", one(0043300), one(0177700), ";wSd"}, /* move to sr */ + +{"movesb", two(0007000, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */ +{"movesb", two(0007000, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */ +{"movesl", two(0007200, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */ +{"movesl", two(0007200, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */ +{"movesw", two(0007100, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */ +{"movesw", two(0007100, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */ + +{"mulsl", two(0046000, 004000), two(0177700, 0107770), ";lD1"}, +{"mulsl", two(0046000, 006000), two(0177700, 0107770), ";lD3D1"}, +{"mulsw", one(0140700), one(0170700), ";wDd"}, +{"muls", one(0140700), one(0170700), ";wDd"}, +{"mulul", two(0046000, 000000), two(0177700, 0107770), ";lD1"}, +{"mulul", two(0046000, 002000), two(0177700, 0107770), ";lD3D1"}, +{"muluw", one(0140300), one(0170700), ";wDd"}, +{"mulu", one(0140300), one(0170700), ";wDd"}, +{"nbcd", one(0044000), one(0177700), "$s"}, +{"negb", one(0042000), one(0177700), "$s"}, +{"negl", one(0042200), one(0177700), "$s"}, +{"negw", one(0042100), one(0177700), "$s"}, +{"negxb", one(0040000), one(0177700), "$s"}, +{"negxl", one(0040200), one(0177700), "$s"}, +{"negxw", one(0040100), one(0177700), "$s"}, +{"nop", one(0047161), one(0177777), ""}, +{"notb", one(0043000), one(0177700), "$s"}, +{"notl", one(0043200), one(0177700), "$s"}, +{"notw", one(0043100), one(0177700), "$s"}, + +{"orb", one(0000000), one(0177700), "#b$s"}, /* ori written as or */ +{"orb", one(0000074), one(0177777), "#bCs"}, /* ori to ccr */ +{"orb", one(0100000), one(0170700), ";bDd"}, /* memory to register */ +{"orb", one(0100400), one(0170700), "Dd~s"}, /* register to memory */ +{"orib", one(0000000), one(0177700), "#b$s"}, +{"orib", one(0000074), one(0177777), "#bCs"}, /* ori to ccr */ +{"oril", one(0000200), one(0177700), "#l$s"}, +{"oriw", one(0000100), one(0177700), "#w$s"}, +{"oriw", one(0000174), one(0177777), "#wSs"}, /* ori to sr */ +{"orl", one(0000200), one(0177700), "#l$s"}, +{"orl", one(0100200), one(0170700), ";lDd"}, /* memory to register */ +{"orl", one(0100600), one(0170700), "Dd~s"}, /* register to memory */ +{"orw", one(0000100), one(0177700), "#w$s"}, +{"orw", one(0000174), one(0177777), "#wSs"}, /* ori to sr */ +{"orw", one(0100100), one(0170700), ";wDd"}, /* memory to register */ +{"orw", one(0100500), one(0170700), "Dd~s"}, /* register to memory */ + +{"pack", one(0100500), one(0170770), "DsDd#w"}, /* pack Ds, Dd, #w */ +{"pack", one(0100510), one(0170770), "-s-d#w"}, /* pack -(As), -(Ad), #w */ +{"pea", one(0044100), one(0177700), "!s"}, +{"reset", one(0047160), one(0177777), ""}, + +{"rolb", one(0160430), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rolb", one(0160470), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"roll", one(0160630), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"roll", one(0160670), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rolw", one(0160530), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rolw", one(0160570), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rolw", one(0163700), one(0177700), "~s"}, /* Rotate memory */ +{"rorb", one(0160030), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rorb", one(0160070), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rorl", one(0160230), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rorl", one(0160270), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rorw", one(0160130), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rorw", one(0160170), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rorw", one(0163300), one(0177700), "~s"}, /* Rotate memory */ + +{"roxlb", one(0160420), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxlb", one(0160460), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxll", one(0160620), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxll", one(0160660), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxlw", one(0160520), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxlw", one(0160560), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxlw", one(0162700), one(0177700), "~s"}, /* Rotate memory */ +{"roxrb", one(0160020), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxrb", one(0160060), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxrl", one(0160220), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxrl", one(0160260), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxrw", one(0160120), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxrw", one(0160160), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxrw", one(0162300), one(0177700), "~s"}, /* Rotate memory */ + +{"rtd", one(0047164), one(0177777), "#w"}, +{"rte", one(0047163), one(0177777), ""}, +{"rtm", one(0003300), one(0177760), "Rs"}, +{"rtr", one(0047167), one(0177777), ""}, +{"rts", one(0047165), one(0177777), ""}, + +{"scc", one(0052300), one(0177700), "$s"}, +{"scs", one(0052700), one(0177700), "$s"}, +{"seq", one(0053700), one(0177700), "$s"}, +{"sf", one(0050700), one(0177700), "$s"}, +{"sge", one(0056300), one(0177700), "$s"}, +{"sgt", one(0057300), one(0177700), "$s"}, +{"shi", one(0051300), one(0177700), "$s"}, +{"sle", one(0057700), one(0177700), "$s"}, +{"sls", one(0051700), one(0177700), "$s"}, +{"slt", one(0056700), one(0177700), "$s"}, +{"smi", one(0055700), one(0177700), "$s"}, +{"sne", one(0053300), one(0177700), "$s"}, +{"spl", one(0055300), one(0177700), "$s"}, +{"st", one(0050300), one(0177700), "$s"}, +{"svc", one(0054300), one(0177700), "$s"}, +{"svs", one(0054700), one(0177700), "$s"}, + +{"sbcd", one(0100400), one(0170770), "DsDd"}, +{"sbcd", one(0100410), one(0170770), "-s-d"}, +{"stop", one(0047162), one(0177777), "#w"}, + +{"subal", one(0110700), one(0170700), "*lAd"}, +{"subaw", one(0110300), one(0170700), "*wAd"}, +{"subb", one(0050400), one(0170700), "Qd%s"}, /* subq written as sub */ +{"subb", one(0002000), one(0177700), "#b$s"}, /* subi written as sub */ +{"subb", one(0110000), one(0170700), ";bDd"}, /* subb ? ?, Dd */ +{"subb", one(0110400), one(0170700), "Dd~s"}, /* subb Dd, ? ? */ +{"subib", one(0002000), one(0177700), "#b$s"}, +{"subil", one(0002200), one(0177700), "#l$s"}, +{"subiw", one(0002100), one(0177700), "#w$s"}, +{"subl", one(0050600), one(0170700), "Qd%s"}, +{"subl", one(0002200), one(0177700), "#l$s"}, +{"subl", one(0110700), one(0170700), "*lAd"}, +{"subl", one(0110200), one(0170700), "*lDd"}, +{"subl", one(0110600), one(0170700), "Dd~s"}, +{"subqb", one(0050400), one(0170700), "Qd%s"}, +{"subql", one(0050600), one(0170700), "Qd%s"}, +{"subqw", one(0050500), one(0170700), "Qd%s"}, +{"subw", one(0050500), one(0170700), "Qd%s"}, +{"subw", one(0002100), one(0177700), "#w$s"}, +{"subw", one(0110100), one(0170700), "*wDd"}, +{"subw", one(0110300), one(0170700), "*wAd"}, /* suba written as sub */ +{"subw", one(0110500), one(0170700), "Dd~s"}, +{"subxb", one(0110400), one(0170770), "DsDd"}, /* subxb Ds, Dd */ +{"subxb", one(0110410), one(0170770), "-s-d"}, /* subxb -(As), -(Ad) */ +{"subxl", one(0110600), one(0170770), "DsDd"}, +{"subxl", one(0110610), one(0170770), "-s-d"}, +{"subxw", one(0110500), one(0170770), "DsDd"}, +{"subxw", one(0110510), one(0170770), "-s-d"}, + +{"swap", one(0044100), one(0177770), "Ds"}, + +{"tas", one(0045300), one(0177700), "$s"}, +{"trap", one(0047100), one(0177760), "Ts"}, + +{"trapcc", one(0052374), one(0177777), ""}, +{"trapcs", one(0052774), one(0177777), ""}, +{"trapeq", one(0053774), one(0177777), ""}, +{"trapf", one(0050774), one(0177777), ""}, +{"trapge", one(0056374), one(0177777), ""}, +{"trapgt", one(0057374), one(0177777), ""}, +{"traphi", one(0051374), one(0177777), ""}, +{"traple", one(0057774), one(0177777), ""}, +{"trapls", one(0051774), one(0177777), ""}, +{"traplt", one(0056774), one(0177777), ""}, +{"trapmi", one(0055774), one(0177777), ""}, +{"trapne", one(0053374), one(0177777), ""}, +{"trappl", one(0055374), one(0177777), ""}, +{"trapt", one(0050374), one(0177777), ""}, +{"trapvc", one(0054374), one(0177777), ""}, +{"trapvs", one(0054774), one(0177777), ""}, + +{"trapcc.w", one(0052372), one(0177777), ""}, +{"trapcs.w", one(0052772), one(0177777), ""}, +{"trapeq.w", one(0053772), one(0177777), ""}, +{"trapf.w", one(0050772), one(0177777), ""}, +{"trapge.w", one(0056372), one(0177777), ""}, +{"trapgt.w", one(0057372), one(0177777), ""}, +{"traphi.w", one(0051372), one(0177777), ""}, +{"traple.w", one(0057772), one(0177777), ""}, +{"trapls.w", one(0051772), one(0177777), ""}, +{"traplt.w", one(0056772), one(0177777), ""}, +{"trapmi.w", one(0055772), one(0177777), ""}, +{"trapne.w", one(0053372), one(0177777), ""}, +{"trappl.w", one(0055372), one(0177777), ""}, +{"trapt.w", one(0050372), one(0177777), ""}, +{"trapvc.w", one(0054372), one(0177777), ""}, +{"trapvs.w", one(0054772), one(0177777), ""}, + +{"trapcc.l", one(0052373), one(0177777), ""}, +{"trapcs.l", one(0052773), one(0177777), ""}, +{"trapeq.l", one(0053773), one(0177777), ""}, +{"trapf.l", one(0050773), one(0177777), ""}, +{"trapge.l", one(0056373), one(0177777), ""}, +{"trapgt.l", one(0057373), one(0177777), ""}, +{"traphi.l", one(0051373), one(0177777), ""}, +{"traple.l", one(0057773), one(0177777), ""}, +{"trapls.l", one(0051773), one(0177777), ""}, +{"traplt.l", one(0056773), one(0177777), ""}, +{"trapmi.l", one(0055773), one(0177777), ""}, +{"trapne.l", one(0053373), one(0177777), ""}, +{"trappl.l", one(0055373), one(0177777), ""}, +{"trapt.l", one(0050373), one(0177777), ""}, +{"trapvc.l", one(0054373), one(0177777), ""}, +{"trapvs.l", one(0054773), one(0177777), ""}, + +{"trapv", one(0047166), one(0177777), ""}, + +{"tstb", one(0045000), one(0177700), ";b"}, +{"tstw", one(0045100), one(0177700), "*w"}, +{"tstl", one(0045200), one(0177700), "*l"}, + +{"unlk", one(0047130), one(0177770), "As"}, +{"unpk", one(0100600), one(0170770), "DsDd#w"}, +{"unpk", one(0100610), one(0170770), "-s-d#w"}, + /* JF floating pt stuff moved down here */ + +{"fabsb", two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fabsd", two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fabsl", two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fabsp", two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fabss", two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fabsw", two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fabsx", two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt"}, + +{"facosb", two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"facosd", two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"facosl", two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"facosp", two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"facoss", two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"facosw", two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"facosx", two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt"}, + +{"faddb", two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"faddd", two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"faddl", two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"faddp", two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fadds", two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"faddw", two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"faddx", two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +/* {"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiFt"}, JF removed */ + +{"fasinb", two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fasind", two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fasinl", two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fasinp", two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fasins", two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fasinw", two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fasinx", two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fatanb", two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fatand", two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fatanl", two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fatanp", two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fatans", two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fatanw", two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fatanx", two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fatanhb", two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fatanhd", two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fatanhl", two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fatanhp", two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fatanhs", two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fatanhw", two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fatanhx", two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fbeq", one(0xF081), one(0xF1BF), "IdBc"}, +{"fbf", one(0xF080), one(0xF1BF), "IdBc"}, +{"fbge", one(0xF093), one(0xF1BF), "IdBc"}, +{"fbgl", one(0xF096), one(0xF1BF), "IdBc"}, +{"fbgle", one(0xF097), one(0xF1BF), "IdBc"}, +{"fbgt", one(0xF092), one(0xF1BF), "IdBc"}, +{"fble", one(0xF095), one(0xF1BF), "IdBc"}, +{"fblt", one(0xF094), one(0xF1BF), "IdBc"}, +{"fbne", one(0xF08E), one(0xF1BF), "IdBc"}, +{"fbnge", one(0xF09C), one(0xF1BF), "IdBc"}, +{"fbngl", one(0xF099), one(0xF1BF), "IdBc"}, +{"fbngle", one(0xF098), one(0xF1BF), "IdBc"}, +{"fbngt", one(0xF09D), one(0xF1BF), "IdBc"}, +{"fbnle", one(0xF09A), one(0xF1BF), "IdBc"}, +{"fbnlt", one(0xF09B), one(0xF1BF), "IdBc"}, +{"fboge", one(0xF083), one(0xF1BF), "IdBc"}, +{"fbogl", one(0xF086), one(0xF1BF), "IdBc"}, +{"fbogt", one(0xF082), one(0xF1BF), "IdBc"}, +{"fbole", one(0xF085), one(0xF1BF), "IdBc"}, +{"fbolt", one(0xF084), one(0xF1BF), "IdBc"}, +{"fbor", one(0xF087), one(0xF1BF), "IdBc"}, +{"fbseq", one(0xF091), one(0xF1BF), "IdBc"}, +{"fbsf", one(0xF090), one(0xF1BF), "IdBc"}, +{"fbsne", one(0xF09E), one(0xF1BF), "IdBc"}, +{"fbst", one(0xF09F), one(0xF1BF), "IdBc"}, +{"fbt", one(0xF08F), one(0xF1BF), "IdBc"}, +{"fbueq", one(0xF089), one(0xF1BF), "IdBc"}, +{"fbuge", one(0xF08B), one(0xF1BF), "IdBc"}, +{"fbugt", one(0xF08A), one(0xF1BF), "IdBc"}, +{"fbule", one(0xF08D), one(0xF1BF), "IdBc"}, +{"fbult", one(0xF08C), one(0xF1BF), "IdBc"}, +{"fbun", one(0xF088), one(0xF1BF), "IdBc"}, + +{"fcmpb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fcmpd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fcmpl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fcmpp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fcmps", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fcmpw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fcmpx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +/* {"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiFt"}, JF removed */ + +{"fcosb", two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fcosd", two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fcosl", two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fcosp", two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fcoss", two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fcosw", two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fcosx", two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fcoshb", two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fcoshd", two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fcoshl", two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fcoshp", two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fcoshs", two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fcoshw", two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fcoshx", two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fdbeq", two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbf", two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbge", two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbgl", two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbgle", two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbgt", two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdble", two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdblt", two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbne", two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbnge", two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbngl", two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbngle", two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbngt", two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbnle", two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbnlt", two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdboge", two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbogl", two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbogt", two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbole", two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbolt", two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbor", two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbseq", two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbsf", two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbsne", two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbst", two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbt", two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbueq", two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbuge", two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbugt", two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbule", two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbult", two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbun", two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw"}, + +{"fdivb", two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fdivd", two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fdivl", two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fdivp", two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fdivs", two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fdivw", two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fdivx", two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +/* {"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiFt"}, JF */ + +{"fetoxb", two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fetoxd", two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fetoxl", two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fetoxp", two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fetoxs", two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fetoxw", two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fetoxx", two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fetoxm1b", two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fetoxm1d", two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fetoxm1l", two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fetoxm1p", two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fetoxm1s", two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fetoxm1w", two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fetoxm1x", two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fgetexpb", two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fgetexpd", two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fgetexpl", two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fgetexpp", two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fgetexps", two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fgetexpw", two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fgetexpx", two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fgetmanb", two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fgetmand", two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fgetmanl", two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fgetmanp", two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fgetmans", two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fgetmanw", two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fgetmanx", two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fintb", two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fintd", two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fintl", two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fintp", two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fints", two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fintw", two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fintx", two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fintrzb", two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fintrzd", two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fintrzl", two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fintrzp", two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fintrzs", two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fintrzw", two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fintrzx", two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt"}, + +{"flog10b", two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"flog10d", two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"flog10l", two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"flog10p", two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"flog10s", two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"flog10w", two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"flog10x", two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt"}, + +{"flog2b", two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"flog2d", two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"flog2l", two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"flog2p", two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"flog2s", two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"flog2w", two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"flog2x", two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt"}, + +{"flognb", two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"flognd", two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"flognl", two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"flognp", two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"flogns", two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"flognw", two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"flognx", two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt"}, + +{"flognp1b", two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"flognp1d", two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"flognp1l", two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"flognp1p", two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"flognp1s", two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"flognp1w", two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"flognp1x", two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fmodb", two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fmodd", two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fmodl", two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fmodp", two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fmods", two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fmodw", two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fmodx", two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +/* {"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiFt"}, JF */ + +{"fmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7"}, /* fmove from to fp */ +{"fmoveb", two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7@b"}, /* fmove from fp to */ +{"fmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7"}, /* fmove from to fp */ +{"fmoved", two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7@F"}, /* fmove from fp to */ +{"fmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7"}, /* fmove from to fp */ +{"fmovel", two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7@l"}, /* fmove from fp to */ +/* Warning: The addressing modes on these are probably not right: + esp, Areg direct is only allowed for FPI */ + /* fmove.l from/to system control registers: */ +{"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"}, +{"fmovel", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8"}, + +/* {"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"}, +{"fmovel", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*ss8"}, */ + +{"fmovep", two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7"}, /* fmove from to fp */ +{"fmovep", two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7@pkC"}, /* fmove.p with k-factors: */ +{"fmovep", two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7@pDk"}, /* fmove.p with k-factors: */ + +{"fmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7"}, /* fmove from to fp */ +{"fmoves", two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7@f"}, /* fmove from fp to */ +{"fmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7"}, /* fmove from to fp */ +{"fmovew", two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7@w"}, /* fmove from fp to */ +{"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7"}, /* fmove from to fp */ +{"fmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7"}, /* fmove from to fp */ +{"fmovex", two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7@x"}, /* fmove from fp to */ +/* JF removed {"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiFt"}, / * fmove from to fp */ + +{"fmovecrx", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7"}, /* fmovecr.x #ccc, FPn */ +{"fmovecr", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7"}, + +/* Other fmovemx. */ +{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s"}, /* fmovem.x to autodecrement, static and dynamic */ +{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s"}, /* fmovem.x to autodecrement, static and dynamic */ + +{"fmovemx", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s"}, /* fmovem.x to autodecrement, static and dynamic */ + +{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s"}, /* fmovem.x to control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s"}, /* fmovem.x to control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3"}, /* fmovem.x from control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk"}, /* fmovem.x from control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s"}, /* fmovem.x to control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3"}, /* fmovem.x from control, static and dynamic: */ + +{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3"}, /* fmovem.x from autoincrement, static and dynamic: */ +{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3"}, /* fmovem.x from autoincrement, static and dynamic: */ +{"fmovemx", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk"}, /* fmovem.x from autoincrement, static and dynamic: */ + +{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8@s"}, +{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Ii#8@s"}, +{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"}, + +{"fmoveml", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8"}, +{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*s#8"}, +{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8"}, + +/* fmovemx with register lists */ +{"fmovem", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s"}, /* fmovem.x to autodecrement, static and dynamic */ +{"fmovem", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s"}, /* fmovem.x to control, static and dynamic: */ +{"fmovem", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3"}, /* fmovem.x from autoincrement, static and dynamic: */ +{"fmovem", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3"}, /* fmovem.x from control, static and dynamic: */ + + /* Alternate mnemonics for GNU as and GNU CC */ +{"fmovem", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s"}, /* fmovem.x to autodecrement, static and dynamic */ +{"fmovem", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s"}, /* fmovem.x to autodecrement, static and dynamic */ + +{"fmovem", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s"}, /* fmovem.x to control, static and dynamic: */ +{"fmovem", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s"}, /* fmovem.x to control, static and dynamic: */ + +{"fmovem", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3"}, /* fmovem.x from autoincrement, static and dynamic: */ +{"fmovem", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk"}, /* fmovem.x from autoincrement, static and dynamic: */ + +{"fmovem", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3"}, /* fmovem.x from control, static and dynamic: */ +{"fmovem", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk"}, /* fmovem.x from control, static and dynamic: */ + +/* fmoveml a FP-control register */ +{"fmovem", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"}, +{"fmovem", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8"}, + +/* fmoveml a FP-control reglist */ +{"fmovem", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8@s"}, +{"fmovem", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8"}, + +{"fmulb", two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fmuld", two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fmull", two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fmulp", two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fmuls", two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fmulw", two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fmulx", two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +/* {"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiFt"}, JF */ + +{"fnegb", two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fnegd", two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fnegl", two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fnegp", two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fnegs", two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fnegw", two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fnegx", two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fnop", two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii"}, + +{"fremb", two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fremd", two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"freml", two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fremp", two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"frems", two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fremw", two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fremx", two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +/* {"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiFt"}, JF */ + +{"frestore", one(0xF140), one(0xF1C0), "Id&s"}, +{"frestore", one(0xF158), one(0xF1F8), "Id+s"}, +{"fsave", one(0xF100), one(0xF1C0), "Id&s"}, +{"fsave", one(0xF120), one(0xF1F8), "Id-s"}, + +{"fsincosb", two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF7FC"}, +{"fsincosd", two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF7FC"}, +{"fsincosl", two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF7FC"}, +{"fsincosp", two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF7FC"}, +{"fsincoss", two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF7FC"}, +{"fsincosw", two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF7FC"}, +{"fsincosx", two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F7FC"}, +{"fsincosx", two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF7FC"}, + +{"fscaleb", two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fscaled", two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fscalel", two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fscalep", two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fscales", two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fscalew", two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fscalex", two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +/* {"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiFt"}, JF */ + +/* $ is necessary to prevent the assembler from using PC-relative. + If @ were used, "label: fseq label" could produce "ftrapeq", + because "label" became "pc@label". */ +{"fseq", two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsf", two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsge", two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsgl", two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsgle", two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsgt", two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsle", two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fslt", two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsne", two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsnge", two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsngl", two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsngle", two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsngt", two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsnle", two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsnlt", two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsoge", two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsogl", two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsogt", two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsole", two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsolt", two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsor", two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsseq", two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fssf", two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fssne", two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsst", two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fst", two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsueq", two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsuge", two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsugt", two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsule", two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsult", two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s"}, +{"fsun", two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s"}, + +{"fsgldivb", two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsgldivd", two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsgldivl", two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsgldivp", two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsgldivs", two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsgldivw", two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsgldivx", two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fsglmulb", two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsglmuld", two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsglmull", two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsglmulp", two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsglmuls", two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsglmulw", two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsglmulx", two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fsinb", two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsind", two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsinl", two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsinp", two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsins", two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsinw", two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsinx", two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fsinhb", two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsinhd", two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsinhl", two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsinhp", two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsinhs", two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsinhw", two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsinhx", two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fsqrtb", two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsqrtd", two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsqrtl", two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsqrtp", two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsqrts", two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsqrtw", two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsqrtx", two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fsubb", two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsubd", two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsubl", two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsubp", two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsubs", two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsubw", two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsubx", two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt"}, + +{"ftanb", two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"ftand", two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"ftanl", two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"ftanp", two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"ftans", two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"ftanw", two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"ftanx", two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt"}, + +{"ftanhb", two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"ftanhd", two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"ftanhl", two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"ftanhp", two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"ftanhs", two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"ftanhw", two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"ftanhx", two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt"}, + +{"ftentoxb", two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"ftentoxd", two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"ftentoxl", two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"ftentoxp", two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"ftentoxs", two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"ftentoxw", two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"ftentoxx", two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt"}, + +{"ftrapeq", two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapf", two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapge", two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapgl", two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapgle", two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapgt", two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftraple", two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftraplt", two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapne", two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapnge", two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapngl", two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapngle", two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapngt", two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapnle", two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapnlt", two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapoge", two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapogl", two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapogt", two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapole", two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapolt", two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapor", two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapseq", two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapsf", two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapsne", two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapst", two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapt", two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapueq", two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapuge", two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapugt", two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapule", two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapult", two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapun", two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii"}, + +{"ftrapeqw", two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapfw", two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapgew", two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapglw", two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapglew", two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapgtw", two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftraplew", two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapltw", two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnew", two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapngew", two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnglw", two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnglew", two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapngtw", two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnlew", two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnltw", two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapogew", two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapoglw", two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapogtw", two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapolew", two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapoltw", two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftraporw", two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapseqw", two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapsfw", two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapsnew", two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapstw", two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftraptw", two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapueqw", two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapugew", two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapugtw", two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapulew", two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapultw", two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapunw", two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w"}, + +{"ftrapeql", two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapfl", two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapgel", two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapgll", two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapglel", two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapgtl", two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftraplel", two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapltl", two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapnel", two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapngel", two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapngll", two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapnglel", two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapngtl", two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapnlel", two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapnltl", two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapogel", two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapogll", two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapogtl", two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapolel", two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapoltl", two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftraporl", two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapseql", two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapsfl", two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapsnel", two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapstl", two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftraptl", two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapueql", two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapugel", two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapugtl", two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapulel", two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapultl", two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapunl", two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l"}, + +{"ftstb", two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b"}, +{"ftstd", two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F"}, +{"ftstl", two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l"}, +{"ftstp", two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p"}, +{"ftsts", two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f"}, +{"ftstw", two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w"}, +{"ftstx", two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8"}, +{"ftstx", two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x"}, + +{"ftwotoxb", two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"ftwotoxd", two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"ftwotoxl", two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"ftwotoxp", two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"ftwotoxs", two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"ftwotoxw", two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"ftwotoxx", two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt"}, + + +{"fjeq", one(0xF081), one(0xF1FF), "IdBc"}, +{"fjf", one(0xF080), one(0xF1FF), "IdBc"}, +{"fjge", one(0xF093), one(0xF1FF), "IdBc"}, +{"fjgl", one(0xF096), one(0xF1FF), "IdBc"}, +{"fjgle", one(0xF097), one(0xF1FF), "IdBc"}, +{"fjgt", one(0xF092), one(0xF1FF), "IdBc"}, +{"fjle", one(0xF095), one(0xF1FF), "IdBc"}, +{"fjlt", one(0xF094), one(0xF1FF), "IdBc"}, +{"fjne", one(0xF08E), one(0xF1FF), "IdBc"}, +{"fjnge", one(0xF09C), one(0xF1FF), "IdBc"}, +{"fjngl", one(0xF099), one(0xF1FF), "IdBc"}, +{"fjngle", one(0xF098), one(0xF1FF), "IdBc"}, +{"fjngt", one(0xF09D), one(0xF1FF), "IdBc"}, +{"fjnle", one(0xF09A), one(0xF1FF), "IdBc"}, +{"fjnlt", one(0xF09B), one(0xF1FF), "IdBc"}, +{"fjoge", one(0xF083), one(0xF1FF), "IdBc"}, +{"fjogl", one(0xF086), one(0xF1FF), "IdBc"}, +{"fjogt", one(0xF082), one(0xF1FF), "IdBc"}, +{"fjole", one(0xF085), one(0xF1FF), "IdBc"}, +{"fjolt", one(0xF084), one(0xF1FF), "IdBc"}, +{"fjor", one(0xF087), one(0xF1FF), "IdBc"}, +{"fjseq", one(0xF091), one(0xF1FF), "IdBc"}, +{"fjsf", one(0xF090), one(0xF1FF), "IdBc"}, +{"fjsne", one(0xF09E), one(0xF1FF), "IdBc"}, +{"fjst", one(0xF09F), one(0xF1FF), "IdBc"}, +{"fjt", one(0xF08F), one(0xF1FF), "IdBc"}, +{"fjueq", one(0xF089), one(0xF1FF), "IdBc"}, +{"fjuge", one(0xF08B), one(0xF1FF), "IdBc"}, +{"fjugt", one(0xF08A), one(0xF1FF), "IdBc"}, +{"fjule", one(0xF08D), one(0xF1FF), "IdBc"}, +{"fjult", one(0xF08C), one(0xF1FF), "IdBc"}, +{"fjun", one(0xF088), one(0xF1FF), "IdBc"}, + +/* The assembler will ignore attempts to force a short offset */ + +{"bhis", one(0061000), one(0177400), "Bg"}, +{"blss", one(0061400), one(0177400), "Bg"}, +{"bccs", one(0062000), one(0177400), "Bg"}, +{"bcss", one(0062400), one(0177400), "Bg"}, +{"bnes", one(0063000), one(0177400), "Bg"}, +{"beqs", one(0063400), one(0177400), "Bg"}, +{"bvcs", one(0064000), one(0177400), "Bg"}, +{"bvss", one(0064400), one(0177400), "Bg"}, +{"bpls", one(0065000), one(0177400), "Bg"}, +{"bmis", one(0065400), one(0177400), "Bg"}, +{"bges", one(0066000), one(0177400), "Bg"}, +{"blts", one(0066400), one(0177400), "Bg"}, +{"bgts", one(0067000), one(0177400), "Bg"}, +{"bles", one(0067400), one(0177400), "Bg"}, + +/* Alternate mnemonics for SUN */ + +{"jbsr", one(0060400), one(0177400), "Bg"}, +{"jbsr", one(0047200), one(0177700), "!s"}, +{"jra", one(0060000), one(0177400), "Bg"}, +{"jra", one(0047300), one(0177700), "!s"}, + +{"jhi", one(0061000), one(0177400), "Bg"}, +{"jls", one(0061400), one(0177400), "Bg"}, +{"jcc", one(0062000), one(0177400), "Bg"}, +{"jcs", one(0062400), one(0177400), "Bg"}, +{"jne", one(0063000), one(0177400), "Bg"}, +{"jeq", one(0063400), one(0177400), "Bg"}, +{"jvc", one(0064000), one(0177400), "Bg"}, +{"jvs", one(0064400), one(0177400), "Bg"}, +{"jpl", one(0065000), one(0177400), "Bg"}, +{"jmi", one(0065400), one(0177400), "Bg"}, +{"jge", one(0066000), one(0177400), "Bg"}, +{"jlt", one(0066400), one(0177400), "Bg"}, +{"jgt", one(0067000), one(0177400), "Bg"}, +{"jle", one(0067400), one(0177400), "Bg"}, + +/* Short offsets are ignored */ + +{"jbsrs", one(0060400), one(0177400), "Bg"}, +{"jras", one(0060000), one(0177400), "Bg"}, +{"jhis", one(0061000), one(0177400), "Bg"}, +{"jlss", one(0061400), one(0177400), "Bg"}, +{"jccs", one(0062000), one(0177400), "Bg"}, +{"jcss", one(0062400), one(0177400), "Bg"}, +{"jnes", one(0063000), one(0177400), "Bg"}, +{"jeqs", one(0063400), one(0177400), "Bg"}, +{"jvcs", one(0064000), one(0177400), "Bg"}, +{"jvss", one(0064400), one(0177400), "Bg"}, +{"jpls", one(0065000), one(0177400), "Bg"}, +{"jmis", one(0065400), one(0177400), "Bg"}, +{"jges", one(0066000), one(0177400), "Bg"}, +{"jlts", one(0066400), one(0177400), "Bg"}, +{"jgts", one(0067000), one(0177400), "Bg"}, +{"jles", one(0067400), one(0177400), "Bg"}, + +{"movql", one(0070000), one(0170400), "MsDd"}, +{"moveql", one(0070000), one(0170400), "MsDd"}, +{"moval", one(0020100), one(0170700), "*lAd"}, +{"movaw", one(0030100), one(0170700), "*wAd"}, +{"movb", one(0010000), one(0170000), ";b$d"}, /* mov */ +{"movl", one(0070000), one(0170400), "MsDd"}, /* movq written as mov */ +{"movl", one(0020000), one(0170000), "*l$d"}, +{"movl", one(0020100), one(0170700), "*lAd"}, +{"movl", one(0047140), one(0177770), "AsUd"}, /* mov to USP */ +{"movl", one(0047150), one(0177770), "UdAs"}, /* mov from USP */ +{"movc", one(0047173), one(0177777), "R1Jj"}, +{"movc", one(0047173), one(0177777), "R1#j"}, +{"movc", one(0047172), one(0177777), "JjR1"}, +{"movc", one(0047172), one(0177777), "#jR1"}, +{"movml", one(0044300), one(0177700), "#w&s"}, /* movm reg to mem. */ +{"movml", one(0044340), one(0177770), "#w-s"}, /* movm reg to autodecrement. */ +{"movml", one(0046300), one(0177700), "!s#w"}, /* movm mem to reg. */ +{"movml", one(0046330), one(0177770), "+s#w"}, /* movm autoinc to reg. */ +{"movml", one(0044300), one(0177700), "Lw&s"}, /* movm reg to mem. */ +{"movml", one(0044340), one(0177770), "lw-s"}, /* movm reg to autodecrement. */ +{"movml", one(0046300), one(0177700), "!sLw"}, /* movm mem to reg. */ +{"movml", one(0046330), one(0177770), "+sLw"}, /* movm autoinc to reg. */ +{"movmw", one(0044200), one(0177700), "#w&s"}, /* movm reg to mem. */ +{"movmw", one(0044240), one(0177770), "#w-s"}, /* movm reg to autodecrement. */ +{"movmw", one(0046200), one(0177700), "!s#w"}, /* movm mem to reg. */ +{"movmw", one(0046230), one(0177770), "+s#w"}, /* movm autoinc to reg. */ +{"movmw", one(0044200), one(0177700), "Lw&s"}, /* movm reg to mem. */ +{"movmw", one(0044240), one(0177770), "lw-s"}, /* movm reg to autodecrement. */ +{"movmw", one(0046200), one(0177700), "!sLw"}, /* movm mem to reg. */ +{"movmw", one(0046230), one(0177770), "+sLw"}, /* movm autoinc to reg. */ +{"movpl", one(0000510), one(0170770), "dsDd"}, /* memory to register */ +{"movpl", one(0000710), one(0170770), "Ddds"}, /* register to memory */ +{"movpw", one(0000410), one(0170770), "dsDd"}, /* memory to register */ +{"movpw", one(0000610), one(0170770), "Ddds"}, /* register to memory */ +{"movq", one(0070000), one(0170400), "MsDd"}, +{"movw", one(0030000), one(0170000), "*w$d"}, +{"movw", one(0030100), one(0170700), "*wAd"}, /* mova, written as mov */ +{"movw", one(0040300), one(0177700), "Ss$s"}, /* Move from sr */ +{"movw", one(0041300), one(0177700), "Cs$s"}, /* Move from ccr */ +{"movw", one(0042300), one(0177700), ";wCd"}, /* mov to ccr */ +{"movw", one(0043300), one(0177700), ";wSd"}, /* mov to sr */ + +{"movsb", two(0007000, 0), two(0177700, 07777), "~sR1"}, +{"movsb", two(0007000, 04000), two(0177700, 07777), "R1~s"}, +{"movsl", two(0007200, 0), two(0177700, 07777), "~sR1"}, +{"movsl", two(0007200, 04000), two(0177700, 07777), "R1~s"}, +{"movsw", two(0007100, 0), two(0177700, 07777), "~sR1"}, +{"movsw", two(0007100, 04000), two(0177700, 07777), "R1~s"}, + +#ifdef m68851 + /* name */ /* opcode */ /* match */ /* args */ + +{"pbac", one(0xf0c7), one(0xffbf), "Bc"}, +{"pbacw", one(0xf087), one(0xffbf), "Bc"}, +{"pbas", one(0xf0c6), one(0xffbf), "Bc"}, +{"pbasw", one(0xf086), one(0xffbf), "Bc"}, +{"pbbc", one(0xf0c1), one(0xffbf), "Bc"}, +{"pbbcw", one(0xf081), one(0xffbf), "Bc"}, +{"pbbs", one(0xf0c0), one(0xffbf), "Bc"}, +{"pbbsw", one(0xf080), one(0xffbf), "Bc"}, +{"pbcc", one(0xf0cf), one(0xffbf), "Bc"}, +{"pbccw", one(0xf08f), one(0xffbf), "Bc"}, +{"pbcs", one(0xf0ce), one(0xffbf), "Bc"}, +{"pbcsw", one(0xf08e), one(0xffbf), "Bc"}, +{"pbgc", one(0xf0cd), one(0xffbf), "Bc"}, +{"pbgcw", one(0xf08d), one(0xffbf), "Bc"}, +{"pbgs", one(0xf0cc), one(0xffbf), "Bc"}, +{"pbgsw", one(0xf08c), one(0xffbf), "Bc"}, +{"pbic", one(0xf0cb), one(0xffbf), "Bc"}, +{"pbicw", one(0xf08b), one(0xffbf), "Bc"}, +{"pbis", one(0xf0ca), one(0xffbf), "Bc"}, +{"pbisw", one(0xf08a), one(0xffbf), "Bc"}, +{"pblc", one(0xf0c3), one(0xffbf), "Bc"}, +{"pblcw", one(0xf083), one(0xffbf), "Bc"}, +{"pbls", one(0xf0c2), one(0xffbf), "Bc"}, +{"pblsw", one(0xf082), one(0xffbf), "Bc"}, +{"pbsc", one(0xf0c5), one(0xffbf), "Bc"}, +{"pbscw", one(0xf085), one(0xffbf), "Bc"}, +{"pbss", one(0xf0c4), one(0xffbf), "Bc"}, +{"pbssw", one(0xf084), one(0xffbf), "Bc"}, +{"pbwc", one(0xf0c9), one(0xffbf), "Bc"}, +{"pbwcw", one(0xf089), one(0xffbf), "Bc"}, +{"pbws", one(0xf0c8), one(0xffbf), "Bc"}, +{"pbwsw", one(0xf088), one(0xffbf), "Bc"}, + + +{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw"}, +{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw"}, +{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw"}, +{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw"}, +{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw"}, +{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw"}, +{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw"}, +{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw"}, +{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw"}, +{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw"}, +{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw"}, +{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw"}, +{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw"}, +{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw"}, +{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw"}, +{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw"}, + +{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "" }, + +{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9" }, +{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s" }, +{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9" }, +{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s" }, +{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9" }, +{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s" }, + +{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9" }, +{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe00), "T3T9&s" }, +{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9" }, +{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s" }, +{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9" }, +{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s"}, + +{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s" }, + +{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s" }, +{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s" }, +{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s" }, +{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s" }, +{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s" }, +{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s" }, + +/* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */ +{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8" }, +{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s" }, +{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8" }, +{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s" }, + +/* BADx, BACx */ +{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3" }, +{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s" }, + +/* PSR, PCSR */ +/* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8" }, */ +{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8" }, +{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s" }, +{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s" }, + +{"prestore", one(0xf140), one(0xffc0), "&s"}, +{"prestore", one(0xf158), one(0xfff8), "+s"}, +{"psave", one(0xf100), one(0xffc0), "&s"}, +{"psave", one(0xf100), one(0xffc0), "+s"}, + +{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s"}, +{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s"}, +{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s"}, +{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s"}, +{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s"}, +{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s"}, +{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s"}, +{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s"}, +{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s"}, +{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s"}, +{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s"}, +{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s"}, +{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s"}, +{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s"}, +{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s"}, +{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s"}, + +{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8" }, +{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9" }, +{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8" }, +{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9" }, +{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8" }, +{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9" }, + +{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8" }, +{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9" }, +{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8" }, +{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9" }, +{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8" }, +{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9" }, + +{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w"}, +{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l"}, +{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), ""}, + +{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w"}, +{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l"}, +{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), ""}, + +{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w"}, +{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l"}, +{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), ""}, + +{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w"}, +{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l"}, +{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), ""}, + +{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w"}, +{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l"}, +{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), ""}, + +{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w"}, +{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l"}, +{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), ""}, + +{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w"}, +{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l"}, +{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), ""}, + +{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w"}, +{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l"}, +{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), ""}, + +{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w"}, +{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l"}, +{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), ""}, + +{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w"}, +{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l"}, +{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), ""}, + +{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w"}, +{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l"}, +{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), ""}, + +{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w"}, +{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l"}, +{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), ""}, + +{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w"}, +{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l"}, +{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), ""}, + +{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w"}, +{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l"}, +{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), ""}, + +{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w"}, +{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l"}, +{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), ""}, + +{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w"}, +{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l"}, +{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), ""}, + +{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s"}, +{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s" }, + +#endif /* m68851 */ + +}; + +int numopcodes=sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]); + +struct m68k_opcode *endop = m68k_opcodes+sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]); diff --git a/gdb/m68k-pinsn.c b/gdb/m68k-pinsn.c new file mode 100644 index 00000000000..608bc25819a --- /dev/null +++ b/gdb/m68k-pinsn.c @@ -0,0 +1,774 @@ +/* Print m68k instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "m68k-opcode.h" +#include "gdbcore.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_filtered (stream, "0%o", (buffer[0] << 8) + buffer[1]); + return 2; + } + + fprintf_filtered (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; + if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4) + p = buffer + 4; + } + + d = m68k_opcodes[best].args; + + if (*d) + fputs_filtered (" ", stream); + + while (*d) + { + p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream); + d += 2; + if (*d && *(d - 2) != 'I' && *d != 'k') + fputs_filtered (",", 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_filtered (stream, "ccr"); + break; + + case 'S': + fprintf_filtered (stream, "sr"); + break; + + case 'U': + fprintf_filtered (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_filtered (stream, names[regno].name); + break; + } + if (regno < 0) + fprintf_filtered (stream, "%d", val); + } + break; + + case 'Q': + val = fetch_arg (buffer, place, 3); + /* 0 means 8, except for the bkpt instruction... */ + if (val == 0 && d[1] != 's') + val = 8; + fprintf_filtered (stream, "#%d", val); + break; + + case 'M': + val = fetch_arg (buffer, place, 8); + if (val & 0x80) + val = val - 0x100; + fprintf_filtered (stream, "#%d", val); + break; + + case 'T': + val = fetch_arg (buffer, place, 4); + fprintf_filtered (stream, "#%d", val); + break; + + case 'D': + fprintf_filtered (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]); + break; + + case 'A': + fprintf_filtered (stream, "%s", + reg_names[fetch_arg (buffer, place, 3) + 010]); + break; + + case 'R': + fprintf_filtered (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]); + break; + + case 'F': + fprintf_filtered (stream, "fp%d", fetch_arg (buffer, place, 3)); + break; + + case 'O': + val = fetch_arg (buffer, place, 6); + if (val & 0x20) + fprintf_filtered (stream, "%s", reg_names [val & 7]); + else + fprintf_filtered (stream, "%d", val); + break; + + case '+': + fprintf_filtered (stream, "%s@+", + reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case '-': + fprintf_filtered (stream, "%s@-", + reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case 'k': + if (place == 'k') + fprintf_filtered (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_filtered (stream, "{#%d}", val); + } + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + break; + + case '#': + case '^': + p1 = buffer + (*d == '#' ? 2 : 4); + 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_filtered (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_filtered (stream, "%s@(%d)", + reg_names[fetch_arg (buffer, place, 3)], val); + break; + + case 's': + fprintf_filtered (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_filtered (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_filtered (stream, "%s", reg_names[val]); + break; + + case 1: + fprintf_filtered (stream, "%s", regname); + break; + + case 2: + fprintf_filtered (stream, "%s@", regname); + break; + + case 3: + fprintf_filtered (stream, "%s@+", regname); + break; + + case 4: + fprintf_filtered (stream, "%s@-", regname); + break; + + case 5: + val = NEXTWORD (p); + fprintf_filtered (stream, "%s@(%d)", regname, val); + break; + + case 6: + p = print_indexed (regno, p, addr, stream); + break; + + case 7: + switch (val & 7) + { + case 0: + val = NEXTWORD (p); + fprintf_filtered (stream, "@#"); + print_address (val, stream); + break; + + case 1: + val = NEXTLONG (p); + fprintf_filtered (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_filtered (stream, "#%g", flval); + else + fprintf_filtered (stream, "#%d", val); + break; + + default: + fprintf_filtered (stream, "", val); + } + } + break; + + case 'L': + case 'l': + if (place == 'w') + { + char doneany; + p1 = buffer + 2; + val = NEXTWORD (p1); + /* Move the pointer ahead if this point is farther ahead + than the last. */ + p = p1 > p ? p1 : p; + if (val == 0) + { + fputs_filtered ("#0", stream); + break; + } + if (*d == 'l') + { + register int newval = 0; + for (regno = 0; regno < 16; ++regno) + if (val & (0x8000 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xffff; + doneany = 0; + for (regno = 0; regno < 16; ++regno) + if (val & (1 << regno)) + { + int first_regno; + if (doneany) + fputs_filtered ("/", stream); + doneany = 1; + fprintf_filtered (stream, "%s", reg_names[regno]); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + fprintf_filtered (stream, "-%s", reg_names[regno]); + } + } + else if (place == '3') + { + /* `fmovem' insn. */ + char doneany; + val = fetch_arg (buffer, place, 8); + if (val == 0) + { + fputs_filtered ("#0", stream); + break; + } + if (*d == 'l') + { + register int newval = 0; + for (regno = 0; regno < 8; ++regno) + if (val & (0x80 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xff; + doneany = 0; + for (regno = 0; regno < 8; ++regno) + if (val & (1 << regno)) + { + int first_regno; + if (doneany) + fputs_filtered ("/", stream); + doneany = 1; + fprintf_filtered (stream, "fp%d", regno); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + fprintf_filtered (stream, "-fp%d", regno); + } + } + else + abort (); + 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); + fputs_filtered (buf, stream); + 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); + fputs_filtered (buf, stream); + 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_filtered (stream, "%d(", outer_disp); + print_base (basereg, base_disp, stream); + + /* If postindexed, print the closeparen before the index. */ + if (word & 4) + fprintf_filtered (stream, ")%s", buf); + /* If preindexed, print the closeparen after the index. */ + else + fprintf_filtered (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_filtered (stream, "%d", disp); + else if (regno == -1) + fprintf_filtered (stream, "0x%x", disp); + else + fprintf_filtered (stream, "%d(%s)", disp, reg_names[regno]); +} diff --git a/gdb/mcheck.c b/gdb/mcheck.c new file mode 100755 index 00000000000..8b63d7267ba --- /dev/null +++ b/gdb/mcheck.c @@ -0,0 +1,119 @@ +/* Standard debugging hooks for `malloc'. + Copyright 1990 Free Software Foundation + Written May 1989 by Mike Haertel. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#include "ansidecl.h" +#include +#include "gmalloc.h" + +/* Old hook values. */ +static void EXFUN((*old_free_hook), (PTR ptr)); +static PTR EXFUN((*old_malloc_hook), (size_t size)); +static PTR EXFUN((*old_realloc_hook), (PTR ptr, size_t size)); + +/* Function to call when something awful happens. */ +static void EXFUN((*abortfunc), (void)) = abort; + +/* Arbitrary magical numbers. */ +#define MAGICWORD 0xfedabeeb +#define MAGICBYTE ((char) 0xd7) + +struct hdr + { + size_t size; /* Exact size requested by user. */ + unsigned int magic; /* Magic number to check header integrity. */ + }; + +static void +DEFUN(checkhdr, (hdr), CONST struct hdr *hdr) +{ + if (hdr->magic != MAGICWORD || ((char *) &hdr[1])[hdr->size] != MAGICBYTE) + (*abortfunc)(); +} + +static void +DEFUN(freehook, (ptr), PTR ptr) +{ + struct hdr *hdr = ((struct hdr *) ptr) - 1; + checkhdr(hdr); + hdr->magic = 0; + __free_hook = old_free_hook; + free(hdr); + __free_hook = freehook; +} + +static PTR +DEFUN(mallochook, (size), size_t size) +{ + struct hdr *hdr; + + __malloc_hook = old_malloc_hook; + hdr = (struct hdr *) malloc(sizeof(struct hdr) + size + 1); + __malloc_hook = mallochook; + if (hdr == NULL) + return NULL; + + hdr->size = size; + hdr->magic = MAGICWORD; + ((char *) &hdr[1])[size] = MAGICBYTE; + return (PTR) (hdr + 1); +} + +static PTR +DEFUN(reallochook, (ptr, size), PTR ptr AND size_t size) +{ + struct hdr *hdr = ((struct hdr *) ptr) - 1; + + checkhdr(hdr); + __free_hook = old_free_hook; + __malloc_hook = old_malloc_hook; + __realloc_hook = old_realloc_hook; + hdr = (struct hdr *) realloc((PTR) hdr, sizeof(struct hdr) + size + 1); + __free_hook = freehook; + __malloc_hook = mallochook; + __realloc_hook = reallochook; + if (hdr == NULL) + return NULL; + + hdr->size = size; + ((char *) &hdr[1])[size] = MAGICBYTE; + return (PTR) (hdr + 1); +} + +void +DEFUN(mcheck, (func), void EXFUN((*func), (void))) +{ + static int mcheck_used = 0; + + if (func) + abortfunc = func; + + /* These hooks may not be safely inserted if malloc is already in use. */ + if (!__malloc_initialized && !mcheck_used) + { + old_free_hook = __free_hook; + __free_hook = freehook; + old_malloc_hook = __malloc_hook; + __malloc_hook = mallochook; + old_realloc_hook = __realloc_hook; + __realloc_hook = reallochook; + mcheck_used = 1; + } +} diff --git a/gdb/mips-opcode.h b/gdb/mips-opcode.h new file mode 100755 index 00000000000..fd92c78f9a1 --- /dev/null +++ b/gdb/mips-opcode.h @@ -0,0 +1,363 @@ +/* Mips opcde list for GDB, the GNU debugger. + Copyright (C) 1989 Free Software Foundation, Inc. + Contributed by Nobuyuki Hikichi(hikichi@sra.junet) + Made to work for little-endian machines, and debugged + by Per Bothner (bothner@cs.wisc.edu). + Many fixes contributed by Frank Yellin (fy@lucid.com). + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef BITS_BIG_ENDIAN +#define BIT_FIELDS_2(a,b) a;b; +#define BIT_FIELDS_4(a,b,c,d) a;b;c;d; +#define BIT_FIELDS_6(a,b,c,d,e,f) a;b;c;d;e;f; +#else +#define BIT_FIELDS_2(a,b) b;a; +#define BIT_FIELDS_4(a,b,c,d) d;c;b;a; +#define BIT_FIELDS_6(a,b,c,d,e,f) f;e;d;c;b;a; +#endif + +struct op_i_fmt +{ +BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned immediate : 16) +}; + +struct op_j_fmt +{ +BIT_FIELDS_2( + unsigned op : 6, + unsigned target : 26) +}; + +struct op_r_fmt +{ +BIT_FIELDS_6( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned rd : 5, + unsigned shamt : 5, + unsigned funct : 6) +}; + + +struct fop_i_fmt +{ +BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned immediate : 16) +}; + +struct op_b_fmt +{ +BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + short delta : 16) +}; + +struct fop_r_fmt +{ +BIT_FIELDS_6( + unsigned op : 6, + unsigned fmt : 5, + unsigned ft : 5, + unsigned fs : 5, + unsigned fd : 5, + unsigned funct : 6) +}; + +struct mips_opcode +{ + char *name; + unsigned long opcode; + unsigned long match; + char *args; + int bdelay; /* Nonzero if delayed branch. */ +}; + +/* args format; + + "s" rs: source register specifier + "t" rt: target register + "i" immediate + "a" target address + "c" branch condition + "d" rd: destination register specifier + "h" shamt: shift amount + "f" funct: function field + + for fpu + "S" fs source 1 register + "T" ft source 2 register + "D" distination register +*/ + +#define one(x) (x << 26) +#define op_func(x, y) ((x << 26) | y) +#define op_cond(x, y) ((x << 26) | (y << 16)) +#define op_rs_func(x, y, z) ((x << 26) | (y << 21) | z) +#define op_rs_b11(x, y, z) ((x << 26) | (y << 21) | z) +#define op_o16(x, y) ((x << 26) | (y << 16)) +#define op_bc(x, y, z) ((x << 26) | (y << 21) | (z << 16)) + +struct mips_opcode mips_opcodes[] = +{ +/* These first opcodes are special cases of the ones in the comments */ + {"nop", 0, 0xffffffff, /*li*/ "", 0}, + {"li", op_bc(9,0,0), op_bc(0x3f,31,0), /*addiu*/ "t,j", 0}, + {"b", one(4), 0xffff0000, /*beq*/ "b", 1}, + {"move", op_func(0, 33), op_cond(0x3f,31)|0x7ff,/*addu*/ "d,s", 0}, + + {"sll", op_func(0, 0), op_func(0x3f, 0x3f), "d,t,h", 0}, + {"srl", op_func(0, 2), op_func(0x3f, 0x3f), "d,t,h", 0}, + {"sra", op_func(0, 3), op_func(0x3f, 0x3f), "d,t,h", 0}, + {"sllv", op_func(0, 4), op_func(0x3f, 0x7ff), "d,t,s", 0}, + {"srlv", op_func(0, 6), op_func(0x3f, 0x7ff), "d,t,s", 0}, + {"srav", op_func(0, 7), op_func(0x3f, 0x7ff), "d,t,s", 0}, + {"jr", op_func(0, 8), op_func(0x3f, 0x1fffff), "s", 1}, + {"jalr", op_func(0, 9), op_func(0x3f, 0x1f07ff), "d,s", 1}, + {"syscall", op_func(0, 12), op_func(0x3f, 0x3f), "", 0}, + {"break", op_func(0, 13), op_func(0x3f, 0x3f), "", 0}, + {"mfhi", op_func(0, 16), op_func(0x3f, 0x03ff07ff), "d", 0}, + {"mthi", op_func(0, 17), op_func(0x3f, 0x1fffff), "s", 0}, + {"mflo", op_func(0, 18), op_func(0x3f, 0x03ff07ff), "d", 0}, + {"mtlo", op_func(0, 19), op_func(0x3f, 0x1fffff), "s", 0}, + {"mult", op_func(0, 24), op_func(0x3f, 0xffff), "s,t", 0}, + {"multu", op_func(0, 25), op_func(0x3f, 0xffff), "s,t", 0}, + {"div", op_func(0, 26), op_func(0x3f, 0xffff), "s,t", 0}, + {"divu", op_func(0, 27), op_func(0x3f, 0xffff), "s,t", 0}, + {"add", op_func(0, 32), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"addu", op_func(0, 33), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"sub", op_func(0, 34), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"subu", op_func(0, 35), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"and", op_func(0, 36), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"or", op_func(0, 37), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"xor", op_func(0, 38), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"nor", op_func(0, 39), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"slt", op_func(0, 42), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"sltu", op_func(0, 43), op_func(0x3f, 0x7ff), "d,s,t", 0}, + + {"bltz", op_cond (1, 0), op_cond(0x3f, 0x1f), "s,b", 1}, + {"bgez", op_cond (1, 1), op_cond(0x3f, 0x1f), "s,b", 1}, + {"bltzal", op_cond (1, 16),op_cond(0x3f, 0x1f), "s,b", 1}, + {"bgezal", op_cond (1, 17),op_cond(0x3f, 0x1f), "s,b", 1}, + + + {"j", one(2), one(0x3f), "a", 1}, + {"jal", one(3), one(0x3f), "a", 1}, + {"beq", one(4), one(0x3f), "s,t,b", 1}, + {"bne", one(5), one(0x3f), "s,t,b", 1}, + {"blez", one(6), one(0x3f) | 0x1f0000, "s,b", 1}, + {"bgtz", one(7), one(0x3f) | 0x1f0000, "s,b", 1}, + {"addi", one(8), one(0x3f), "t,s,j", 0}, + {"addiu", one(9), one(0x3f), "t,s,j", 0}, + {"slti", one(10), one(0x3f), "t,s,j", 0}, + {"sltiu", one(11), one(0x3f), "t,s,j", 0}, + {"andi", one(12), one(0x3f), "t,s,i", 0}, + {"ori", one(13), one(0x3f), "t,s,i", 0}, + {"xori", one(14), one(0x3f), "t,s,i", 0}, + /* rs field is don't care field? */ + {"lui", one(15), one(0x3f), "t,i", 0}, + +/* co processor 0 instruction */ + {"mfc0", op_rs_b11 (16, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"cfc0", op_rs_b11 (16, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"mtc0", op_rs_b11 (16, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"ctc0", op_rs_b11 (16, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + + {"bc0f", op_o16(16, 0x100), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc0f", op_o16(16, 0x180), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc0t", op_o16(16, 0x101), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc0t", op_o16(16, 0x181), op_o16(0x3f, 0x3ff), "b", 1}, + + {"tlbr", op_rs_func(16, 0x10, 1), ~0, "", 0}, + {"tlbwi", op_rs_func(16, 0x10, 2), ~0, "", 0}, + {"tlbwr", op_rs_func(16, 0x10, 6), ~0, "", 0}, + {"tlbp", op_rs_func(16, 0x10, 8), ~0, "", 0}, + {"rfe", op_rs_func(16, 0x10, 16), ~0, "", 0}, + + {"mfc1", op_rs_b11 (17, 0, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0}, + {"cfc1", op_rs_b11 (17, 2, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0}, + {"mtc1", op_rs_b11 (17, 4, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0}, + {"ctc1", op_rs_b11 (17, 6, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0}, + + {"bc1f", op_o16(17, 0x100), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc1f", op_o16(17, 0x180), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc1t", op_o16(17, 0x101), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc1t", op_o16(17, 0x181), op_o16(0x3f, 0x3ff), "b", 1}, + +/* fpu instruction */ + {"add.s", op_rs_func(17, 0x10, 0), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"add.d", op_rs_func(17, 0x11, 0), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"sub.s", op_rs_func(17, 0x10, 1), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"sub.d", op_rs_func(17, 0x11, 1), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"mul.s", op_rs_func(17, 0x10, 2), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"mul.d", op_rs_func(17, 0x11, 2), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"div.s", op_rs_func(17, 0x10, 3), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"div.d", op_rs_func(17, 0x11, 3), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"abs.s", op_rs_func(17, 0x10, 5), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"abs.d", op_rs_func(17, 0x11, 5), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"mov.s", op_rs_func(17, 0x10, 6), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"mov.d", op_rs_func(17, 0x11, 6), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"neg.s", op_rs_func(17, 0x10, 7), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"neg.d", op_rs_func(17, 0x11, 7), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.s.s", op_rs_func(17, 0x10, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.s.d", op_rs_func(17, 0x11, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.s.w", op_rs_func(17, 0x14, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.d.s", op_rs_func(17, 0x10, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.d.d", op_rs_func(17, 0x11, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.d.w", op_rs_func(17, 0x14, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.w.s", op_rs_func(17, 0x10, 36), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.w.d", op_rs_func(17, 0x11, 36), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"c.f.s", op_rs_func(17, 0x10, 48), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.f.d", op_rs_func(17, 0x11, 48), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.un.s", op_rs_func(17, 0x10, 49), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.un.d", op_rs_func(17, 0x11, 49), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.eq.s", op_rs_func(17, 0x10, 50), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.eq.d", op_rs_func(17, 0x11, 50), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ueq.s", op_rs_func(17, 0x10, 51), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ueq.d", op_rs_func(17, 0x11, 51), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.olt.s", op_rs_func(17, 0x10, 52), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.olt.d", op_rs_func(17, 0x11, 52), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ult.s", op_rs_func(17, 0x10, 53), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ult.d", op_rs_func(17, 0x11, 53), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ole.s", op_rs_func(17, 0x10, 54), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ole.d", op_rs_func(17, 0x11, 54), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ule.s", op_rs_func(17, 0x10, 55), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ule.d", op_rs_func(17, 0x11, 55), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.sf.s", op_rs_func(17, 0x10, 56), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.sf.d", op_rs_func(17, 0x11, 56), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngle.s", op_rs_func(17, 0x10, 57), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngle.d", op_rs_func(17, 0x11, 57), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.seq.s", op_rs_func(17, 0x10, 58), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.seq.d", op_rs_func(17, 0x11, 58), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngl.s", op_rs_func(17, 0x10, 59), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngl.d", op_rs_func(17, 0x11, 59), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.lt.s", op_rs_func(17, 0x10, 60), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.lt.d", op_rs_func(17, 0x11, 60), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.nge.s", op_rs_func(17, 0x10, 61), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.nge.d", op_rs_func(17, 0x11, 61), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.le.s", op_rs_func(17, 0x10, 62), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.le.d", op_rs_func(17, 0x11, 62), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngt.s", op_rs_func(17, 0x10, 63), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngt.d", op_rs_func(17, 0x11, 63), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + +/* co processor 2 instruction */ + {"mfc2", op_rs_b11 (18, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"cfc2", op_rs_b11 (18, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"mtc2", op_rs_b11 (18, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"ctc2", op_rs_b11 (18, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"bc2f", op_o16(18, 0x100), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc2f", op_o16(18, 0x180), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc2f", op_o16(18, 0x101), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc2t", op_o16(18, 0x181), op_o16(0x3f, 0x3ff), "b", 1}, + +/* co processor 3 instruction */ + {"mtc3", op_rs_b11 (19, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"cfc3", op_rs_b11 (19, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"mtc3", op_rs_b11 (19, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"ctc3", op_rs_b11 (19, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"bc3f", op_o16(19, 0x100), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc3f", op_o16(19, 0x180), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc3t", op_o16(19, 0x101), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc3t", op_o16(19, 0x181), op_o16(0x3f, 0x3ff), "b", 1}, + + {"lb", one(32), one(0x3f), "t,j(s)", 0}, + {"lh", one(33), one(0x3f), "t,j(s)", 0}, + {"lwl", one(34), one(0x3f), "t,j(s)", 0}, + {"lw", one(35), one(0x3f), "t,j(s)", 0}, + {"lbu", one(36), one(0x3f), "t,j(s)", 0}, + {"lhu", one(37), one(0x3f), "t,j(s)", 0}, + {"lwr", one(38), one(0x3f), "t,j(s)", 0}, + {"sb", one(40), one(0x3f), "t,j(s)", 0}, + {"sh", one(41), one(0x3f), "t,j(s)", 0}, + {"swl", one(42), one(0x3f), "t,j(s)", 0}, + {"swr", one(46), one(0x3f), "t,j(s)", 0}, + {"sw", one(43), one(0x3f), "t,j(s)", 0}, + {"lwc0", one(48), one(0x3f), "t,j(s)", 0}, +/* for fpu */ + {"lwc1", one(49), one(0x3f), "T,j(s)", 0}, + {"lwc2", one(50), one(0x3f), "t,j(s)", 0}, + {"lwc3", one(51), one(0x3f), "t,j(s)", 0}, + {"swc0", one(56), one(0x3f), "t,j(s)", 0}, +/* for fpu */ + {"swc1", one(57), one(0x3f), "T,j(s)", 0}, + {"swc2", one(58), one(0x3f), "t,j(s)", 0}, + {"swc3", one(59), one(0x3f), "t,j(s)", 0}, +}; diff --git a/gdb/mips-pinsn.c b/gdb/mips-pinsn.c new file mode 100644 index 00000000000..b348339d098 --- /dev/null +++ b/gdb/mips-pinsn.c @@ -0,0 +1,149 @@ +/* Print mips instructions for GDB, the GNU debugger. + Copyright (C) 1989 Free Software Foundation, Inc. + Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp) + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "mips-opcode.h" + +/* Mips instructions are never longer than this many bytes. */ +#define MAXLEN 4 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof mips_opcodes / sizeof mips_opcodes[0]) + +#define MKLONG(p) *(unsigned long*)p + +extern char *reg_names[]; + + +/* subroutine */ +static unsigned char * +print_insn_arg (d, l, stream, pc) + char *d; + register unsigned long int *l; + FILE *stream; + CORE_ADDR pc; +{ + switch (*d) + { + case ',': + case '(': + case ')': + fputc (*d, stream); + break; + + case 's': + fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rs]); + break; + + case 't': + fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rt]); + break; + + case 'i': + fprintf (stream, "%d", ((struct op_i_fmt *) l)->immediate); + break; + + case 'j': /* same as i, but sign-extended */ + fprintf (stream, "%d", ((struct op_b_fmt *) l)->delta); + break; + + case 'a': + print_address ((pc & 0xF0000000) | (((struct op_j_fmt *)l)->target << 2), + stream); + break; + + case 'b': + print_address ((((struct op_b_fmt *) l)->delta << 2) + pc + 4, stream); + break; + + case 'd': + fprintf (stream, "%s", reg_names[((struct op_r_fmt *) l)->rd]); + break; + + case 'h': + fprintf (stream, "0x%x", ((struct op_r_fmt *) l)->shamt); + break; + + case 'S': + fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fs); + break; + + case 'T': + fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->ft); + break; + + case 'D': + fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fd); + break; + + default: + fprintf (stream, "# internal error, undefined modifier(%c)", *d); + break; + } +} + +/* Print the mips instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes, which + is always 4. */ + +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + register int i; + register char *d; + unsigned long int l; + + read_memory (memaddr, buffer, MAXLEN); + + for (i = 0; i < NOPCODES; i++) + { + register unsigned int opcode = mips_opcodes[i].opcode; + register unsigned int match = mips_opcodes[i].match; + if ((*(unsigned int*)buffer & match) == opcode) + break; + } + + l = MKLONG (buffer); + /* Handle undefined instructions. */ + if (i == NOPCODES) + { + fprintf (stream, "0x%x",l); + return 4; + } + + fprintf (stream, "%s", mips_opcodes[i].name); + + if (!(d = mips_opcodes[i].args)) + return 4; + + fputc (' ', stream); + + while (*d) + print_insn_arg (d++, &l, stream, memaddr); + + return 4; +} diff --git a/gdb/mips-xdep.c b/gdb/mips-xdep.c new file mode 100644 index 00000000000..7748f1c0e16 --- /dev/null +++ b/gdb/mips-xdep.c @@ -0,0 +1,132 @@ +/* Low level MIPS interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU + and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +/* #include Can we live without this? */ + +#include "gdbcore.h" + +#include /* After a.out.h */ +#include +#include + +/* Get all registers from the inferior */ + +void +fetch_inferior_registers () +{ + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + registers_fetched (); + + for (regno = 1; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, 1); + 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]; + + if (regno == 0) + return; + + if (regno > 0) + { + regaddr = register_addr (regno, 1); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else + { + for (regno = 1; regno < NUM_REGS; regno++) + { + if (regno == 32 || regno == 35 || regno == 36 || regno == 71) + continue; + regaddr = register_addr (regno, 1); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing all regs, number %d", regno); + perror_with_name (buf); + } + } + } +} + +void +fetch_core_registers () +{ + register int regno; + int val; + + for (regno = 1; regno < NUM_REGS; regno++) { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = bfd_seek (core_bfd, register_addr (regno, 0)); + if (val < 0 || (val = bfd_read (core_bfd, buf, sizeof buf)) < 0) { + char buffer[50]; + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + supply_register (regno, buf); + } +} diff --git a/gdb/munch b/gdb/munch new file mode 100755 index 00000000000..8b59ed00682 --- /dev/null +++ b/gdb/munch @@ -0,0 +1,21 @@ +#!/bin/sh + +# create an initialization procedure from a list of .o files + +echo '/* Do not modify this file. It is created automatically by "munch". */' +echo 'void initialize_all_files () {' + +# make it easy to use a different nm, e.g. for cross-developing +MUNCH_NM=${MUNCH_NM-nm} +if test "`$MUNCH_NM main.o | egrep 'T _?main$'`" = "" ; then + # System V style nm + shift; + $MUNCH_NM $* | egrep '^(.*[^a-zA-Z_]_|_)_?initialize_.*\.text' | \ + sed -e 's/^.*\(_initialize_[a-zA-Z0-9_]*\)[^a-zA-Z0-9_].*$/ {extern void \1 (); \1 ();}/' +else + # BSD style nm + $MUNCH_NM -p $* | egrep 'T *_?_initialize_' | \ + sed -e 's/^.*T *_*\(.*\)/ {extern void _\1 (); _\1 ();}/' +fi + +echo '}' diff --git a/gdb/news-xdep.c b/gdb/news-xdep.c new file mode 100644 index 00000000000..58a9191dc2d --- /dev/null +++ b/gdb/news-xdep.c @@ -0,0 +1,65 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef __GNUC__ +/* Bad implement execle(3). It's depend for "/bin/cc". + + main() + { + printf("execle:\n"); + execle(FILE, ARGS, envp); + exit(1); + } + + GCC: + link a6,#0 + pea LC5 ; call printf + jbsr _printf + ; ; (not popd stack) + pea _envp ; call execle + clrl sp@- + pea LC4 + pea LC4 + pea LC4 + pea LC3 + pea LC6 + jbsr _execle + addw #32,sp ; delayed pop !! + + /bin/cc: + link.l fp,#L23 + movem.l #L24,(sp) + pea L26 ; call printf + jbsr _printf + addq.l #4,sp ; <--- popd stack !! + pea _envp ; call execle + clr.l -(sp) + pea L32 + + */ + +execle(name, args) + char *name, *args; +{ + register char **env = &args; + while (*env++) + ; + execve(name, (char **)&args, (char **)*env); +} +#endif diff --git a/gdb/nindy-tdep.c b/gdb/nindy-tdep.c new file mode 100644 index 00000000000..b609fd7971b --- /dev/null +++ b/gdb/nindy-tdep.c @@ -0,0 +1,77 @@ +/* Target-machine dependent code for the NINDY monitor running on the Intel 960 + Copyright (C) 1991 Free Software Foundation, Inc. + Contributed by Intel Corporation. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Miscellaneous NINDY-dependent routines. + Some replace macros normally defined in "tm.h". */ + +#include +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" + +/* 'start_frame' is a variable in the NINDY runtime startup routine + that contains the frame pointer of the 'start' routine (the routine + that calls 'main'). By reading its contents out of remote memory, + we can tell where the frame chain ends: backtraces should halt before + they display this frame. */ + +int +nindy_frame_chain_valid (chain, curframe) + unsigned int chain; + FRAME curframe; +{ + struct symbol *sym; + int i; + + /* crtnindy.o is an assembler module that is assumed to be linked + * first in an i80960 executable. It contains the true entry point; + * it performs startup up initialization and then calls 'main'. + * + * 'sf' is the name of a variable in crtnindy.o that is set + * during startup to the address of the first frame. + * + * 'a' is the address of that variable in 80960 memory. + */ + static char sf[] = "start_frame"; + CORE_ADDR a; + + + chain &= ~0x3f; /* Zero low 6 bits because previous frame pointers + contain return status info in them. */ + if ( chain == 0 ){ + return 0; + } + + sym = lookup_symbol(sf, 0, VAR_NAMESPACE, (int *)NULL, + (struct symtab **)NULL); + if ( sym != 0 ){ + a = sym->value.value; + } else { + for ( i = 0; strcmp(misc_function_vector[i].name,sf); i++ ){ + if ( i >= misc_function_count ){ + return 0; + } + } + a = misc_function_vector[i].address; + } + + return ( chain != read_memory_integer(a,4) ); +} diff --git a/gdb/np1-opcode.h b/gdb/np1-opcode.h new file mode 100755 index 00000000000..654682570fa --- /dev/null +++ b/gdb/np1-opcode.h @@ -0,0 +1,422 @@ +/* Print GOULD NPL instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct gld_opcode +{ + char *name; + unsigned long opcode; + unsigned long mask; + char *args; + int length; +}; + +/* We store four bytes of opcode for all opcodes because that + is the most any of them need. The actual length of an instruction + is always at least 2 bytes, and at most four. The length of the + instruction is based on the opcode. + + The mask component is a mask saying which bits must match + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing characters + that are used to format the arguments to the instruction. */ + +/* Kinds of operands: + r Register in first field + R Register in second field + b Base register in first field + B Base register in second field + v Vector register in first field + V Vector register in first field + A Optional address register (base register) + X Optional index register + I Immediate data (16bits signed) + O Offset field (16bits signed) + h Offset field (15bits signed) + d Offset field (14bits signed) + S Shift count field + + any other characters are printed as is... +*/ + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ +struct gld_opcode gld_opcodes[] = +{ +{ "lb", 0xb4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lbs", 0xec080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lh", 0xb4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lnh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lw", 0xb4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ld", 0xb4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lnd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "li", 0xf8000000, 0xfc7f0000, "r,I", 4 }, +{ "lpa", 0x50080000, 0xfc080000, "r,xOA,X", 4 }, +{ "la", 0x50000000, 0xfc080000, "r,xOA,X", 4 }, +{ "labr", 0x58080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lbp", 0x90080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lhp", 0x90000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lwp", 0x90000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ldp", 0x90000002, 0xfc080002, "r,xOA,X", 4 }, +{ "suabr", 0x58000000, 0xfc080000, "b,xOA,X", 4 }, +{ "lf", 0xbc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lfbr", 0xbc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lwbr", 0x5c000000, 0xfc080000, "b,xOA,X", 4 }, +{ "stb", 0xd4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sth", 0xd4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stw", 0xd4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "std", 0xd4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stf", 0xdc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stfbr", 0xdc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "stwbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "zmb", 0xd8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmh", 0xd8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "zmw", 0xd8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmd", 0xd8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stbp", 0x94080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sthp", 0x94000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stwp", 0x94000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stdp", 0x94000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lil", 0xf80b0000, 0xfc7f0000, "r,D", 4 }, +{ "lwsl1", 0xec000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwsl2", 0xfc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwsl3", 0xfc080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "lvb", 0xb0080000, 0xfc080000, "v,xOA,X", 4 }, +{ "lvh", 0xb0000001, 0xfc080001, "v,xOA,X", 4 }, +{ "lvw", 0xb0000000, 0xfc080000, "v,xOA,X", 4 }, +{ "lvd", 0xb0000002, 0xfc080002, "v,xOA,X", 4 }, +{ "liv", 0x3c040000, 0xfc0f0000, "v,R", 2 }, +{ "livf", 0x3c080000, 0xfc0f0000, "v,R", 2 }, +{ "stvb", 0xd0080000, 0xfc080000, "v,xOA,X", 4 }, +{ "stvh", 0xd0000001, 0xfc080001, "v,xOA,X", 4 }, +{ "stvw", 0xd0000000, 0xfc080000, "v,xOA,X", 4 }, +{ "stvd", 0xd0000002, 0xfc080002, "v,xOA,X", 4 }, + +{ "trr", 0x2c000000, 0xfc0f0000, "r,R", 2 }, +{ "trn", 0x2c040000, 0xfc0f0000, "r,R", 2 }, +{ "trnd", 0x2c0c0000, 0xfc0f0000, "r,R", 2 }, +{ "trabs", 0x2c010000, 0xfc0f0000, "r,R", 2 }, +{ "trabsd", 0x2c090000, 0xfc0f0000, "r,R", 2 }, +{ "trc", 0x2c030000, 0xfc0f0000, "r,R", 2 }, +{ "xcr", 0x28040000, 0xfc0f0000, "r,R", 2 }, +{ "cxcr", 0x2c060000, 0xfc0f0000, "r,R", 2 }, +{ "cxcrd", 0x2c0e0000, 0xfc0f0000, "r,R", 2 }, +{ "tbrr", 0x2c020000, 0xfc0f0000, "r,B", 2 }, +{ "trbr", 0x28030000, 0xfc0f0000, "b,R", 2 }, +{ "xcbr", 0x28020000, 0xfc0f0000, "b,B", 2 }, +{ "tbrbr", 0x28010000, 0xfc0f0000, "b,B", 2 }, + +{ "trvv", 0x28050000, 0xfc0f0000, "v,V", 2 }, +{ "trvvn", 0x2c050000, 0xfc0f0000, "v,V", 2 }, +{ "trvvnd", 0x2c0d0000, 0xfc0f0000, "v,V", 2 }, +{ "trvab", 0x2c070000, 0xfc0f0000, "v,V", 2 }, +{ "trvabd", 0x2c0f0000, 0xfc0f0000, "v,V", 2 }, +{ "cmpv", 0x14060000, 0xfc0f0000, "v,V", 2 }, +{ "expv", 0x14070000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvlt", 0x10030000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvle", 0x10040000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvgt", 0x14030000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvge", 0x14040000, 0xfc0f0000, "v,V", 2 }, +{ "mrvveq", 0x10050000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvne", 0x10050000, 0xfc0f0000, "v,V", 2 }, +{ "mrvrlt", 0x100d0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrle", 0x100e0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrgt", 0x140d0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrge", 0x140e0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvreq", 0x100f0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrne", 0x140f0000, 0xfc0f0000, "v,R", 2 }, +{ "trvr", 0x140b0000, 0xfc0f0000, "r,V", 2 }, +{ "trrv", 0x140c0000, 0xfc0f0000, "v,R", 2 }, + +{ "bu", 0x40000000, 0xff880000, "xOA,X", 4 }, +{ "bns", 0x70080000, 0xff880000, "xOA,X", 4 }, +{ "bnco", 0x70880000, 0xff880000, "xOA,X", 4 }, +{ "bge", 0x71080000, 0xff880000, "xOA,X", 4 }, +{ "bne", 0x71880000, 0xff880000, "xOA,X", 4 }, +{ "bunge", 0x72080000, 0xff880000, "xOA,X", 4 }, +{ "bunle", 0x72880000, 0xff880000, "xOA,X", 4 }, +{ "bgt", 0x73080000, 0xff880000, "xOA,X", 4 }, +{ "bnany", 0x73880000, 0xff880000, "xOA,X", 4 }, +{ "bs" , 0x70000000, 0xff880000, "xOA,X", 4 }, +{ "bco", 0x70800000, 0xff880000, "xOA,X", 4 }, +{ "blt", 0x71000000, 0xff880000, "xOA,X", 4 }, +{ "beq", 0x71800000, 0xff880000, "xOA,X", 4 }, +{ "buge", 0x72000000, 0xff880000, "xOA,X", 4 }, +{ "bult", 0x72800000, 0xff880000, "xOA,X", 4 }, +{ "ble", 0x73000000, 0xff880000, "xOA,X", 4 }, +{ "bany", 0x73800000, 0xff880000, "xOA,X", 4 }, +{ "brlnk", 0x44000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bib", 0x48000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bih", 0x48080000, 0xfc080000, "r,xOA,X", 4 }, +{ "biw", 0x4c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bid", 0x4c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivb", 0x60000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivh", 0x60080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivw", 0x64000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivd", 0x64080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsb", 0x68000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsh", 0x68080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsw", 0x6c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsd", 0x6c080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "camb", 0x80080000, 0xfc080000, "r,xOA,X", 4 }, +{ "camh", 0x80000001, 0xfc080001, "r,xOA,X", 4 }, +{ "camw", 0x80000000, 0xfc080000, "r,xOA,X", 4 }, +{ "camd", 0x80000002, 0xfc080002, "r,xOA,X", 4 }, +{ "car", 0x10000000, 0xfc0f0000, "r,R", 2 }, +{ "card", 0x14000000, 0xfc0f0000, "r,R", 2 }, +{ "ci", 0xf8050000, 0xfc7f0000, "r,I", 4 }, +{ "chkbnd", 0x5c080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "cavv", 0x10010000, 0xfc0f0000, "v,V", 2 }, +{ "cavr", 0x10020000, 0xfc0f0000, "v,R", 2 }, +{ "cavvd", 0x10090000, 0xfc0f0000, "v,V", 2 }, +{ "cavrd", 0x100b0000, 0xfc0f0000, "v,R", 2 }, + +{ "anmb", 0x84080000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmh", 0x84000001, 0xfc080001, "r,xOA,X", 4 }, +{ "anmw", 0x84000000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmd", 0x84000002, 0xfc080002, "r,xOA,X", 4 }, +{ "anr", 0x04000000, 0xfc0f0000, "r,R", 2 }, +{ "ani", 0xf8080000, 0xfc7f0000, "r,I", 4 }, +{ "ormb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "ormw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "orr", 0x08000000, 0xfc0f0000, "r,R", 2 }, +{ "oi", 0xf8090000, 0xfc7f0000, "r,I", 4 }, +{ "eomb", 0x8c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomh", 0x8c000001, 0xfc080001, "r,xOA,X", 4 }, +{ "eomw", 0x8c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomd", 0x8c000002, 0xfc080002, "r,xOA,X", 4 }, +{ "eor", 0x0c000000, 0xfc0f0000, "r,R", 2 }, +{ "eoi", 0xf80a0000, 0xfc7f0000, "r,I", 4 }, + +{ "anvv", 0x04010000, 0xfc0f0000, "v,V", 2 }, +{ "anvr", 0x04020000, 0xfc0f0000, "v,R", 2 }, +{ "orvv", 0x08010000, 0xfc0f0000, "v,V", 2 }, +{ "orvr", 0x08020000, 0xfc0f0000, "v,R", 2 }, +{ "eovv", 0x0c010000, 0xfc0f0000, "v,V", 2 }, +{ "eovr", 0x0c020000, 0xfc0f0000, "v,R", 2 }, + +{ "sacz", 0x100c0000, 0xfc0f0000, "r,R", 2 }, +{ "sla", 0x1c400000, 0xfc600000, "r,S", 2 }, +{ "sll", 0x1c600000, 0xfc600000, "r,S", 2 }, +{ "slc", 0x24400000, 0xfc600000, "r,S", 2 }, +{ "slad", 0x20400000, 0xfc600000, "r,S", 2 }, +{ "slld", 0x20600000, 0xfc600000, "r,S", 2 }, +{ "sra", 0x1c000000, 0xfc600000, "r,S", 2 }, +{ "srl", 0x1c200000, 0xfc600000, "r,S", 2 }, +{ "src", 0x24000000, 0xfc600000, "r,S", 2 }, +{ "srad", 0x20000000, 0xfc600000, "r,S", 2 }, +{ "srld", 0x20200000, 0xfc600000, "r,S", 2 }, +{ "sda", 0x3c030000, 0xfc0f0000, "r,R", 2 }, +{ "sdl", 0x3c020000, 0xfc0f0000, "r,R", 2 }, +{ "sdc", 0x3c010000, 0xfc0f0000, "r,R", 2 }, +{ "sdad", 0x3c0b0000, 0xfc0f0000, "r,R", 2 }, +{ "sdld", 0x3c0a0000, 0xfc0f0000, "r,R", 2 }, + +{ "svda", 0x3c070000, 0xfc0f0000, "v,R", 2 }, +{ "svdl", 0x3c060000, 0xfc0f0000, "v,R", 2 }, +{ "svdc", 0x3c050000, 0xfc0f0000, "v,R", 2 }, +{ "svdad", 0x3c0e0000, 0xfc0f0000, "v,R", 2 }, +{ "svdld", 0x3c0d0000, 0xfc0f0000, "v,R", 2 }, + +{ "sbm", 0xac080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zbm", 0xac000000, 0xfc080000, "f,xOA,X", 4 }, +{ "tbm", 0xa8080000, 0xfc080000, "f,xOA,X", 4 }, +{ "incmb", 0xa0000000, 0xfc080000, "xOA,X", 4 }, +{ "incmh", 0xa0080000, 0xfc080000, "xOA,X", 4 }, +{ "incmw", 0xa4000000, 0xfc080000, "xOA,X", 4 }, +{ "incmd", 0xa4080000, 0xfc080000, "xOA,X", 4 }, +{ "sbmd", 0x7c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zbmd", 0x7c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "tbmd", 0x78080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "ssm", 0x9c080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zsm", 0x9c000000, 0xfc080000, "f,xOA,X", 4 }, +{ "tsm", 0x98080000, 0xfc080000, "f,xOA,X", 4 }, + +{ "admb", 0xc8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "admh", 0xc8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "admw", 0xc8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "admd", 0xc8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "adr", 0x38000000, 0xfc0f0000, "r,R", 2 }, +{ "armb", 0xe8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "armh", 0xe8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "armw", 0xe8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "armd", 0xe8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "adi", 0xf8010000, 0xfc0f0000, "r,I", 4 }, +{ "sumb", 0xcc080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumh", 0xcc000001, 0xfc080001, "r,xOA,X", 4 }, +{ "sumw", 0xcc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumd", 0xcc000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sur", 0x3c000000, 0xfc0f0000, "r,R", 2 }, +{ "sui", 0xf8020000, 0xfc0f0000, "r,I", 4 }, +{ "mpmb", 0xc0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpmh", 0xc0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "mpmw", 0xc0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpr", 0x38020000, 0xfc0f0000, "r,R", 2 }, +{ "mprd", 0x3c0f0000, 0xfc0f0000, "r,R", 2 }, +{ "mpi", 0xf8030000, 0xfc0f0000, "r,I", 4 }, +{ "dvmb", 0xc4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvmh", 0xc4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "dvmw", 0xc4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvr", 0x380a0000, 0xfc0f0000, "r,R", 2 }, +{ "dvi", 0xf8040000, 0xfc0f0000, "r,I", 4 }, +{ "exs", 0x38080000, 0xfc0f0000, "r,R", 2 }, + +{ "advv", 0x30000000, 0xfc0f0000, "v,V", 2 }, +{ "advvd", 0x30080000, 0xfc0f0000, "v,V", 2 }, +{ "adrv", 0x34000000, 0xfc0f0000, "v,R", 2 }, +{ "adrvd", 0x34080000, 0xfc0f0000, "v,R", 2 }, +{ "suvv", 0x30010000, 0xfc0f0000, "v,V", 2 }, +{ "suvvd", 0x30090000, 0xfc0f0000, "v,V", 2 }, +{ "surv", 0x34010000, 0xfc0f0000, "v,R", 2 }, +{ "survd", 0x34090000, 0xfc0f0000, "v,R", 2 }, +{ "mpvv", 0x30020000, 0xfc0f0000, "v,V", 2 }, +{ "mprv", 0x34020000, 0xfc0f0000, "v,R", 2 }, + +{ "adfw", 0xe0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "adfd", 0xe0080002, 0xfc080002, "r,xOA,X", 4 }, +{ "adrfw", 0x38010000, 0xfc0f0000, "r,R", 2 }, +{ "adrfd", 0x38090000, 0xfc0f0000, "r,R", 2 }, +{ "surfw", 0xe0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "surfd", 0xe0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "surfw", 0x38030000, 0xfc0f0000, "r,R", 2 }, +{ "surfd", 0x380b0000, 0xfc0f0000, "r,R", 2 }, +{ "mpfw", 0xe4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpfd", 0xe4080002, 0xfc080002, "r,xOA,X", 4 }, +{ "mprfw", 0x38060000, 0xfc0f0000, "r,R", 2 }, +{ "mprfd", 0x380e0000, 0xfc0f0000, "r,R", 2 }, +{ "rfw", 0xe4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "rfd", 0xe4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "rrfw", 0x0c0e0000, 0xfc0f0000, "r", 2 }, +{ "rrfd", 0x0c0f0000, 0xfc0f0000, "r", 2 }, + +{ "advvfw", 0x30040000, 0xfc0f0000, "v,V", 2 }, +{ "advvfd", 0x300c0000, 0xfc0f0000, "v,V", 2 }, +{ "adrvfw", 0x34040000, 0xfc0f0000, "v,R", 2 }, +{ "adrvfd", 0x340c0000, 0xfc0f0000, "v,R", 2 }, +{ "suvvfw", 0x30050000, 0xfc0f0000, "v,V", 2 }, +{ "suvvfd", 0x300d0000, 0xfc0f0000, "v,V", 2 }, +{ "survfw", 0x34050000, 0xfc0f0000, "v,R", 2 }, +{ "survfd", 0x340d0000, 0xfc0f0000, "v,R", 2 }, +{ "mpvvfw", 0x30060000, 0xfc0f0000, "v,V", 2 }, +{ "mpvvfd", 0x300e0000, 0xfc0f0000, "v,V", 2 }, +{ "mprvfw", 0x34060000, 0xfc0f0000, "v,R", 2 }, +{ "mprvfd", 0x340e0000, 0xfc0f0000, "v,R", 2 }, +{ "rvfw", 0x30070000, 0xfc0f0000, "v", 2 }, +{ "rvfd", 0x300f0000, 0xfc0f0000, "v", 2 }, + +{ "fltw", 0x38070000, 0xfc0f0000, "r,R", 2 }, +{ "fltd", 0x380f0000, 0xfc0f0000, "r,R", 2 }, +{ "fixw", 0x38050000, 0xfc0f0000, "r,R", 2 }, +{ "fixd", 0x380d0000, 0xfc0f0000, "r,R", 2 }, +{ "cfpds", 0x3c090000, 0xfc0f0000, "r,R", 2 }, + +{ "fltvw", 0x080d0000, 0xfc0f0000, "v,V", 2 }, +{ "fltvd", 0x080f0000, 0xfc0f0000, "v,V", 2 }, +{ "fixvw", 0x080c0000, 0xfc0f0000, "v,V", 2 }, +{ "fixvd", 0x080e0000, 0xfc0f0000, "v,V", 2 }, +{ "cfpvds", 0x0c0d0000, 0xfc0f0000, "v,V", 2 }, + +{ "orvrn", 0x000a0000, 0xfc0f0000, "r,V", 2 }, +{ "andvrn", 0x00080000, 0xfc0f0000, "r,V", 2 }, +{ "frsteq", 0x04090000, 0xfc0f0000, "r,V", 2 }, +{ "sigma", 0x0c080000, 0xfc0f0000, "r,V", 2 }, +{ "sigmad", 0x0c0a0000, 0xfc0f0000, "r,V", 2 }, +{ "sigmf", 0x08080000, 0xfc0f0000, "r,V", 2 }, +{ "sigmfd", 0x080a0000, 0xfc0f0000, "r,V", 2 }, +{ "prodf", 0x04080000, 0xfc0f0000, "r,V", 2 }, +{ "prodfd", 0x040a0000, 0xfc0f0000, "r,V", 2 }, +{ "maxv", 0x10080000, 0xfc0f0000, "r,V", 2 }, +{ "maxvd", 0x100a0000, 0xfc0f0000, "r,V", 2 }, +{ "minv", 0x14080000, 0xfc0f0000, "r,V", 2 }, +{ "minvd", 0x140a0000, 0xfc0f0000, "r,V", 2 }, + +{ "lpsd", 0xf0000000, 0xfc080000, "xOA,X", 4 }, +{ "ldc", 0xf0080000, 0xfc080000, "xOA,X", 4 }, +{ "spm", 0x040c0000, 0xfc0f0000, "r", 2 }, +{ "rpm", 0x040d0000, 0xfc0f0000, "r", 2 }, +{ "tritr", 0x00070000, 0xfc0f0000, "r", 2 }, +{ "trrit", 0x00060000, 0xfc0f0000, "r", 2 }, +{ "rpswt", 0x04080000, 0xfc0f0000, "r", 2 }, +{ "exr", 0xf8070000, 0xfc0f0000, "", 4 }, +{ "halt", 0x00000000, 0xfc0f0000, "", 2 }, +{ "wait", 0x00010000, 0xfc0f0000, "", 2 }, +{ "nop", 0x00020000, 0xfc0f0000, "", 2 }, +{ "eiae", 0x00030000, 0xfc0f0000, "", 2 }, +{ "efae", 0x000d0000, 0xfc0f0000, "", 2 }, +{ "diae", 0x000e0000, 0xfc0f0000, "", 2 }, +{ "dfae", 0x000f0000, 0xfc0f0000, "", 2 }, +{ "spvc", 0xf8060000, 0xfc0f0000, "r,T,N", 4 }, +{ "rdsts", 0x00090000, 0xfc0f0000, "r", 2 }, +{ "setcpu", 0x000c0000, 0xfc0f0000, "r", 2 }, +{ "cmc", 0x000b0000, 0xfc0f0000, "r", 2 }, +{ "trrcu", 0x00040000, 0xfc0f0000, "r", 2 }, +{ "attnio", 0x00050000, 0xfc0f0000, "", 2 }, +{ "fudit", 0x28080000, 0xfc0f0000, "", 2 }, +{ "break", 0x28090000, 0xfc0f0000, "", 2 }, +{ "frzss", 0x280a0000, 0xfc0f0000, "", 2 }, +{ "ripi", 0x04040000, 0xfc0f0000, "r,R", 2 }, +{ "xcp", 0x04050000, 0xfc0f0000, "r", 2 }, +{ "block", 0x04060000, 0xfc0f0000, "", 2 }, +{ "unblock", 0x04070000, 0xfc0f0000, "", 2 }, +{ "trsc", 0x08060000, 0xfc0f0000, "r,R", 2 }, +{ "tscr", 0x08070000, 0xfc0f0000, "r,R", 2 }, +{ "fq", 0x04080000, 0xfc0f0000, "r", 2 }, +{ "flupte", 0x2c080000, 0xfc0f0000, "r", 2 }, +{ "rviu", 0x040f0000, 0xfc0f0000, "", 2 }, +{ "ldel", 0x280c0000, 0xfc0f0000, "r,R", 2 }, +{ "ldu", 0x280d0000, 0xfc0f0000, "r,R", 2 }, +{ "stdecc", 0x280b0000, 0xfc0f0000, "r,R", 2 }, +{ "trpc", 0x08040000, 0xfc0f0000, "r", 2 }, +{ "tpcr", 0x08050000, 0xfc0f0000, "r", 2 }, +{ "ghalt", 0x0c050000, 0xfc0f0000, "r", 2 }, +{ "grun", 0x0c040000, 0xfc0f0000, "", 2 }, +{ "tmpr", 0x2c0a0000, 0xfc0f0000, "r,R", 2 }, +{ "trmp", 0x2c0b0000, 0xfc0f0000, "r,R", 2 }, + +{ "trrve", 0x28060000, 0xfc0f0000, "r", 2 }, +{ "trver", 0x28070000, 0xfc0f0000, "r", 2 }, +{ "trvlr", 0x280f0000, 0xfc0f0000, "r", 2 }, + +{ "linkfl", 0x18000000, 0xfc0f0000, "r,R", 2 }, +{ "linkbl", 0x18020000, 0xfc0f0000, "r,R", 2 }, +{ "linkfp", 0x18010000, 0xfc0f0000, "r,R", 2 }, +{ "linkbp", 0x18030000, 0xfc0f0000, "r,R", 2 }, +{ "linkpl", 0x18040000, 0xfc0f0000, "r,R", 2 }, +{ "ulinkl", 0x18080000, 0xfc0f0000, "r,R", 2 }, +{ "ulinkp", 0x18090000, 0xfc0f0000, "r,R", 2 }, +{ "ulinktl", 0x180a0000, 0xfc0f0000, "r,R", 2 }, +{ "ulinktp", 0x180b0000, 0xfc0f0000, "r,R", 2 }, +}; + +int numopcodes = sizeof(gld_opcodes) / sizeof(gld_opcodes[0]); + +struct gld_opcode *endop = gld_opcodes + sizeof(gld_opcodes) / + sizeof(gld_opcodes[0]); diff --git a/gdb/ns32k-opcode.h b/gdb/ns32k-opcode.h new file mode 100644 index 00000000000..5f336e9cf05 --- /dev/null +++ b/gdb/ns32k-opcode.h @@ -0,0 +1,328 @@ +/* ns32k-opcode.h */ + +#ifndef ns32k_opcodeT +#define ns32k_opcodeT int +#endif /* no ns32k_opcodeT */ + +struct not_wot /* ns32k opcode table: wot to do with this */ + /* particular opcode */ +{ + int obits; /* number of opcode bits */ + int ibits; /* number of instruction bits */ + ns32k_opcodeT code; /* op-code (may be > 8 bits!) */ + char *args; /* how to compile said opcode */ +}; + +struct not /* ns32k opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct not_wot detail; /* rest of opcode table [datum] */ +}; + +/* Instructions look like this: + + basic instruction--1, 2, or 3 bytes + index byte for operand A, if operand A is indexed--1 byte + index byte for operand B, if operand B is indexed--1 byte + addressing extension for operand A + addressing extension for operand B + implied operands + + Operand A is the operand listed first in the following opcode table. + Operand B is the operand listed second in the following opcode table. + All instructions have at most 2 general operands, so this is enough. + The implied operands are associated with operands other than A and B. + + Each operand has a digit and a letter. + + The digit gives the position in the assembly language. The letter, + one of the following, tells us what kind of operand it is. */ + +/* F : 32 bit float + * L : 64 bit float + * B : byte + * W : word + * D : double-word + * Q : quad-word + * d : displacement + * q : quick + * i : immediate (8 bits) + * r : register number (3 bits) + * p : displacement - pc relative addressing +*/ +static struct not +notstrs[] = +{ + { "absf", 14,24, 0x35be, "1F2F" }, + { "absl", 14,24, 0x34be, "1L2L" }, + { "absb", 14,24, 0x304e, "1B2B" }, + { "absw", 14,24, 0x314e, "1W2W" }, + { "absd", 14,24, 0x334e, "1D2D" }, + { "acbb", 7,16, 0x4c, "2B1q3p" }, + { "acbw", 7,16, 0x4d, "2W1q3p" }, + { "acbd", 7,16, 0x4f, "2D1q3p" }, + { "addf", 14,24, 0x01be, "1F2F" }, + { "addl", 14,24, 0x00be, "1L2L" }, + { "addb", 6,16, 0x00, "1B2B" }, + { "addw", 6,16, 0x01, "1W2W" }, + { "addd", 6,16, 0x03, "1D2D" }, + { "addcb", 6,16, 0x10, "1B2B" }, + { "addcw", 6,16, 0x11, "1W2W" }, + { "addcd", 6,16, 0x13, "1D2D" }, + { "addpb", 14,24, 0x3c4e, "1B2B" }, + { "addpw", 14,24, 0x3d4e, "1W2W" }, + { "addpd", 14,24, 0x3f4e, "1D2D" }, + { "addqb", 7,16, 0x0c, "2B1q" }, + { "addqw", 7,16, 0x0d, "2W1q" }, + { "addqd", 7,16, 0x0f, "2D1q" }, + { "addr", 6,16, 0x27, "1D2D" }, + { "adjspb", 11,16, 0x057c, "1B" }, + { "adjspw", 11,16, 0x057d, "1W" }, + { "adjspd", 11,16, 0x057f, "1D" }, + { "andb", 6,16, 0x28, "1B2B" }, + { "andw", 6,16, 0x29, "1W2W" }, + { "andd", 6,16, 0x2b, "1D2D" }, + { "ashb", 14,24, 0x044e, "1B2B" }, + { "ashw", 14,24, 0x054e, "1B2W" }, + { "ashd", 14,24, 0x074e, "1B2D" }, + { "beq", 8,8, 0x0a, "1p" }, + { "bne", 8,8, 0x1a, "1p" }, + { "bcs", 8,8, 0x2a, "1p" }, + { "bcc", 8,8, 0x3a, "1p" }, + { "bhi", 8,8, 0x4a, "1p" }, + { "bls", 8,8, 0x5a, "1p" }, + { "bgt", 8,8, 0x6a, "1p" }, + { "ble", 8,8, 0x7a, "1p" }, + { "bfs", 8,8, 0x8a, "1p" }, + { "bfc", 8,8, 0x9a, "1p" }, + { "blo", 8,8, 0xaa, "1p" }, + { "bhs", 8,8, 0xba, "1p" }, + { "blt", 8,8, 0xca, "1p" }, + { "bge", 8,8, 0xda, "1p" }, + { "bicb", 6,16, 0x08, "1B2B" }, + { "bicw", 6,16, 0x09, "1W2W" }, + { "bicd", 6,16, 0x0b, "1D2D" }, + { "bicpsrb", 11,16, 0x17c, "1B" }, + { "bicpsrw", 11,16, 0x17d, "1W" }, + { "bispsrb", 11,16, 0x37c, "1B" }, + { "bispsrw", 11,16, 0x37d, "1W" }, + { "bpt", 8,8, 0xf2, "" }, + { "br", 8,8, 0xea, "1p" }, + { "bsr", 8,8, 0x02, "1p" }, + { "caseb", 11,16, 0x77c, "1B" }, + { "casew", 11,16, 0x77d, "1W" }, + { "cased", 11,16, 0x77f, "1D" }, + { "cbitb", 14,24, 0x084e, "1B2D" }, + { "cbitw", 14,24, 0x094e, "1W2D" }, + { "cbitd", 14,24, 0x0b4e, "1D2D" }, + { "cbitib", 14,24, 0x0c4e, "1B2D" }, + { "cbitiw", 14,24, 0x0d4e, "1W2D" }, + { "cbitid", 14,24, 0x0f4e, "1D2D" }, + { "checkb", 11,24, 0x0ee, "2A3B1r" }, + { "checkw", 11,24, 0x1ee, "2A3B1r" }, + { "checkd", 11,24, 0x3ee, "2A3D1r" }, + { "cmpf", 14,24, 0x09be, "1F2F" }, + { "cmpl", 14,24, 0x08be, "1L2L" }, + { "cmpb", 6,16, 0x04, "1B2B" }, + { "cmpw", 6,16, 0x05, "1W2W" }, + { "cmpd", 6,16, 0x07, "1D2D" }, + { "cmpmb", 14,24, 0x04ce, "1D2D3d" }, + { "cmpmw", 14,24, 0x05ce, "1D2D3d" }, + { "cmpmd", 14,24, 0x07ce, "1D2D3d" }, + { "cmpqb", 7,16, 0x1c, "2B1q" }, + { "cmpqw", 7,16, 0x1d, "2W1q" }, + { "cmpqd", 7,16, 0x1f, "2D1q" }, + { "cmpsb", 16,16, 0x040e, "1i" }, + { "cmpsw", 16,16, 0x050e, "1i" }, + { "cmpsd", 16,16, 0x070e, "1i" }, + { "cmpst", 16,16, 0x840e, "1i" }, + { "comb", 14,24, 0x344e, "1B2B" }, + { "comw", 14,24, 0x354e, "1W2W" }, + { "comd", 14,24, 0x374e, "1D2D" }, + { "cvtp", 11,24, 0x036e, "2D3D1r" }, + { "cxp", 8,8, 0x22, "1p" }, + { "cxpd", 11,16, 0x07f, "1D" }, + { "deib", 14,24, 0x2cce, "1B2W" }, + { "deiw", 14,24, 0x2dce, "1W2D" }, + { "deid", 14,24, 0x2fce, "1D2Q" }, + { "dia", 8,8, 0xc2, "" }, + { "divf", 14,24, 0x21be, "1F2F" }, + { "divl", 14,24, 0x20be, "1L2L" }, + { "divb", 14,24, 0x3cce, "1B2B" }, + { "divw", 14,24, 0x3dce, "1W2W" }, + { "divd", 14,24, 0x3fce, "1D2D" }, + { "enter", 8,8, 0x82, "1i2d" }, + { "exit", 8,8, 0x92, "1i" }, + { "extb", 11,24, 0x02e, "2D3B1r4d" }, + { "extw", 11,24, 0x12e, "2D3W1r4d" }, + { "extd", 11,24, 0x32e, "2D3D1r4d" }, + { "extsb", 14,24, 0x0cce, "1D2B3i" }, + { "extsw", 14,24, 0x0dce, "1D2W3i" }, + { "extsd", 14,24, 0x0fce, "1D2D3i" }, + { "ffsb", 14,24, 0x046e, "1B2B" }, + { "ffsw", 14,24, 0x056e, "1W2B" }, + { "ffsd", 14,24, 0x076e, "1D2B" }, + { "flag", 8,8, 0xd2, "" }, + { "floorfb", 14,24, 0x3c3e, "1F2B" }, + { "floorfw", 14,24, 0x3d3e, "1F2W" }, + { "floorfd", 14,24, 0x3f3e, "1F2D" }, + { "floorlb", 14,24, 0x383e, "1L2B" }, + { "floorlw", 14,24, 0x393e, "1L2W" }, + { "floorld", 14,24, 0x3b3e, "1L2D" }, + { "ibitb", 14,24, 0x384e, "1B2D" }, + { "ibitw", 14,24, 0x394e, "1W2D" }, + { "ibitd", 14,24, 0x3b4e, "1D2D" }, + { "indexb", 11,24, 0x42e, "2B3B1r" }, + { "indexw", 11,24, 0x52e, "2W3W1r" }, + { "indexd", 11,24, 0x72e, "2D3D1r" }, + { "insb", 11,24, 0x0ae, "2B3B1r4d" }, + { "insw", 11,24, 0x1ae, "2W3W1r4d" }, + { "insd", 11,24, 0x3ae, "2D3D1r4d" }, + { "inssb", 14,24, 0x08ce, "1B2D3i" }, + { "inssw", 14,24, 0x09ce, "1W2D3i" }, + { "inssd", 14,24, 0x0bce, "1D2D3i" }, + { "jsr", 11,16, 0x67f, "1A" }, + { "jump", 11,16, 0x27f, "1A" }, + { "lfsr", 19,24, 0x00f3e,"1D" }, + { "lmr", 15,24, 0x0b1e, "2D1q" }, + { "lprb", 7,16, 0x6c, "2B1q" }, + { "lprw", 7,16, 0x6d, "2W1q" }, + { "lprd", 7,16, 0x6f, "2D1q" }, + { "lshb", 14,24, 0x144e, "1B2B" }, + { "lshw", 14,24, 0x154e, "1B2W" }, + { "lshd", 14,24, 0x174e, "1B2D" }, + { "meib", 14,24, 0x24ce, "1B2W" }, + { "meiw", 14,24, 0x25ce, "1W2D" }, + { "meid", 14,24, 0x27ce, "1D2Q" }, + { "modb", 14,24, 0x38ce, "1B2B" }, + { "modw", 14,24, 0x39ce, "1W2W" }, + { "modd", 14,24, 0x3bce, "1D2D" }, + { "movf", 14,24, 0x05be, "1F2F" }, + { "movl", 14,24, 0x04be, "1L2L" }, + { "movb", 6,16, 0x14, "1B2B" }, + { "movw", 6,16, 0x15, "1W2W" }, + { "movd", 6,16, 0x17, "1D2D" }, + { "movbf", 14,24, 0x043e, "1B2F" }, + { "movwf", 14,24, 0x053e, "1W2F" }, + { "movdf", 14,24, 0x073e, "1D2F" }, + { "movbl", 14,24, 0x003e, "1B2L" }, + { "movwl", 14,24, 0x013e, "1W2L" }, + { "movdl", 14,24, 0x033e, "1D2L" }, + { "movfl", 14,24, 0x1b3e, "1F2L" }, + { "movlf", 14,24, 0x163e, "1L2F" }, + { "movmb", 14,24, 0x00ce, "1D2D3d" }, + { "movmw", 14,24, 0x00de, "1D2D3d" }, + { "movmd", 14,24, 0x00fe, "1D2D3d" }, + { "movqb", 7,16, 0x5c, "2B1q" }, + { "movqw", 7,16, 0x5d, "2B1q" }, + { "movqd", 7,16, 0x5f, "2B1q" }, + { "movsb", 16,16, 0x000e, "1i" }, + { "movsw", 16,16, 0x010e, "1i" }, + { "movsd", 16,16, 0x030e, "1i" }, + { "movst", 16,16, 0x800e, "1i" }, + { "movsub", 14,24, 0x0cae, "1A1A" }, + { "movsuw", 14,24, 0x0dae, "1A1A" }, + { "movsud", 14,24, 0x0fae, "1A1A" }, + { "movusb", 14,24, 0x1cae, "1A1A" }, + { "movusw", 14,24, 0x1dae, "1A1A" }, + { "movusd", 14,24, 0x1fae, "1A1A" }, + { "movxbd", 14,24, 0x1cce, "1B2D" }, + { "movxwd", 14,24, 0x1dce, "1W2D" }, + { "movxbw", 14,24, 0x10ce, "1B2W" }, + { "movzbd", 14,24, 0x18ce, "1B2D" }, + { "movzwd", 14,24, 0x19ce, "1W2D" }, + { "movzbw", 14,24, 0x14ce, "1B2W" }, + { "mulf", 14,24, 0x31be, "1F2F" }, + { "mull", 14,24, 0x30be, "1L2L" }, + { "mulb", 14,24, 0x20ce, "1B2B" }, + { "mulw", 14,24, 0x21ce, "1W2W" }, + { "muld", 14,24, 0x23ce, "1D2D" }, + { "negf", 14,24, 0x15be, "1F2F" }, + { "negl", 14,24, 0x14be, "1L2L" }, + { "negb", 14,24, 0x204e, "1B2B" }, + { "negw", 14,24, 0x214e, "1W2W" }, + { "negd", 14,24, 0x234e, "1D2D" }, + { "nop", 8,8, 0xa2, "" }, + { "notb", 14,24, 0x244e, "1B2B" }, + { "notw", 14,24, 0x254e, "1W2W" }, + { "notd", 14,24, 0x274e, "1D2D" }, + { "orb", 6,16, 0x18, "1B1B" }, + { "orw", 6,16, 0x19, "1W1W" }, + { "ord", 6,16, 0x1b, "1D2D" }, + { "quob", 14,24, 0x30ce, "1B2B" }, + { "quow", 14,24, 0x31ce, "1W2W" }, + { "quod", 14,24, 0x33ce, "1D2D" }, + { "rdval", 19,24, 0x0031e,"1A" }, + { "remb", 14,24, 0x34ce, "1B2B" }, + { "remw", 14,24, 0x35ce, "1W2W" }, + { "remd", 14,24, 0x37ce, "1D2D" }, + { "restore", 8,8, 0x72, "1i" }, + { "ret", 8,8, 0x12, "1d" }, + { "reti", 8,8, 0x52, "" }, + { "rett", 8,8, 0x42, "" }, + { "rotb", 14,24, 0x004e, "1B2B" }, + { "rotw", 14,24, 0x014e, "1B2W" }, + { "rotd", 14,24, 0x034e, "1B2D" }, + { "roundfb", 14,24, 0x243e, "1F2B" }, + { "roundfw", 14,24, 0x253e, "1F2W" }, + { "roundfd", 14,24, 0x273e, "1F2D" }, + { "roundlb", 14,24, 0x203e, "1L2B" }, + { "roundlw", 14,24, 0x213e, "1L2W" }, + { "roundld", 14,24, 0x233e, "1L2D" }, + { "rxp", 8,8, 0x32, "1d" }, + { "sCONDb", 7,16, 0x3c, "2B1q" }, + { "sCONDw", 7,16, 0x3d, "2D1q" }, + { "sCONDd", 7,16, 0x3f, "2D1q" }, + { "save", 8,8, 0x62, "1i" }, + { "sbitb", 14,24, 0x184e, "1B2A" }, + { "sbitw", 14,24, 0x194e, "1W2A" }, + { "sbitd", 14,24, 0x1b4e, "1D2A" }, + { "sbitib", 14,24, 0x1c4e, "1B2A" }, + { "sbitiw", 14,24, 0x1d4e, "1W2A" }, + { "sbitid", 14,24, 0x1f4e, "1D2A" }, + { "setcfg", 15,24, 0x0b0e, "5D1q" }, + { "sfsr", 14,24, 0x673e, "5D1D" }, + { "skpsb", 16,16, 0x0c0e, "1i" }, + { "skpsw", 16,16, 0x0d0e, "1i" }, + { "skpsd", 16,16, 0x0f0e, "1i" }, + { "skpst", 16,16, 0x8c0e, "1i" }, + { "smr", 15,24, 0x0f1e, "2D1q" }, + { "sprb", 7,16, 0x2c, "2B1q" }, + { "sprw", 7,16, 0x2d, "2W1q" }, + { "sprd", 7,16, 0x2f, "2D1q" }, + { "subf", 14,24, 0x11be, "1F2F" }, + { "subl", 14,24, 0x10be, "1L2L" }, + { "subb", 6,16, 0x20, "1B2B" }, + { "subw", 6,16, 0x21, "1W2W" }, + { "subd", 6,16, 0x23, "1D2D" }, + { "subcb", 6,16, 0x30, "1B2B" }, + { "subcw", 6,16, 0x31, "1W2W" }, + { "subcd", 6,16, 0x33, "1D2D" }, + { "subpb", 14,24, 0x2c4e, "1B2B" }, + { "subpw", 14,24, 0x2d4e, "1W2W" }, + { "subpd", 14,24, 0x2f4e, "1D2D" }, +#ifndef NS32K_SVC_IMMED_OPERANDS + { "svc", 8,8, 0xe2, "2i1i" }, /* not really, but unix uses it */ +#else + { "svc", 8,8, 0xe2, "" }, /* not really, but unix uses it */ +#endif + { "tbitb", 6,16, 0x34, "1B2A" }, + { "tbitw", 6,16, 0x35, "1W2A" }, + { "tbitd", 6,16, 0x37, "1D2A" }, + { "truncfb", 14,24, 0x2c3e, "1F2B" }, + { "truncfw", 14,24, 0x2d3e, "1F2W" }, + { "truncfd", 14,24, 0x2f3e, "1F2D" }, + { "trunclb", 14,24, 0x283e, "1L2B" }, + { "trunclw", 14,24, 0x293e, "1L2W" }, + { "truncld", 14,24, 0x2b3e, "1L2D" }, + { "wait", 8,8, 0xb2, "" }, + { "wrval", 19,24, 0x0071e,"1A" }, + { "xorb", 6,16, 0x38, "1B2B" }, + { "xorw", 6,16, 0x39, "1W2W" }, + { "xord", 6,16, 0x3b, "1D2D" }, +}; /* notstrs */ + +/* end: ns32k.opcode.h */ + +#define MAX_ARGS 4 +#define ARG_LEN 50 diff --git a/gdb/ns32k-pinsn.c b/gdb/ns32k-pinsn.c new file mode 100644 index 00000000000..1c558e96ed7 --- /dev/null +++ b/gdb/ns32k-pinsn.c @@ -0,0 +1,523 @@ +/* Print 32000 instructions for GDB, the GNU debugger. + Copyright (C) 1986,1988 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "ns32k-opcode.h" +#include "gdbcore.h" + +/* 32000 instructions are never longer than this. */ +#define MAXLEN 62 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof notstrs / sizeof notstrs[0]) + +extern char *reg_names[]; + +#define NEXT_IS_ADDR '|' + +/* + * extract "count" bits starting "offset" bits + * into buffer + */ + +int +bit_extract (buffer, offset, count) + char *buffer; + int offset; + int count; +{ + int result; + int mask; + int bit; + + buffer += offset >> 3; + offset &= 7; + bit = 1; + result = 0; + while (count--) + { + if ((*buffer & (1 << offset))) + result |= bit; + if (++offset == 8) + { + offset = 0; + buffer++; + } + bit <<= 1; + } + return result; +} + +float +fbit_extract (buffer, offset, count) +{ + union { + int ival; + float fval; + } foo; + + foo.ival = bit_extract (buffer, offset, 32); + return foo.fval; +} + +double +dbit_extract (buffer, offset, count) +{ + union { + struct {int low, high; } ival; + double dval; + } foo; + + foo.ival.low = bit_extract (buffer, offset, 32); + foo.ival.high = bit_extract (buffer, offset+32, 32); + return foo.dval; +} + +sign_extend (value, bits) +{ + value = value & ((1 << bits) - 1); + return (value & (1 << (bits-1)) + ? value | (~((1 << bits) - 1)) + : value); +} + +flip_bytes (ptr, count) + char *ptr; + int count; +{ + char tmp; + + while (count > 0) + { + tmp = *ptr; + ptr[0] = ptr[count-1]; + ptr[count-1] = tmp; + ptr++; + count -= 2; + } +} + +/* Given a character C, does it represent a general addressing mode? */ +#define Is_gen(c) \ + ((c) == 'F' || (c) == 'L' || (c) == 'B' \ + || (c) == 'W' || (c) == 'D' || (c) == 'A') + +/* Adressing modes. */ +#define Adrmod_index_byte 0x1c +#define Adrmod_index_word 0x1d +#define Adrmod_index_doubleword 0x1e +#define Adrmod_index_quadword 0x1f + +/* Is MODE an indexed addressing mode? */ +#define Adrmod_is_index(mode) \ + (mode == Adrmod_index_byte \ + || mode == Adrmod_index_word \ + || mode == Adrmod_index_doubleword \ + || mode == Adrmod_index_quadword) + + +/* Print the 32000 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; + unsigned short first_word; + int gen, disp; + int ioffset; /* bits into instruction */ + int aoffset; /* bits into arguments */ + char arg_bufs[MAX_ARGS+1][ARG_LEN]; + int argnum; + int maxarg; + + read_memory (memaddr, buffer, MAXLEN); + + first_word = *(unsigned short *) buffer; + for (i = 0; i < NOPCODES; i++) + if ((first_word & ((1 << notstrs[i].detail.obits) - 1)) + == notstrs[i].detail.code) + break; + + /* Handle undefined instructions. */ + if (i == NOPCODES) + { + fprintf (stream, "0%o", buffer[0]); + return 1; + } + + fprintf (stream, "%s", notstrs[i].name); + + ioffset = notstrs[i].detail.ibits; + aoffset = notstrs[i].detail.ibits; + d = notstrs[i].detail.args; + + if (*d) + { + /* Offset in bits of the first thing beyond each index byte. + Element 0 is for operand A and element 1 is for operand B. + The rest are irrelevant, but we put them here so we don't + index outside the array. */ + int index_offset[MAX_ARGS]; + + /* 0 for operand A, 1 for operand B, greater for other args. */ + int whicharg = 0; + + fputc ('\t', stream); + + maxarg = 0; + + /* First we have to find and keep track of the index bytes, + if we are using scaled indexed addressing mode, since the index + bytes occur right after the basic instruction, not as part + of the addressing extension. */ + if (Is_gen(d[1])) + { + int addr_mode = bit_extract (buffer, ioffset - 5, 5); + + if (Adrmod_is_index (addr_mode)) + { + aoffset += 8; + index_offset[0] = aoffset; + } + } + if (d[2] && Is_gen(d[3])) + { + int addr_mode = bit_extract (buffer, ioffset - 10, 5); + + if (Adrmod_is_index (addr_mode)) + { + aoffset += 8; + index_offset[1] = aoffset; + } + } + + while (*d) + { + argnum = *d - '1'; + d++; + if (argnum > maxarg && argnum < MAX_ARGS) + maxarg = argnum; + ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer, + memaddr, arg_bufs[argnum], + index_offset[whicharg]); + d++; + whicharg++; + } + for (argnum = 0; argnum <= maxarg; argnum++) + { + CORE_ADDR addr; + char *ch, *index (); + for (ch = arg_bufs[argnum]; *ch;) + { + if (*ch == NEXT_IS_ADDR) + { + ++ch; + addr = atoi (ch); + print_address (addr, stream); + while (*ch && *ch != NEXT_IS_ADDR) + ++ch; + if (*ch) + ++ch; + } + else + putc (*ch++, stream); + } + if (argnum < maxarg) + fprintf (stream, ", "); + } + } + return aoffset / 8; +} + +/* Print an instruction operand of category given by d. IOFFSET is + the bit position below which small (<1 byte) parts of the operand can + be found (usually in the basic instruction, but for indexed + addressing it can be in the index byte). AOFFSETP is a pointer to the + bit position of the addressing extension. BUFFER contains the + instruction. ADDR is where BUFFER was read from. Put the disassembled + version of the operand in RESULT. INDEX_OFFSET is the bit position + of the index byte (it contains garbage if this operand is not a + general operand using scaled indexed addressing mode). */ + +print_insn_arg (d, ioffset, aoffsetp, buffer, addr, result, index_offset) + char d; + int ioffset, *aoffsetp; + char *buffer; + CORE_ADDR addr; + char *result; + int index_offset; +{ + int addr_mode; + float Fvalue; + double Lvalue; + int Ivalue; + int disp1, disp2; + int index; + + switch (d) + { + case 'F': + case 'L': + case 'B': + case 'W': + case 'D': + case 'A': + addr_mode = bit_extract (buffer, ioffset-5, 5); + ioffset -= 5; + switch (addr_mode) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + switch (d) + { + case 'F': + case 'L': + sprintf (result, "f%d", addr_mode); + break; + default: + sprintf (result, "r%d", addr_mode); + } + break; + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(r%d)", disp1, addr_mode & 7); + break; + case 0x10: + case 0x11: + case 0x12: + disp1 = get_displacement (buffer, aoffsetp); + disp2 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(%d(%s))", disp2, disp1, + addr_mode==0x10?"fp":addr_mode==0x11?"sp":"sb"); + break; + case 0x13: + sprintf (result, "reserved"); + break; + case 0x14: + switch (d) + { + case 'B': + Ivalue = bit_extract (buffer, *aoffsetp, 8); + Ivalue = sign_extend (Ivalue, 8); + *aoffsetp += 8; + sprintf (result, "$%d", Ivalue); + break; + case 'W': + Ivalue = bit_extract (buffer, *aoffsetp, 16); + flip_bytes (&Ivalue, 2); + *aoffsetp += 16; + Ivalue = sign_extend (Ivalue, 16); + sprintf (result, "$%d", Ivalue); + break; + case 'D': + Ivalue = bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Ivalue, 4); + *aoffsetp += 32; + sprintf (result, "$%d", Ivalue); + break; + case 'A': + Ivalue = bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Ivalue, 4); + *aoffsetp += 32; + sprintf (result, "$|%d|", Ivalue); + break; + case 'F': + Fvalue = fbit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Fvalue, 4); + *aoffsetp += 32; + sprintf (result, "$%g", Fvalue); + break; + case 'L': + Lvalue = dbit_extract (buffer, *aoffsetp, 64); + flip_bytes (&Lvalue, 8); + *aoffsetp += 64; + sprintf (result, "$%g", Lvalue); + break; + } + break; + case 0x15: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "@|%d|", disp1); + break; + case 0x16: + disp1 = get_displacement (buffer, aoffsetp); + disp2 = get_displacement (buffer, aoffsetp); + sprintf (result, "EXT(%d) + %d", disp1, disp2); + break; + case 0x17: + sprintf (result, "tos"); + break; + case 0x18: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(fp)", disp1); + break; + case 0x19: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(sp)", disp1); + break; + case 0x1a: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(sb)", disp1); + break; + case 0x1b: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "|%d|", addr + disp1); + break; + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + index = bit_extract (buffer, index_offset - 8, 3); + print_insn_arg (d, index_offset, aoffsetp, buffer, addr, + result, 0); + { + static char *ind[] = {"b", "w", "d", "q"}; + char *off; + + off = result + strlen (result); + sprintf (off, "[r%d:%s]", index, + ind[addr_mode & 3]); + } + break; + } + break; + case 'q': + Ivalue = bit_extract (buffer, ioffset-4, 4); + Ivalue = sign_extend (Ivalue, 4); + sprintf (result, "%d", Ivalue); + ioffset -= 4; + break; + case 'r': + Ivalue = bit_extract (buffer, ioffset-3, 3); + sprintf (result, "r%d", Ivalue&7); + ioffset -= 3; + break; + case 'd': + sprintf (result, "%d", get_displacement (buffer, aoffsetp)); + break; + case 'p': + sprintf (result, "%c%d%c", NEXT_IS_ADDR, + addr + get_displacement (buffer, aoffsetp), + NEXT_IS_ADDR); + break; + case 'i': + Ivalue = bit_extract (buffer, *aoffsetp, 8); + *aoffsetp += 8; + sprintf (result, "0x%x", Ivalue); + break; + } + return ioffset; +} + +get_displacement (buffer, aoffsetp) + char *buffer; + int *aoffsetp; +{ + int Ivalue; + + Ivalue = bit_extract (buffer, *aoffsetp, 8); + switch (Ivalue & 0xc0) + { + case 0x00: + case 0x40: + Ivalue = sign_extend (Ivalue, 7); + *aoffsetp += 8; + break; + case 0x80: + Ivalue = bit_extract (buffer, *aoffsetp, 16); + flip_bytes (&Ivalue, 2); + Ivalue = sign_extend (Ivalue, 14); + *aoffsetp += 16; + break; + case 0xc0: + Ivalue = bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Ivalue, 4); + Ivalue = sign_extend (Ivalue, 30); + *aoffsetp += 32; + break; + } + return Ivalue; +} + +/* Return the number of locals in the current frame given a pc + pointing to the enter instruction. This is used in the macro + FRAME_FIND_SAVED_REGS. */ + +ns32k_localcount (enter_pc) + CORE_ADDR enter_pc; +{ + unsigned char localtype; + int localcount; + + localtype = read_memory_integer (enter_pc+2, 1); + if ((localtype & 0x80) == 0) + localcount = localtype; + else if ((localtype & 0xc0) == 0x80) + localcount = (((localtype & 0x3f) << 8) + | (read_memory_integer (enter_pc+3, 1) & 0xff)); + else + localcount = (((localtype & 0x3f) << 24) + | ((read_memory_integer (enter_pc+3, 1) & 0xff) << 16) + | ((read_memory_integer (enter_pc+4, 1) & 0xff) << 8 ) + | (read_memory_integer (enter_pc+5, 1) & 0xff)); + return localcount; +} + +/* + * Get the address of the enter opcode for the function + * containing PC, if there is an enter for the function, + * and if the pc is between the enter and exit. + * Returns positive address if pc is between enter/exit, + * 1 if pc before enter or after exit, 0 otherwise. + */ + +CORE_ADDR +ns32k_get_enter_addr (pc) + CORE_ADDR pc; +{ + CORE_ADDR enter_addr; + unsigned char op; + + if (ABOUT_TO_RETURN (pc)) + return 1; /* after exit */ + + enter_addr = get_pc_function_start (pc); + + if (pc == enter_addr) + return 1; /* before enter */ + + op = read_memory_integer (enter_addr, 1); + + if (op != 0x82) + return 0; /* function has no enter/exit */ + + return enter_addr; /* pc is between enter and exit */ +} diff --git a/gdb/obstack.c b/gdb/obstack.c new file mode 100755 index 00000000000..590fcaa9dcf --- /dev/null +++ b/gdb/obstack.c @@ -0,0 +1,333 @@ +/* obstack.c - subroutines used implicitly by object stack macros + Copyright (C) 1988 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 1, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "obstack.h" + +#ifdef __STDC__ +#define POINTER void * +#else +#define POINTER char * +#endif + +/* Determine default alignment. */ +struct fooalign {char x; double d;}; +#define DEFAULT_ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0) +/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. + But in fact it might be less smart and round addresses to as much as + DEFAULT_ROUNDING. So we prepare for it to do that. */ +union fooround {long x; double d;}; +#define DEFAULT_ROUNDING (sizeof (union fooround)) + +/* When we copy a long block of data, this is the unit to do it with. + On some machines, copying successive ints does not work; + in such a case, redefine COPYING_UNIT to `long' (if that works) + or `char' as a last resort. */ +#ifndef COPYING_UNIT +#define COPYING_UNIT int +#endif + +/* The non-GNU-C macros copy the obstack into this global variable + to avoid multiple evaluation. */ + +struct obstack *_obstack; + +/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). + Objects start on multiples of ALIGNMENT (0 means use default). + CHUNKFUN is the function to use to allocate chunks, + and FREEFUN the function to free them. */ + +void +_obstack_begin (h, size, alignment, chunkfun, freefun) + struct obstack *h; + int size; + int alignment; + POINTER (*chunkfun) (); + void (*freefun) (); +{ + register struct _obstack_chunk* chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = chunkfun; + h->freefun = freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + + chunk = h->chunk = (struct _obstack_chunk *)(*h->chunkfun) (h->chunk_size); + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; +} + +/* Allocate a new current chunk for the obstack *H + on the assumption that LENGTH bytes need to be added + to the current object, or a new object of length LENGTH allocated. + Copies any partial object from the end of the old chunk + to the beginning of the new one. + + The function must be "int" so it can be used in non-ANSI C + compilers in a : expression. */ + +int +_obstack_newchunk (h, length) + struct obstack *h; + int length; +{ + register struct _obstack_chunk* old_chunk = h->chunk; + register struct _obstack_chunk* new_chunk; + register long new_size; + register int obj_size = h->next_free - h->object_base; + register int i; + int already; + + /* Compute size for new chunk. */ + new_size = (obj_size + length) + (obj_size >> 3) + 100; + if (new_size < h->chunk_size) + new_size = h->chunk_size; + + /* Allocate and initialize the new chunk. */ + new_chunk = h->chunk = (struct _obstack_chunk *)(*h->chunkfun) (new_size); + new_chunk->prev = old_chunk; + new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; + + /* Move the existing object to the new chunk. + Word at a time is fast and is safe if the object + is sufficiently aligned. */ + if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) + { + for (i = obj_size / sizeof (COPYING_UNIT) - 1; + i >= 0; i--) + ((COPYING_UNIT *)new_chunk->contents)[i] + = ((COPYING_UNIT *)h->object_base)[i]; + /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, + but that can cross a page boundary on a machine + which does not do strict alignment for COPYING_UNITS. */ + already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); + } + else + already = 0; + /* Copy remaining bytes one by one. */ + for (i = already; i < obj_size; i++) + new_chunk->contents[i] = h->object_base[i]; + + h->object_base = new_chunk->contents; + h->next_free = h->object_base + obj_size; +} + +/* Return nonzero if object OBJ has been allocated from obstack H. + This is here for debugging. + If you use it in a program, you are probably losing. */ + +int +_obstack_allocated_p (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + while (lp != 0 && ((POINTER)lp > obj || (POINTER)(lp)->limit < obj)) + { + plp = lp -> prev; + lp = plp; + } + return lp != 0; +} + +/* Free objects in obstack H, including OBJ and everything allocate + more recently than OBJ. If OBJ is zero, free everything in H. */ + +#ifdef __STDC__ +#undef obstack_free +void +obstack_free (struct obstack *h, POINTER obj) +#else +int +_obstack_free (h, obj) + struct obstack *h; + POINTER obj; +#endif +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj)) + { + plp = lp -> prev; + (*h->freefun) ((POINTER) lp); + lp = plp; + } + if (lp) + { + (h)->object_base = (h)->next_free = (char *)(obj); + (h)->chunk_limit = lp->limit; + (h)->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +/* Let same .o link with output of gcc and other compilers. */ + +#ifdef __STDC__ +int +_obstack_free (h, obj) + struct obstack *h; + POINTER obj; +{ + obstack_free (h, obj); +} +#endif + +/* #if 0 */ +/* These are now turned off because the applications do not use it + and it uses bcopy via obstack_grow, which causes trouble on sysV. */ + +/* Now define the functional versions of the obstack macros. + Define them to simply use the corresponding macros to do the job. */ + +#ifdef __STDC__ +/* These function definitions do not work with non-ANSI preprocessors; + they won't pass through the macro names in parentheses. */ + +/* The function names appear in parentheses in order to prevent + the macro-definitions of the names from being expanded there. */ + +POINTER (obstack_base) (obstack) + struct obstack *obstack; +{ + return obstack_base (obstack); +} + +POINTER (obstack_next_free) (obstack) + struct obstack *obstack; +{ + return obstack_next_free (obstack); +} + +int (obstack_object_size) (obstack) + struct obstack *obstack; +{ + return obstack_object_size (obstack); +} + +int (obstack_room) (obstack) + struct obstack *obstack; +{ + return obstack_room (obstack); +} + +void (obstack_grow) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow (obstack, pointer, length); +} + +void (obstack_grow0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow0 (obstack, pointer, length); +} + +void (obstack_1grow) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow (obstack, character); +} + +void (obstack_blank) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank (obstack, length); +} + +void (obstack_1grow_fast) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow_fast (obstack, character); +} + +void (obstack_blank_fast) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank_fast (obstack, length); +} + +POINTER (obstack_finish) (obstack) + struct obstack *obstack; +{ + return obstack_finish (obstack); +} + +POINTER (obstack_alloc) (obstack, length) + struct obstack *obstack; + int length; +{ + return obstack_alloc (obstack, length); +} + +POINTER (obstack_copy) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy (obstack, pointer, length); +} + +POINTER (obstack_copy0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy0 (obstack, pointer, length); +} + +#endif /* __STDC__ */ + +/* #endif 0 */ diff --git a/gdb/obstack.h b/gdb/obstack.h new file mode 100755 index 00000000000..2e80c9c70fa --- /dev/null +++ b/gdb/obstack.h @@ -0,0 +1,416 @@ +/* obstack.h - object stack macros + Copyright (C) 1988 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 1, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "fascist pig with a read-only mind" +[Gosper's immortal quote from HAKMEM item 154, out of context] you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a symbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beginning of the new larger chunk. We then carry on +accreting characters to the end of the object as we normally would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' a obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef __OBSTACKS__ +#define __OBSTACKS__ + +/* We use subtraction of (char *)0 instead of casting to int + because on word-addressable machines a simple cast to int + may ignore the byte-within-word field of the pointer. */ + +#ifndef __PTR_TO_INT +#define __PTR_TO_INT(P) ((P) - (char *)0) +#endif + +#ifndef __INT_TO_PTR +#define __INT_TO_PTR(P) ((P) + (char *)0) +#endif + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + int temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ +#ifdef __STDC__ + void *(*chunkfun) (); /* User's fcn to allocate a chunk. */ +#else + char *(*chunkfun) (); /* User's fcn to allocate a chunk. */ +#endif + void (*freefun) (); /* User's function to free a chunk. */ +}; + +#ifdef __STDC__ + +/* Do the function-declarations after the structs + but before defining the macros. */ + +void obstack_init (struct obstack *obstack); + +void * obstack_alloc (struct obstack *obstack, int size); + +void * obstack_copy (struct obstack *obstack, void *address, int size); +void * obstack_copy0 (struct obstack *obstack, void *address, int size); + +void obstack_free (struct obstack *obstack, void *block); + +void obstack_blank (struct obstack *obstack, int size); + +void obstack_grow (struct obstack *obstack, void *data, int size); +void obstack_grow0 (struct obstack *obstack, void *data, int size); + +void obstack_1grow (struct obstack *obstack, int data_char); +void obstack_ptr_grow (struct obstack *obstack, void *data); +void obstack_int_grow (struct obstack *obstack, int data); + +void * obstack_finish (struct obstack *obstack); + +int obstack_object_size (struct obstack *obstack); + +int obstack_room (struct obstack *obstack); +void obstack_1grow_fast (struct obstack *obstack, int data_char); +void obstack_ptr_grow_fast (struct obstack *obstack, void *data); +void obstack_int_grow_fast (struct obstack *obstack, int data); +void obstack_blank_fast (struct obstack *obstack, int size); + +void * obstack_base (struct obstack *obstack); +void * obstack_next_free (struct obstack *obstack); +int obstack_alignment_mask (struct obstack *obstack); +int obstack_chunk_size (struct obstack *obstack); + +#endif /* __STDC__ */ + +/* Non-ANSI C cannot really support alternative functions for these macros, + so we do not declare them. */ + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +#define obstack_init(h) \ + _obstack_begin ((h), 0, 0, obstack_chunk_alloc, obstack_chunk_free) + +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, obstack_chunk_alloc, obstack_chunk_free) + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#if defined (__GNUC__) && defined (__STDC__) + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +#define obstack_object_size(OBSTACK) \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +#define obstack_room(OBSTACK) \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +#define obstack_grow(OBSTACK,where,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len > __o->chunk_limit) \ + ? _obstack_newchunk (__o, __len) : 0); \ + bcopy (where, __o->next_free, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_grow0(OBSTACK,where,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len + 1 > __o->chunk_limit) \ + ? _obstack_newchunk (__o, __len + 1) : 0), \ + bcopy (where, __o->next_free, __len), \ + __o->next_free += __len, \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +#define obstack_1grow(OBSTACK,datum) \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + 1 > __o->chunk_limit) \ + ? _obstack_newchunk (__o, 1) : 0), \ + *(__o->next_free)++ = (datum); \ + (void) 0; }) + +/* These assume that the obstack alignment is good enough for pointers or ints, + and that the data added so far to the current object + shares that much alignment. */ + +#define obstack_ptr_grow(OBSTACK,datum) \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + sizeof (void *) > __o->chunk_limit) \ + ? _obstack_newchunk (__o, sizeof (void *)) : 0), \ + *(*(void ***)&__o->next_free)++ = ((void *)datum); \ + (void) 0; }) + +#define obstack_int_grow(OBSTACK,datum) \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + sizeof (int) > __o->chunk_limit) \ + ? _obstack_newchunk (__o, sizeof (int)) : 0), \ + *(*(int **)&__o->next_free)++ = ((int)datum); \ + (void) 0; }) + +#define obstack_ptr_grow_fast(h,aptr) (*(*(void ***)&(h)->next_free)++ = (void *)aptr) +#define obstack_int_grow_fast(h,aint) (*(*(int **)&(h)->next_free)++ = (int)aint) + +#define obstack_blank(OBSTACK,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->chunk_limit - __o->next_free < __len) \ + ? _obstack_newchunk (__o, __len) : 0); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_alloc(OBSTACK,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +#define obstack_copy(OBSTACK,where,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_copy0(OBSTACK,where,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_finish(OBSTACK) \ +({ struct obstack *__o = (OBSTACK); \ + void *value = (void *) __o->object_base; \ + __o->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT (__o->next_free)+__o->alignment_mask)\ + & ~ (__o->alignment_mask)); \ + ((__o->next_free - (char *)__o->chunk \ + > __o->chunk_limit - (char *)__o->chunk) \ + ? (__o->next_free = __o->chunk_limit) : 0); \ + __o->object_base = __o->next_free; \ + value; }) + +#define obstack_free(OBSTACK, OBJ) \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (OBJ); \ + if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = __obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +#define obstack_object_size(h) \ + (unsigned) ((h)->next_free - (h)->object_base) + +#define obstack_room(h) \ + (unsigned) ((h)->chunk_limit - (h)->next_free) + +#define obstack_grow(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), (h)->temp) : 0), \ + bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp) + +#define obstack_grow0(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), (h)->temp + 1) : 0), \ + bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp, \ + *((h)->next_free)++ = 0) + +#define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), 1) : 0), \ + *((h)->next_free)++ = (datum)) + +#define obstack_ptr_grow(h,datum) \ +( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), sizeof (char *)) : 0), \ + *(*(char ***)&(h)->next_free)++ = ((char *)datum)) + +#define obstack_int_grow(h,datum) \ +( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), sizeof (int)) : 0), \ + *(*(int **)&(h)->next_free)++ = ((int)datum)) + +#define obstack_ptr_grow_fast(h,aptr) (*(*(char ***)&(h)->next_free)++ = (char *)aptr) +#define obstack_int_grow_fast(h,aint) (*(*(int **)&(h)->next_free)++ = (int)aint) + +#define obstack_blank(h,length) \ +( (h)->temp = (length), \ + (((h)->chunk_limit - (h)->next_free < (h)->temp) \ + ? _obstack_newchunk ((h), (h)->temp) : 0), \ + (h)->next_free += (h)->temp) + +#define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +#define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_finish(h) \ +( (h)->temp = __PTR_TO_INT ((h)->object_base), \ + (h)->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \ + & ~ ((h)->alignment_mask)), \ + (((h)->next_free - (char *)(h)->chunk \ + > (h)->chunk_limit - (char *)(h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + __INT_TO_PTR ((h)->temp)) + +#ifdef __STDC__ +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp >= 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : ((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0))) +#else +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp >= 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (int) _obstack_free ((h), (h)->temp + (char *) (h)->chunk))) +#endif + +#endif /* not __GNUC__ or not __STDC__ */ + +/* Declare the external functions we use; they are in obstack.c. */ + +#ifdef __STDC__ + extern int _obstack_newchunk (struct obstack *h, int length); + extern int _obstack_free (struct obstack *h, void *obj); + extern void _obstack_begin (struct obstack *h, int size, int alignment, + void *(*chunkfun) (), void (*freefun) ()); +#else + extern int _obstack_newchunk (); + extern int _obstack_free (); + extern void _obstack_begin (); +#endif + +#endif /* not __OBSTACKS__ */ + diff --git a/gdb/param-no-tm.h b/gdb/param-no-tm.h new file mode 100755 index 00000000000..2e4af53fb73 --- /dev/null +++ b/gdb/param-no-tm.h @@ -0,0 +1,76 @@ +/* Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (PARAM_H) +#define PARAM_H 1 + +/* DO NOT #include "tm.h" -- a particular tm file has been inc'd by caller */ + +#include "xm.h" + +/* TARGET_BYTE_ORDER and HOST_BYTE_ORDER should be defined to one of these. */ +#if !defined (BIG_ENDIAN) +#define BIG_ENDIAN 4321 +#endif + +#if !defined (LITTLE_ENDIAN) +#define LITTLE_ENDIAN 1234 +#endif + +/* The bit byte-order has to do just with numbering of bits in + debugging symbols and such. Conceptually, it's quite separate + from byte/word byte order. */ + +#if TARGET_BYTE_ORDER == BIG_ENDIAN +#define BITS_BIG_ENDIAN 1 +#endif + +#if TARGET_BYTE_ORDER == LITTLE_ENDIAN +/*#define BITS_BIG_ENDIAN */ +#endif + +/* Swap LEN bytes at BUFFER between target and host byte-order. */ +#if TARGET_BYTE_ORDER == HOST_BYTE_ORDER +#define SWAP_TARGET_AND_HOST(buffer,len) +#else /* Target and host byte order differ. */ +#define SWAP_TARGET_AND_HOST(buffer,len) \ + { \ + char tmp; \ + char *p = (char *)(buffer); \ + char *q = ((char *)(buffer)) + len - 1; \ + for (; p < q; p++, q--) \ + { \ + tmp = *q; \ + *q = *p; \ + *p = tmp; \ + } \ + } +#endif /* Target and host byte order differ. */ + +/* On some machines there are bits in addresses which are not really + part of the address, but are used by the kernel, the hardware, etc. + for special purposes. ADDR_BITS_REMOVE takes out any such bits + so we get a "real" address such as one would find in a symbol + table. ADDR_BITS_SET sets those bits the way the system wants + them. */ +#if !defined (ADDR_BITS_REMOVE) +#define ADDR_BITS_REMOVE(addr) (addr) +#define ADDR_BITS_SET(addr) (addr) +#endif /* No ADDR_BITS_REMOVE. */ + +#endif /* param.h not already included. */ diff --git a/gdb/param.h b/gdb/param.h new file mode 100755 index 00000000000..0a569366bbb --- /dev/null +++ b/gdb/param.h @@ -0,0 +1,30 @@ +/* Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The standard thing is to include param.h. However, files that are + specific to a particular target can include that tm-xxx.h file and + param-no-tm.h. Any future inclusions of param.h will be protected + against by the #if !defined stuff below. */ + +#if !defined (PARAM_H) +#include "tm.h" +#endif + +#include "param-no-tm.h" + +#define PARAM_H 1 diff --git a/gdb/pn-opcode.h b/gdb/pn-opcode.h new file mode 100755 index 00000000000..fde4764c02c --- /dev/null +++ b/gdb/pn-opcode.h @@ -0,0 +1,282 @@ +/* Print GOULD PN (PowerNode) instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct gld_opcode +{ + char *name; + unsigned long opcode; + unsigned long mask; + char *args; + int length; +}; + +/* We store four bytes of opcode for all opcodes because that + is the most any of them need. The actual length of an instruction + is always at least 2 bytes, and at most four. The length of the + instruction is based on the opcode. + + The mask component is a mask saying which bits must match + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing characters + that are used to format the arguments to the instruction. */ + +/* Kinds of operands: + r Register in first field + R Register in second field + b Base register in first field + B Base register in second field + v Vector register in first field + V Vector register in first field + A Optional address register (base register) + X Optional index register + I Immediate data (16bits signed) + O Offset field (16bits signed) + h Offset field (15bits signed) + d Offset field (14bits signed) + S Shift count field + + any other characters are printed as is... +*/ + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ +struct gld_opcode gld_opcodes[] = +{ +{ "abm", 0xa0080000, 0xfc080000, "f,xOA,X", 4 }, +{ "abr", 0x18080000, 0xfc0c0000, "r,f", 2 }, +{ "aci", 0xfc770000, 0xfc7f8000, "r,I", 4 }, +{ "adfd", 0xe0080002, 0xfc080002, "r,xOA,X", 4 }, +{ "adfw", 0xe0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "adi", 0xc8010000, 0xfc7f0000, "r,I", 4 }, +{ "admb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "admd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "admh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "admw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "adr", 0x38000000, 0xfc0f0000, "r,R", 2 }, +{ "adrfd", 0x38090000, 0xfc0f0000, "r,R", 2 }, +{ "adrfw", 0x38010000, 0xfc0f0000, "r,R", 2 }, +{ "adrm", 0x38080000, 0xfc0f0000, "r,R", 2 }, +{ "ai", 0xfc030000, 0xfc07ffff, "I", 4 }, +{ "anmb", 0x84080000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmd", 0x84000002, 0xfc080002, "r,xOA,X", 4 }, +{ "anmh", 0x84000001, 0xfc080001, "r,xOA,X", 4 }, +{ "anmw", 0x84000000, 0xfc080000, "r,xOA,X", 4 }, +{ "anr", 0x04000000, 0xfc0f0000, "r,R", 2 }, +{ "armb", 0xe8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "armd", 0xe8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "armh", 0xe8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "armw", 0xe8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bcf", 0xf0000000, 0xfc080000, "I,xOA,X", 4 }, +{ "bct", 0xec000000, 0xfc080000, "I,xOA,X", 4 }, +{ "bei", 0x00060000, 0xffff0000, "", 2 }, +{ "bft", 0xf0000000, 0xff880000, "xOA,X", 4 }, +{ "bib", 0xf4000000, 0xfc780000, "r,xOA", 4 }, +{ "bid", 0xf4600000, 0xfc780000, "r,xOA", 4 }, +{ "bih", 0xf4200000, 0xfc780000, "r,xOA", 4 }, +{ "biw", 0xf4400000, 0xfc780000, "r,xOA", 4 }, +{ "bl", 0xf8800000, 0xff880000, "xOA,X", 4 }, +{ "bsub", 0x5c080000, 0xff8f0000, "", 2 }, +{ "bsubm", 0x28080000, 0xfc080000, "", 4 }, +{ "bu", 0xec000000, 0xff880000, "xOA,X", 4 }, +{ "call", 0x28080000, 0xfc0f0000, "", 2 }, +{ "callm", 0x5c080000, 0xff880000, "", 4 }, +{ "camb", 0x90080000, 0xfc080000, "r,xOA,X", 4 }, +{ "camd", 0x90000002, 0xfc080002, "r,xOA,X", 4 }, +{ "camh", 0x90000001, 0xfc080001, "r,xOA,X", 4 }, +{ "camw", 0x90000000, 0xfc080000, "r.xOA,X", 4 }, +{ "car", 0x10000000, 0xfc0f0000, "r,R", 2 }, +{ "cd", 0xfc060000, 0xfc070000, "r,f", 4 }, +{ "cea", 0x000f0000, 0xffff0000, "", 2 }, +{ "ci", 0xc8050000, 0xfc7f0000, "r,I", 4 }, +{ "cmc", 0x040a0000, 0xfc7f0000, "r", 2 }, +{ "cmmb", 0x94080000, 0xfc080000, "r,xOA,X", 4 }, +{ "cmmd", 0x94000002, 0xfc080002, "r,xOA,X", 4 }, +{ "cmmh", 0x94000001, 0xfc080001, "r,xOA,X", 4 }, +{ "cmmw", 0x94000000, 0xfc080000, "r,xOA,X", 4 }, +{ "cmr", 0x14000000, 0xfc0f0000, "r,R", 2 }, +{ "daci", 0xfc7f0000, 0xfc7f8000, "r,I", 4 }, +{ "dae", 0x000e0000, 0xffff0000, "", 2 }, +{ "dai", 0xfc040000, 0xfc07ffff, "I", 4 }, +{ "dci", 0xfc6f0000, 0xfc7f8000, "r,I", 4 }, +{ "di", 0xfc010000, 0xfc07ffff, "I", 4 }, +{ "dvfd", 0xe4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "dvfw", 0xe4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvi", 0xc8040000, 0xfc7f0000, "r,I", 4 }, +{ "dvmb", 0xc4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvmh", 0xc4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "dvmw", 0xc4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvr", 0x380a0000, 0xfc0f0000, "r,R", 2 }, +{ "dvrfd", 0x380c0000, 0xfc0f0000, "r,R", 4 }, +{ "dvrfw", 0x38040000, 0xfc0f0000, "r,xOA,X", 4 }, +{ "eae", 0x00080000, 0xffff0000, "", 2 }, +{ "eci", 0xfc670000, 0xfc7f8080, "r,I", 4 }, +{ "ecwcs", 0xfc4f0000, 0xfc7f8000, "", 4 }, +{ "ei", 0xfc000000, 0xfc07ffff, "I", 4 }, +{ "eomb", 0x8c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomd", 0x8c000002, 0xfc080002, "r,xOA,X", 4 }, +{ "eomh", 0x8c000001, 0xfc080001, "r,xOA,X", 4 }, +{ "eomw", 0x8c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "eor", 0x0c000000, 0xfc0f0000, "r,R", 2 }, +{ "eorm", 0x0c080000, 0xfc0f0000, "r,R", 2 }, +{ "es", 0x00040000, 0xfc7f0000, "r", 2 }, +{ "exm", 0xa8000000, 0xff880000, "xOA,X", 4 }, +{ "exr", 0xc8070000, 0xfc7f0000, "r", 2 }, +{ "exrr", 0xc8070002, 0xfc7f0002, "r", 2 }, +{ "fixd", 0x380d0000, 0xfc0f0000, "r,R", 2 }, +{ "fixw", 0x38050000, 0xfc0f0000, "r,R", 2 }, +{ "fltd", 0x380f0000, 0xfc0f0000, "r,R", 2 }, +{ "fltw", 0x38070000, 0xfc0f0000, "r,R", 2 }, +{ "grio", 0xfc3f0000, 0xfc7f8000, "r,I", 4 }, +{ "halt", 0x00000000, 0xffff0000, "", 2 }, +{ "hio", 0xfc370000, 0xfc7f8000, "r,I", 4 }, +{ "jwcs", 0xfa080000, 0xff880000, "xOA,X", 4 }, +{ "la", 0x50000000, 0xfc000000, "r,xOA,X", 4 }, +{ "labr", 0x58080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lb", 0xac080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lcs", 0x00030000, 0xfc7f0000, "r", 2 }, +{ "ld", 0xac000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lear", 0x80000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lf", 0xcc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lfbr", 0xcc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lh", 0xac000001, 0xfc080001, "r,xOA,X", 4 }, +{ "li", 0xc8000000, 0xfc7f0000, "r,I", 4 }, +{ "lmap", 0x2c070000, 0xfc7f0000, "r", 2 }, +{ "lmb", 0xb0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lmd", 0xb0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lmh", 0xb0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lmw", 0xb0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnb", 0xb4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnd", 0xb4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lnh", 0xb4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lnw", 0xb4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lpsd", 0xf9800000, 0xff880000, "r,xOA,X", 4 }, +{ "lpsdcm", 0xfa800000, 0xff880000, "r,xOA,X", 4 }, +{ "lw", 0xac000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwbr", 0x5c000000, 0xfc080000, "b,xOA,X", 4 }, +{ "mpfd", 0xe4080002, 0xfc080002, "r,xOA,X", 4 }, +{ "mpfw", 0xe4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpi", 0xc8030000, 0xfc7f0000, "r,I", 4 }, +{ "mpmb", 0xc0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpmh", 0xc0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "mpmw", 0xc0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpr", 0x38020000, 0xfc0f0000, "r,R", 2 }, +{ "mprfd", 0x380e0000, 0xfc0f0000, "r,R", 2 }, +{ "mprfw", 0x38060000, 0xfc0f0000, "r,R", 2 }, +{ "nop", 0x00020000, 0xffff0000, "", 2 }, +{ "ormb", 0x88080000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormd", 0x88000002, 0xfc080002, "r,xOA,X", 4 }, +{ "ormh", 0x88000001, 0xfc080001, "r,xOA,X", 4 }, +{ "ormw", 0x88000000, 0xfc080000, "r,xOA,X", 4 }, +{ "orr", 0x08000000, 0xfc0f0000, "r,R", 2 }, +{ "orrm", 0x08080000, 0xfc0f0000, "r,R", 2 }, +{ "rdsts", 0x00090000, 0xfc7f0000, "r", 2 }, +{ "return", 0x280e0000, 0xfc7f0000, "", 2 }, +{ "ri", 0xfc020000, 0xfc07ffff, "I", 4 }, +{ "rnd", 0x00050000, 0xfc7f0000, "r", 2 }, +{ "rpswt", 0x040b0000, 0xfc7f0000, "r", 2 }, +{ "rschnl", 0xfc2f0000, 0xfc7f8000, "r,I", 4 }, +{ "rsctl", 0xfc470000, 0xfc7f8000, "r,I", 4 }, +{ "rwcs", 0x000b0000, 0xfc0f0000, "r,R", 2 }, +{ "sacz", 0x10080000, 0xfc0f0000, "r,R", 2 }, +{ "sbm", 0x98080000, 0xfc080000, "f,xOA,X", 4 }, +{ "sbr", 0x18000000, 0xfc0c0000, "r,f", 4 }, +{ "sea", 0x000d0000, 0xffff0000, "", 2 }, +{ "setcpu", 0x2c090000, 0xfc7f0000, "r", 2 }, +{ "sio", 0xfc170000, 0xfc7f8000, "r,I", 4 }, +{ "sipu", 0x000a0000, 0xffff0000, "", 2 }, +{ "sla", 0x1c400000, 0xfc600000, "r,S", 2 }, +{ "slad", 0x20400000, 0xfc600000, "r,S", 2 }, +{ "slc", 0x24400000, 0xfc600000, "r,S", 2 }, +{ "sll", 0x1c600000, 0xfc600000, "r,S", 2 }, +{ "slld", 0x20600000, 0xfc600000, "r,S", 2 }, +{ "smc", 0x04070000, 0xfc070000, "", 2 }, +{ "sra", 0x1c000000, 0xfc600000, "r,S", 2 }, +{ "srad", 0x20000000, 0xfc600000, "r,S", 2 }, +{ "src", 0x24000000, 0xfc600000, "r,S", 2 }, +{ "srl", 0x1c200000, 0xfc600000, "r,S", 2 }, +{ "srld", 0x20200000, 0xfc600000, "r,S", 2 }, +{ "stb", 0xd4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "std", 0xd4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stf", 0xdc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stfbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "sth", 0xd4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stmb", 0xd8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "stmd", 0xd8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stmh", 0xd8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stmw", 0xd8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stpio", 0xfc270000, 0xfc7f8000, "r,I", 4 }, +{ "stw", 0xd4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stwbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "suabr", 0x58000000, 0xfc080000, "b,xOA,X", 4 }, +{ "sufd", 0xe0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sufw", 0xe0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sui", 0xc8020000, 0xfc7f0000, "r,I", 4 }, +{ "sumb", 0xbc080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumd", 0xbc000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sumh", 0xbc000001, 0xfc080001, "r,xOA,X", 4 }, +{ "sumw", 0xbc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sur", 0x3c000000, 0xfc0f0000, "r,R", 2 }, +{ "surfd", 0x380b0000, 0xfc0f0000, "r,xOA,X", 4 }, +{ "surfw", 0x38030000, 0xfc0f0000, "r,R", 2 }, +{ "surm", 0x3c080000, 0xfc0f0000, "r,R", 2 }, +{ "svc", 0xc8060000, 0xffff0000, "", 4 }, +{ "tbm", 0xa4080000, 0xfc080000, "f,xOA,X", 4 }, +{ "tbr", 0x180c0000, 0xfc0c0000, "r,f", 2 }, +{ "tbrr", 0x2c020000, 0xfc0f0000, "r,B", 2 }, +{ "tccr", 0x28040000, 0xfc7f0000, "", 2 }, +{ "td", 0xfc050000, 0xfc070000, "r,f", 4 }, +{ "tio", 0xfc1f0000, 0xfc7f8000, "r,I", 4 }, +{ "tmapr", 0x2c0a0000, 0xfc0f0000, "r,R", 2 }, +{ "tpcbr", 0x280c0000, 0xfc7f0000, "r", 2 }, +{ "trbr", 0x2c010000, 0xfc0f0000, "b,R", 2 }, +{ "trc", 0x2c030000, 0xfc0f0000, "r,R", 2 }, +{ "trcc", 0x28050000, 0xfc7f0000, "", 2 }, +{ "trcm", 0x2c0b0000, 0xfc0f0000, "r,R", 2 }, +{ "trn", 0x2c040000, 0xfc0f0000, "r,R", 2 }, +{ "trnm", 0x2c0c0000, 0xfc0f0000, "r,R", 2 }, +{ "trr", 0x2c000000, 0xfc0f0000, "r,R", 2 }, +{ "trrm", 0x2c080000, 0xfc0f0000, "r,R", 2 }, +{ "trsc", 0x2c0e0000, 0xfc0f0000, "r,R", 2 }, +{ "trsw", 0x28000000, 0xfc7f0000, "r", 2 }, +{ "tscr", 0x2c0f0000, 0xfc0f0000, "r,R", 2 }, +{ "uei", 0x00070000, 0xffff0000, "", 2 }, +{ "wait", 0x00010000, 0xffff0000, "", 2 }, +{ "wcwcs", 0xfc5f0000, 0xfc7f8000, "", 4 }, +{ "wwcs", 0x000c0000, 0xfc0f0000, "r,R", 2 }, +{ "xcbr", 0x28020000, 0xfc0f0000, "b,B", 2 }, +{ "xcr", 0x2c050000, 0xfc0f0000, "r,R", 2 }, +{ "xcrm", 0x2c0d0000, 0xfc0f0000, "r,R", 2 }, +{ "zbm", 0x9c080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zbr", 0x18040000, 0xfc0c0000, "r,f", 2 }, +{ "zmb", 0xf8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmd", 0xf8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "zmh", 0xf8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "zmw", 0xf8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "zr", 0x0c000000, 0xfc0f0000, "r", 2 }, +}; + +int numopcodes = sizeof(gld_opcodes) / sizeof(gld_opcodes[0]); + +struct gld_opcode *endop = gld_opcodes + sizeof(gld_opcodes) / + sizeof(gld_opcodes[0]); diff --git a/gdb/pyr-opcode.h b/gdb/pyr-opcode.h new file mode 100755 index 00000000000..06632b8d919 --- /dev/null +++ b/gdb/pyr-opcode.h @@ -0,0 +1,287 @@ +/* pyramid.opcode.h -- gdb initial attempt. */ + +/* pyramid opcode table: wot to do with this + particular opcode */ + +struct pyr_datum +{ + char nargs; + char * args; /* how to compile said opcode */ + unsigned long mask; /* Bit vector: which operand modes are valid + for this opcode */ + unsigned char code; /* op-code (always 6(?) bits */ +}; + +typedef struct pyr_insn_format { + unsigned int mode :4; + unsigned int operator :8; + unsigned int index_scale :2; + unsigned int index_reg :6; + unsigned int operand_1 :6; + unsigned int operand_2:6; +} pyr_insn_format; + + +/* We store four bytes of opcode for all opcodes. + Pyramid is sufficiently RISCy that: + - insns are always an integral number of words; + - the length of any insn can be told from the first word of + the insn. (ie, if there are zero, one, or two words of + immediate operand/offset). + + + The args component is a string containing two characters for each + operand of the instruction. The first specifies the kind of operand; + the second, the place it is stored. */ + +/* Kinds of operands: + mask assembler syntax description + 0x0001: movw Rn,Rn register to register + 0x0002: movw K,Rn quick immediate to register + 0x0004: movw I,Rn long immediate to register + 0x0008: movw (Rn),Rn register indirect to register + movw (Rn)[x],Rn register indirect to register + 0x0010: movw I(Rn),Rn offset register indirect to register + movw I(Rn)[x],Rn offset register indirect, indexed, to register + + 0x0020: movw Rn,(Rn) register to register indirect + 0x0040: movw K,(Rn) quick immediate to register indirect + 0x0080: movw I,(Rn) long immediate to register indirect + 0x0100: movw (Rn),(Rn) register indirect to-register indirect + 0x0100: movw (Rn),(Rn) register indirect to-register indirect + 0x0200: movw I(Rn),(Rn) register indirect+offset to register indirect + 0x0200: movw I(Rn),(Rn) register indirect+offset to register indirect + + 0x0400: movw Rn,I(Rn) register to register indirect+offset + 0x0800: movw K,I(Rn) quick immediate to register indirect+offset + 0x1000: movw I,I(Rn) long immediate to register indirect+offset + 0x1000: movw (Rn),I(Rn) register indirect to-register indirect+offset + 0x1000: movw I(Rn),I(Rn) register indirect+offset to register indirect + +offset + 0x0000: (irregular) ??? + + + Each insn has a four-bit field encoding the type(s) of its operands. +*/ + +/* Some common combinations + */ + +/* the first 5,(0x1|0x2|0x4|0x8|0x10) ie (1|2|4|8|16), ie ( 32 -1)*/ +#define GEN_TO_REG (31) + +#define UNKNOWN ((unsigned long)-1) +#define ANY (GEN_TO_REG | (GEN_TO_REG << 5) | (GEN_TO_REG << 15)) + +#define CONVERT (1|8|0x10|0x20|0x200) + +#define K_TO_REG (2) +#define I_TO_REG (4) +#define NOTK_TO_REG (GEN_TO_REG & ~K_TO_REG) +#define NOTI_TO_REG (GEN_TO_REG & ~I_TO_REG) + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ + +struct pyr_opcode /* pyr opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct pyr_datum datum; /* rest of opcode table [datum] */ +}; + +#define pyr_how args +#define pyr_nargs nargs +#define pyr_mask mask +#define pyr_name name + +struct pyr_opcode pyr_opcodes[] = +{ + {"movb", { 2, "", UNKNOWN, 0x11}, }, + {"movh", { 2, "", UNKNOWN, 0x12} }, + {"movw", { 2, "", ANY, 0x10} }, + {"movl", { 2, "", ANY, 0x13} }, + {"mnegw", { 2, "", (0x1|0x8|0x10), 0x14} }, + {"mnegf", { 2, "", 0x1, 0x15} }, + {"mnegd", { 2, "", 0x1, 0x16} }, + {"mcomw", { 2, "", (0x1|0x8|0x10), 0x17} }, + {"mabsw", { 2, "", (0x1|0x8|0x10), 0x18} }, + {"mabsf", { 2, "", 0x1, 0x19} }, + {"mabsd", { 2, "", 0x1, 0x1a} }, + {"mtstw", { 2, "", (0x1|0x8|0x10), 0x1c} }, + {"mtstf", { 2, "", 0x1, 0x1d} }, + {"mtstd", { 2, "", 0x1, 0x1e} }, + {"mova", { 2, "", 0x8|0x10, 0x1f} }, + {"movzbw", { 2, "", (0x1|0x8|0x10), 0x20} }, + {"movzhw", { 2, "", (0x1|0x8|0x10), 0x21} }, + /* 2 insns out of order here */ + {"movbl", { 2, "", 1, 0x4f} }, + {"filbl", { 2, "", 1, 0x4e} }, + + {"cvtbw", { 2, "", CONVERT, 0x22} }, + {"cvthw", { 2, "", CONVERT, 0x23} }, + {"cvtwb", { 2, "", CONVERT, 0x24} }, + {"cvtwh", { 2, "", CONVERT, 0x25} }, + {"cvtwf", { 2, "", CONVERT, 0x26} }, + {"cvtwd", { 2, "", CONVERT, 0x27} }, + {"cvtfw", { 2, "", CONVERT, 0x28} }, + {"cvtfd", { 2, "", CONVERT, 0x29} }, + {"cvtdw", { 2, "", CONVERT, 0x2a} }, + {"cvtdf", { 2, "", CONVERT, 0x2b} }, + + {"addw", { 2, "", GEN_TO_REG, 0x40} }, + {"addwc", { 2, "", GEN_TO_REG, 0x41} }, + {"subw", { 2, "", GEN_TO_REG, 0x42} }, + {"subwb", { 2, "", GEN_TO_REG, 0x43} }, + {"rsubw", { 2, "", GEN_TO_REG, 0x44} }, + {"mulw", { 2, "", GEN_TO_REG, 0x45} }, + {"emul", { 2, "", GEN_TO_REG, 0x47} }, + {"umulw", { 2, "", GEN_TO_REG, 0x46} }, + {"divw", { 2, "", GEN_TO_REG, 0x48} }, + {"ediv", { 2, "", GEN_TO_REG, 0x4a} }, + {"rdivw", { 2, "", GEN_TO_REG, 0x4b} }, + {"udivw", { 2, "", GEN_TO_REG, 0x49} }, + {"modw", { 2, "", GEN_TO_REG, 0x4c} }, + {"umodw", { 2, "", GEN_TO_REG, 0x4d} }, + + + {"addf", { 2, "", 1, 0x50} }, + {"addd", { 2, "", 1, 0x51} }, + {"subf", { 2, "", 1, 0x52} }, + {"subd", { 2, "", 1, 0x53} }, + {"mulf", { 2, "", 1, 0x56} }, + {"muld", { 2, "", 1, 0x57} }, + {"divf", { 2, "", 1, 0x58} }, + {"divd", { 2, "", 1, 0x59} }, + + + {"cmpb", { 2, "", UNKNOWN, 0x61} }, + {"cmph", { 2, "", UNKNOWN, 0x62} }, + {"cmpw", { 2, "", UNKNOWN, 0x60} }, + {"ucmpb", { 2, "", UNKNOWN, 0x66} }, + /* WHY no "ucmph"??? */ + {"ucmpw", { 2, "", UNKNOWN, 0x65} }, + {"xchw", { 2, "", UNKNOWN, 0x0f} }, + + + {"andw", { 2, "", GEN_TO_REG, 0x30} }, + {"orw", { 2, "", GEN_TO_REG, 0x31} }, + {"xorw", { 2, "", GEN_TO_REG, 0x32} }, + {"bicw", { 2, "", GEN_TO_REG, 0x33} }, + {"lshlw", { 2, "", GEN_TO_REG, 0x38} }, + {"ashlw", { 2, "", GEN_TO_REG, 0x3a} }, + {"ashll", { 2, "", GEN_TO_REG, 0x3c} }, + {"ashrw", { 2, "", GEN_TO_REG, 0x3b} }, + {"ashrl", { 2, "", GEN_TO_REG, 0x3d} }, + {"rotlw", { 2, "", GEN_TO_REG, 0x3e} }, + {"rotrw", { 2, "", GEN_TO_REG, 0x3f} }, + + /* push and pop insns are "going away next release". */ + {"pushw", { 2, "", GEN_TO_REG, 0x0c} }, + {"popw", { 2, "", (0x1|0x8|0x10), 0x0d} }, + {"pusha", { 2, "", (0x8|0x10), 0x0e} }, + + {"bitsw", { 2, "", UNKNOWN, 0x35} }, + {"bitcw", { 2, "", UNKNOWN, 0x36} }, + /* some kind of ibra/dbra insns??*/ + {"icmpw", { 2, "", UNKNOWN, 0x67} }, + {"dcmpw", { 2, "", (1|4|0x20|0x80|0x400|0x1000), 0x69} },/*FIXME*/ + {"acmpw", { 2, "", 1, 0x6b} }, + + /* Call is written as a 1-op insn, but is always (dis)assembled as a 2-op + insn with a 2nd op of tr14. The assembler will have to grok this. */ + {"call", { 2, "", GEN_TO_REG, 0x04} }, + {"call", { 1, "", GEN_TO_REG, 0x04} }, + + {"callk", { 1, "", UNKNOWN, 0x06} },/* system call?*/ + /* Ret is usually written as a 0-op insn, but gets disassembled as a + 1-op insn. The operand is always tr15. */ + {"ret", { 0, "", UNKNOWN, 0x09} }, + {"ret", { 1, "", UNKNOWN, 0x09} }, + {"adsf", { 2, "", (1|2|4), 0x08} }, + {"retd", { 2, "", UNKNOWN, 0x0a} }, + {"btc", { 2, "", UNKNOWN, 0x01} }, + {"bfc", { 2, "", UNKNOWN, 0x02} }, + /* Careful: halt is 0x00000000. Jump must have some other (mode?)bit set?? */ + {"jump", { 1, "", UNKNOWN, 0x00} }, + {"btp", { 2, "", UNKNOWN, 0xf00} }, + /* read control-stack pointer is another 1-or-2 operand insn. */ + {"rcsp", { 2, "", UNKNOWN, 0x01f} }, + {"rcsp", { 1, "", UNKNOWN, 0x01f} } +}; + +/* end: pyramid.opcode.h */ +/* One day I will have to take the time to find out what operands + are valid for these insns, and guess at what they mean. + + I can't imagine what the "I???" insns (iglob, etc) do. + + the arithmetic-sounding insns ending in "p" sound awfully like BCD + arithmetic insns: + dshlp -> Decimal SHift Left Packed + dshrp -> Decimal SHift Right Packed + and cvtlp would be convert long to packed. + I have no idea how the operands are interpreted; but having them be + a long register with (address, length) of an in-memory packed BCD operand + would not be surprising. + They are unlikely to be a packed bcd string: 64 bits of long give + is only 15 digits+sign, which isn't enough for COBOL. + */ +#if 0 + {"wcsp", { 2, "", UNKNOWN, 0x00} }, /*write csp?*/ + /* The OSx Operating System Porting Guide claims SSL does things + with tr12 (a register reserved to it) to do with static block-structure + references. SSL=Set Static Link? It's "Going away next release". */ + {"ssl", { 2, "", UNKNOWN, 0x00} }, + {"ccmps", { 2, "", UNKNOWN, 0x00} }, + {"lcd", { 2, "", UNKNOWN, 0x00} }, + {"uemul", { 2, "", UNKNOWN, 0x00} }, /*unsigned emul*/ + {"srf", { 2, "", UNKNOWN, 0x00} }, /*Gidget time???*/ + {"mnegp", { 2, "", UNKNOWN, 0x00} }, /move-neg phys?*/ + {"ldp", { 2, "", UNKNOWN, 0x00} }, /*load phys?*/ + {"ldti", { 2, "", UNKNOWN, 0x00} }, + {"ldb", { 2, "", UNKNOWN, 0x00} }, + {"stp", { 2, "", UNKNOWN, 0x00} }, + {"stti", { 2, "", UNKNOWN, 0x00} }, + {"stb", { 2, "", UNKNOWN, 0x00} }, + {"stu", { 2, "", UNKNOWN, 0x00} }, + {"addp", { 2, "", UNKNOWN, 0x00} }, + {"subp", { 2, "", UNKNOWN, 0x00} }, + {"mulp", { 2, "", UNKNOWN, 0x00} }, + {"divp", { 2, "", UNKNOWN, 0x00} }, + {"dshlp", { 2, "", UNKNOWN, 0x00} }, /* dec shl packed? */ + {"dshrp", { 2, "", UNKNOWN, 0x00} }, /* dec shr packed? */ + {"movs", { 2, "", UNKNOWN, 0x00} }, /*move (string?)?*/ + {"cmpp", { 2, "", UNKNOWN, 0x00} }, /* cmp phys?*/ + {"cmps", { 2, "", UNKNOWN, 0x00} }, /* cmp (string?)?*/ + {"cvtlp", { 2, "", UNKNOWN, 0x00} }, /* cvt long to p??*/ + {"cvtpl", { 2, "", UNKNOWN, 0x00} }, /* cvt p to l??*/ + {"dintr", { 2, "", UNKNOWN, 0x00} }, /* ?? intr ?*/ + {"rphysw", { 2, "", UNKNOWN, 0x00} }, /* read phys word?*/ + {"wphysw", { 2, "", UNKNOWN, 0x00} }, /* write phys word?*/ + {"cmovs", { 2, "", UNKNOWN, 0x00} }, + {"rsubw", { 2, "", UNKNOWN, 0x00} }, + {"bicpsw", { 2, "", UNKNOWN, 0x00} }, /* clr bit in psw? */ + {"bispsw", { 2, "", UNKNOWN, 0x00} }, /* set bit in psw? */ + {"eio", { 2, "", UNKNOWN, 0x00} }, /* ?? ?io ? */ + {"callp", { 2, "", UNKNOWN, 0x00} }, /* call phys?*/ + {"callr", { 2, "", UNKNOWN, 0x00} }, + {"lpcxt", { 2, "", UNKNOWN, 0x00} }, /*load proc context*/ + {"rei", { 2, "", UNKNOWN, 0x00} }, /*ret from intrpt*/ + {"rport", { 2, "", UNKNOWN, 0x00} }, /*read-port?*/ + {"rtod", { 2, "", UNKNOWN, 0x00} }, /*read-time-of-day?*/ + {"ssi", { 2, "", UNKNOWN, 0x00} }, + {"vtpa", { 2, "", UNKNOWN, 0x00} }, /*virt-to-phys-addr?*/ + {"wicl", { 2, "", UNKNOWN, 0x00} }, /* write icl ? */ + {"wport", { 2, "", UNKNOWN, 0x00} }, /*write-port?*/ + {"wtod", { 2, "", UNKNOWN, 0x00} }, /*write-time-of-day?*/ + {"flic", { 2, "", UNKNOWN, 0x00} }, + {"iglob", { 2, "", UNKNOWN, 0x00} }, /* I global? */ + {"iphys", { 2, "", UNKNOWN, 0x00} }, /* I physical? */ + {"ipid", { 2, "", UNKNOWN, 0x00} }, /* I pid? */ + {"ivect", { 2, "", UNKNOWN, 0x00} }, /* I vector? */ + {"lamst", { 2, "", UNKNOWN, 0x00} }, + {"tio", { 2, "", UNKNOWN, 0x00} }, +#endif diff --git a/gdb/pyr-pinsn.c b/gdb/pyr-pinsn.c new file mode 100644 index 00000000000..d58ae47f8d5 --- /dev/null +++ b/gdb/pyr-pinsn.c @@ -0,0 +1,347 @@ +/* Disassembler for the Pyramid Technology 90x + Copyright (C) 1988,1989 Free Software Foundation, Inc. + +This file is part of GDB, the GNU disassembler. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "pyr-opcode.h" +#include "gdbcore.h" + + +/* A couple of functions used for debugging frame-handling on + Pyramids. (The Pyramid-dependent handling of register values for + windowed registers is known to be buggy.) + + When debugging, these functions supplant the normal definitions of some + of the macros in m-pyramid.h The quantity of information produced + when these functions are used makes the gdb unusable as a + debugger for user programs. */ + +extern unsigned pyr_saved_pc(), pyr_frame_chain(); + +CORE_ADDR pyr_frame_chain(frame) + CORE_ADDR frame; +{ + int foo=frame - CONTROL_STACK_FRAME_SIZE; + /* printf ("...following chain from %x: got %x\n", frame, foo);*/ + return foo; +} + +CORE_ADDR pyr_saved_pc(frame) + CORE_ADDR frame; +{ + int foo=0; + foo = read_memory_integer (((CORE_ADDR)(frame))+60, 4); + printf ("..reading pc from frame 0x%0x+%d regs: got %0x\n", + frame, 60/4, foo); + return foo; +} + + +/* Pyramid instructions are never longer than this many bytes. */ +#define MAXLEN 24 + +/* Number of elements in the opcode table. */ +/*const*/ static int nopcodes = (sizeof (pyr_opcodes) / sizeof( pyr_opcodes[0])); +#define NOPCODES (nopcodes) + +extern char *reg_names[]; + +/* Let's be byte-independent so we can use this as a cross-assembler. + (will this ever be useful? + */ + +#define NEXTLONG(p) \ + (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) + + +/* Print one 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, nargs, insn_size =4; + register unsigned char *p; + register char *d; + register int insn_opcode, operand_mode; + register int index_multiplier, index_reg_regno, op_1_regno, op_2_regno ; + long insn; /* first word of the insn, not broken down. */ + pyr_insn_format insn_decode; /* the same, broken out into op{code,erands} */ + long extra_1, extra_2; + + read_memory (memaddr, buffer, MAXLEN); + insn_decode = *((pyr_insn_format *) buffer); + insn = * ((int *) buffer); + insn_opcode = insn_decode.operator; + operand_mode = insn_decode.mode; + index_multiplier = insn_decode.index_scale; + index_reg_regno = insn_decode.index_reg; + op_1_regno = insn_decode.operand_1; + op_2_regno = insn_decode.operand_2; + + + if (*((int *)buffer) == 0x0) { + /* "halt" looks just like an invalid "jump" to the insn decoder, + so is dealt with as a special case */ + fprintf (stream, "halt"); + return (4); + } + + for (i = 0; i < NOPCODES; i++) + if (pyr_opcodes[i].datum.code == insn_opcode) + break; + + if (i == NOPCODES) + /* FIXME: Handle unrecognised instructions better. */ + fprintf (stream, "???\t#%08x\t(op=%x mode =%x)", + insn, insn_decode.operator, insn_decode.mode); + else + { + /* Print the mnemonic for the instruction. Pyramid insn operands + are so regular that we can deal with almost all of them + separately. + Unconditional branches are an exception: they are encoded as + conditional branches (branch if false condition, I think) + with no condition specified. The average user will not be + aware of this. To maintain their illusion that an + unconditional branch insn exists, we will have to FIXME to + treat the insn mnemnonic of all branch instructions here as a + special case: check the operands of branch insn and print an + appropriate mnemonic. */ + + fprintf (stream, "%s\t", pyr_opcodes[i].name); + + /* Print the operands of the insn (as specified in + insn.operand_mode). + Branch operands of branches are a special case: they are a word + offset, not a byte offset. */ + + if (insn_decode.operator == 0x01 || insn_decode.operator == 0x02) { + register int bit_codes=(insn >> 16)&0xf; + register int i; + register int displacement = (insn & 0x0000ffff) << 2; + + static char cc_bit_names[] = "cvzn"; /* z,n,c,v: strange order? */ + + /* Is bfc and no bits specified an unconditional branch?*/ + for (i=0;i<4;i++) { + if ((bit_codes) & 0x1) + fputc (cc_bit_names[i], stream); + bit_codes >>= 1; + } + + fprintf (stream, ",%0x", + displacement + memaddr); + return (insn_size); + } + + switch (operand_mode) { + case 0: + fprintf (stream, "%s,%s", + reg_names [op_1_regno], + reg_names [op_2_regno]); + break; + + case 1: + fprintf (stream, " 0x%0x,%s", + op_1_regno, + reg_names [op_2_regno]); + break; + + case 2: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf (stream, " $0x%0x,%s", + extra_1, + reg_names [op_2_regno]); + break; + case 3: + fprintf (stream, " (%s),%s", + reg_names [op_1_regno], + reg_names [op_2_regno]); + break; + + case 4: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf (stream, " 0x%0x(%s),%s", + extra_1, + reg_names [op_1_regno], + reg_names [op_2_regno]); + break; + + /* S1 destination mode */ + case 5: + fprintf (stream, + ((index_reg_regno) ? "%s,(%s)[%s*%1d]" : "%s,(%s)"), + reg_names [op_1_regno], + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 6: + fprintf (stream, + ((index_reg_regno) ? " $%#0x,(%s)[%s*%1d]" + : " $%#0x,(%s)"), + op_1_regno, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 7: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf (stream, + ((index_reg_regno) ? " $%#0x,(%s)[%s*%1d]" + : " $%#0x,(%s)"), + extra_1, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 8: + fprintf (stream, + ((index_reg_regno) ? " (%s),(%s)[%s*%1d]" : " (%s),(%s)"), + reg_names [op_1_regno], + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 9: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf (stream, + ((index_reg_regno) + ? "%#0x(%s),(%s)[%s*%1d]" + : "%#0x(%s),(%s)"), + extra_1, + reg_names [op_1_regno], + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + /* S2 destination mode */ + case 10: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf (stream, + ((index_reg_regno) ? "%s,%#0x(%s)[%s*%1d]" : "%s,%#0x(%s)"), + reg_names [op_1_regno], + extra_1, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + case 11: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf (stream, + ((index_reg_regno) ? + " $%#0x,%#0x(%s)[%s*%1d]" : " $%#0x,%#0x(%s)"), + op_1_regno, + extra_1, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + case 12: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + read_memory (memaddr+8, buffer, MAXLEN); + insn_size += 4; + extra_2 = * ((int *) buffer); + fprintf (stream, + ((index_reg_regno) ? + " $%#0x,%#0x(%s)[%s*%1d]" : " $%#0x,%#0x(%s)"), + extra_1, + extra_2, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 13: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf (stream, + ((index_reg_regno) + ? " (%s),%#0x(%s)[%s*%1d]" + : " (%s),%#0x(%s)"), + reg_names [op_1_regno], + extra_1, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + case 14: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + read_memory (memaddr+8, buffer, MAXLEN); + insn_size += 4; + extra_2 = * ((int *) buffer); + fprintf (stream, + ((index_reg_regno) ? "%#0x(%s),%#0x(%s)[%s*%1d]" + : "%#0x(%s),%#0x(%s) "), + extra_1, + reg_names [op_1_regno], + extra_2, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + default: + fprintf (stream, + ((index_reg_regno) ? "%s,%s [%s*%1d]" : "%s,%s"), + reg_names [op_1_regno], + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + fprintf (stream, + "\t\t# unknown mode in %08x", + insn); + break; + } /* switch */ + } + + { + return insn_size; + } + abort (); +} diff --git a/gdb/pyr-tdep.c b/gdb/pyr-tdep.c new file mode 100644 index 00000000000..b79ea0c8347 --- /dev/null +++ b/gdb/pyr-tdep.c @@ -0,0 +1,129 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/*** Prettier register printing. ***/ + +/* Print registers in the same format as pyramid's dbx, adb, sdb. */ +pyr_print_registers(reg_buf, regnum) + long *reg_buf[]; +{ + register int regno; + int usp, ksp; + struct user u; + + for (regno = 0; regno < 16; regno++) { + printf/*_filtered*/ ("%6.6s: %8x %6.6s: %8x %6s: %8x %6s: %8x\n", + reg_names[regno], reg_buf[regno], + reg_names[regno+16], reg_buf[regno+16], + reg_names[regno+32], reg_buf[regno+32], + reg_names[regno+48], reg_buf[regno+48]); + } + usp = ptrace (3, inferior_pid, + ((char *)&u.u_pcb.pcb_usp) - + ((char *)&u), 0); + ksp = ptrace (3, inferior_pid, + ((char *)&u.u_pcb.pcb_ksp) - + ((char *)&u), 0); + printf/*_filtered*/ ("\n%6.6s: %8x %6.6s: %8x (%08x) %6.6s %8x\n", + reg_names[CSP_REGNUM],reg_buf[CSP_REGNUM], + reg_names[KSP_REGNUM], reg_buf[KSP_REGNUM], ksp, + "usp", usp); +} + +/* Print the register regnum, or all registers if regnum is -1. */ + +pyr_do_registers_info (regnum) + int regnum; +{ + /* On a pyr, we know a virtual register can always fit in an long. + Here (and elsewhere) we take advantage of that. Yuk. */ + long raw_regs[MAX_REGISTER_RAW_SIZE*NUM_REGS]; + register int i; + + for (i = 0 ; i < 64 ; i++) { + read_relative_register_raw_bytes(i, raw_regs+i); + } + if (regnum == -1) + pyr_print_registers (raw_regs, regnum); + else + for (i = 0; i < NUM_REGS; i++) + if (i == regnum) { + long val = raw_regs[i]; + + fputs_filtered (reg_names[i], stdout); + printf_filtered(":"); + print_spaces_filtered (6 - strlen (reg_names[i]), stdout); + if (val == 0) + printf_filtered ("0"); + else + printf_filtered ("0x%08x %d", val, val); + printf_filtered("\n"); + } +} + +/*** Debugging editions of various macros from m-pyr.h ****/ + +CORE_ADDR frame_locals_address (frame) + FRAME frame; +{ + register int addr = find_saved_register (frame,CFP_REGNUM); + register int result = read_memory_integer (addr, 4); +#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING + fprintf (stderr, + "\t[[..frame_locals:%8x, %s= %x @%x fcfp= %x foo= %x\n\t gr13=%x pr13=%x tr13=%x @%x]]\n", + frame->frame, + reg_names[CFP_REGNUM], + result, addr, + frame->frame_cfp, (CFP_REGNUM), + + + read_register(13), read_register(29), read_register(61), + find_saved_register(frame, 61)); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + + /* FIXME: I thought read_register (CFP_REGNUM) should be the right answer; + or at least CFP_REGNUM relative to FRAME (ie, result). + There seems to be a bug in the way the innermost frame is set up. */ + + return ((frame->next) ? result: frame->frame_cfp); +} + +CORE_ADDR frame_args_addr (frame) + FRAME frame; +{ + register int addr = find_saved_register (frame,CFP_REGNUM); + register int result = read_memory_integer (addr, 4); + +#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING + fprintf (stderr, + "\t[[..frame_args:%8x, %s= %x @%x fcfp= %x r_r= %x\n\t gr13=%x pr13=%x tr13=%x @%x]]\n", + frame->frame, + reg_names[CFP_REGNUM], + result, addr, + frame->frame_cfp, read_register(CFP_REGNUM), + + read_register(13), read_register(29), read_register(61), + find_saved_register(frame, 61)); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + + /* FIXME: I thought read_register (CFP_REGNUM) should be the right answer; + or at least CFP_REGNUM relative to FRAME (ie, result). + There seems to be a bug in the way the innermost frame is set up. */ + return ((frame->next) ? result: frame->frame_cfp); +} diff --git a/gdb/pyr-xdep.c b/gdb/pyr-xdep.c new file mode 100644 index 00000000000..5ba4a8d41a4 --- /dev/null +++ b/gdb/pyr-xdep.c @@ -0,0 +1,366 @@ +/* Low level Pyramid interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +/* #include Can we live without this? */ + +#include "gdbcore.h" +#include /* After a.out.h */ +#include +#include + +void +fetch_inferior_registers () +{ + register int regno, datum; + register unsigned int regaddr; + int reg_buf[NUM_REGS+1]; + struct user u; + register int skipped_frames = 0; + + registers_fetched (); + + for (regno = 0; regno < 64; regno++) { + reg_buf[regno] = ptrace (3, inferior_pid, regno, 0); + +#if defined(PYRAMID_CONTROL_FRAME_DEBUGGING) + printf ("Fetching %s from inferior, got %0x\n", + reg_names[regno], + reg_buf[regno]); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + + if (reg_buf[regno] == -1 && errno == EIO) { + printf("fetch_interior_registers: fetching %s from inferior\n", + reg_names[regno]); + errno = 0; + } + supply_register (regno, reg_buf+regno); + } + /* that leaves regs 64, 65, and 66 */ + datum = ptrace (3, inferior_pid, + ((char *)&u.u_pcb.pcb_csp) - + ((char *)&u), 0); + + + + /* FIXME: Find the Current Frame Pointer (CFP). CFP is a global + register (ie, NOT windowed), that gets saved in a frame iff + the code for that frame has a prologue (ie, "adsf N"). If + there is a prologue, the adsf insn saves the old cfp in + pr13, cfp is set to sp, and N bytes of locals are allocated + (sp is decremented by n). + This makes finding CFP hard. I guess the right way to do it + is: + - If this is the innermost frame, believe ptrace() or + the core area. + - Otherwise: + Find the first insn of the current frame. + - find the saved pc; + - find the call insn that saved it; + - figure out where the call is to; + - if the first insn is an adsf, we got a frame + pointer. */ + + + /* Normal processors have separate stack pointers for user and + kernel mode. Getting the last user mode frame on such + machines is easy: the kernel context of the ptrace()'d + process is on the kernel stack, and the USP points to what + we want. But Pyramids only have a single cfp for both user and + kernel mode. And processes being ptrace()'d have some + kernel-context control frames on their stack. + To avoid tracing back into the kernel context of an inferior, + we skip 0 or more contiguous control frames where the pc is + in the kernel. */ + + while (1) { + register int inferior_saved_pc; + inferior_saved_pc = ptrace (1, inferior_pid, datum+((32+15)*4), 0); + if (inferior_saved_pc > 0) break; +#if defined(PYRAMID_CONTROL_FRAME_DEBUGGING) + printf("skipping kernel frame %08x, pc=%08x\n", datum, + inferior_saved_pc); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + skipped_frames++; + datum -= CONTROL_STACK_FRAME_SIZE; + } + + reg_buf[CSP_REGNUM] = datum; + supply_register(CSP_REGNUM, reg_buf+CSP_REGNUM); +#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING + if (skipped_frames) { + fprintf (stderr, + "skipped %d frames from %x to %x; cfp was %x, now %x\n", + skipped_frames, reg_buf[CSP_REGNUM]); + } +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ +} + +/* 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]; + + if (regno >= 0) + { + if ((0 <= regno) && (regno < 64)) { + /*regaddr = register_addr (regno, offset);*/ + regaddr = regno; + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + } + else + { + for (regno = 0; regno < NUM_REGS; regno++) + { + /*regaddr = register_addr (regno, offset);*/ + regaddr = regno; + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing all regs, number %d", regno); + perror_with_name (buf); + } + } +} + +/*** Extensions to core and dump files, for GDB. */ + +extern unsigned int last_frame_offset; + +#ifdef PYRAMID_CORE + +/* Can't make definitions here static, since core.c needs them + to do bounds checking on the core-file areas. O well. */ + +/* have two stacks: one for data, one for register windows. */ +extern CORE_ADDR reg_stack_start; +extern CORE_ADDR reg_stack_end; + +/* need this so we can find the global registers: they never get saved. */ +CORE_ADDR global_reg_offset; +static CORE_ADDR last_frame_address; +CORE_ADDR last_frame_offset; + + +/* Address in core file of start of register window stack area. + Don't know if is this any of meaningful, useful or necessary. */ +extern int reg_stack_offset; + +#endif /* PYRAMID_CORE */ + + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +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; + +#ifdef PYRAMID_CORE + reg_stack_start = CONTROL_STACK_ADDR; + reg_stack_end = CONTROL_STACK_ADDR; /* this isn't strictly true...*/ +#endif /* PYRAMID_CORE */ + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + + unsigned int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* find registers in core file */ +#ifdef PYRAMID_PTRACE + stack_start = stack_end - NBPG * u.u_ussize; + reg_stack_offset = stack_offset + (NBPG *u.u_ussize); + reg_stack_end = reg_stack_start + NBPG * u.u_cssize; + + last_frame_address = ((int) u.u_pcb.pcb_csp); + last_frame_offset = reg_stack_offset + last_frame_address + - CONTROL_STACK_ADDR ; + global_reg_offset = (char *)&u - (char *)&u.u_pcb.pcb_gr0 ; + + /* skip any control-stack frames that were executed in the + kernel. */ + + while (1) { + char buf[4]; + val = lseek (corechan, last_frame_offset+(47*4), 0); + if (val < 0) + perror_with_name (filename); + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + + if (*(int *)buf >= 0) + break; + printf ("skipping frame %0x\n", last_frame_address); + last_frame_offset -= CONTROL_STACK_FRAME_SIZE; + last_frame_address -= CONTROL_STACK_FRAME_SIZE; + } + reg_offset = last_frame_offset; + +#if 1 || defined(PYRAMID_CONTROL_FRAME_DEBUGGING) + printf ("Control stack pointer = 0x%08x\n", + u.u_pcb.pcb_csp); + printf ("offset to control stack %d outermost frame %d (%0x)\n", + reg_stack_offset, reg_offset, last_frame_address); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + +#else /* not PYRAMID_CORE */ + stack_start = stack_end - NBPG * u.u_ssize; + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; +#endif /* not PYRAMID_CORE */ + +#ifdef __not_on_pyr_yet + /* Some machines put an absolute address in here and some put + the offset in the upage of the regs. */ + reg_offset = (int) u.u_ar0; + if (reg_offset > NBPG * UPAGES) + reg_offset -= KERNEL_U_ADDR; +#endif + + /* 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 < 64; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0 + || (val = myread (corechan, buf, sizeof buf)) < 0) + { + char * buffer = (char *) alloca (strlen (reg_names[regno]) + + 30); + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + + if (val < 0) + perror_with_name (filename); +#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING + printf ("[reg %s(%d), offset in file %s=0x%0x, addr =0x%0x, =%0x]\n", + reg_names[regno], regno, filename, + register_addr(regno, reg_offset), + regno * 4 + last_frame_address, + *((int *)buf)); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + +#if 1 || defined(PYRAMID_CONTROL_FRAME_DEBUGGING) + printf ("Providing CSP (%0x) as nominal address of current frame.\n", + last_frame_address); +#endif PYRAMID_CONTROL_FRAME_DEBUGGING + /* FIXME: Which of the following is correct? */ +#if 0 + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); +#else + set_current_frame ( create_new_frame (last_frame_address, + read_pc ())); +#endif + + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} diff --git a/gdb/regex.c b/gdb/regex.c new file mode 100644 index 00000000000..45c34780f6c --- /dev/null +++ b/gdb/regex.c @@ -0,0 +1,1738 @@ +/* Extended regular expression matching and search library. + Copyright (C) 1985, 1989 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + + +/* To test, compile with -Dtest. + This Dtestable feature turns this into a self-contained program + which reads a pattern, describes how it compiles, + then reads a string and searches for it. */ + +#ifdef emacs + +/* The `emacs' switch turns on certain special matching commands + that make sense only in emacs. */ + +#include "config.h" +#include "lisp.h" +#include "buffer.h" +#include "syntax.h" + +#else /* not emacs */ + +#ifdef USG +#ifndef BSTRING +#define bcopy(s,d,n) memcpy((d),(s),(n)) +#define bcmp(s1,s2,n) memcmp((s1),(s2),(n)) +#define bzero(s,n) memset((s),0,(n)) +#endif +#endif + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef sparc +#include +#endif +#endif + +/* + * Define the syntax stuff, so we can do the \<...\> things. + */ + +#ifndef Sword /* must be non-zero in some of the tests below... */ +#define Sword 1 +#endif + +#define SYNTAX(c) re_syntax_table[c] + +#ifdef SYNTAX_TABLE + +char *re_syntax_table; + +#else + +static char re_syntax_table[256]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + done = 1; +} + +#endif /* SYNTAX_TABLE */ +#endif /* not emacs */ + +#include "regex.h" + +/* Number of failure points to allocate space for initially, + when matching. If this number is exceeded, more space is allocated, + so it is not a hard limit. */ + +#ifndef NFAILURES +#define NFAILURES 80 +#endif /* NFAILURES */ + +/* width of a byte in bits */ + +#define BYTEWIDTH 8 + +#ifndef SIGN_EXTEND_CHAR +#define SIGN_EXTEND_CHAR(x) (x) +#endif + +static int obscure_syntax = 0; + +/* Specify the precise syntax of regexp for compilation. + This provides for compatibility for various utilities + which historically have different, incompatible syntaxes. + + The argument SYNTAX is a bit-mask containing the two bits + RE_NO_BK_PARENS and RE_NO_BK_VBAR. */ + +int +re_set_syntax (syntax) +{ + int ret; + + ret = obscure_syntax; + obscure_syntax = syntax; + return ret; +} + +/* re_compile_pattern takes a regular-expression string + and converts it into a buffer full of byte commands for matching. + + PATTERN is the address of the pattern string + SIZE is the length of it. + BUFP is a struct re_pattern_buffer * which points to the info + on where to store the byte commands. + This structure contains a char * which points to the + actual space, which should have been obtained with malloc. + re_compile_pattern may use realloc to grow the buffer space. + + The number of bytes of commands can be found out by looking in + the struct re_pattern_buffer that bufp pointed to, + after re_compile_pattern returns. +*/ + +#define PATPUSH(ch) (*b++ = (char) (ch)) + +#define PATFETCH(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; \ + if (translate) c = translate[c]; } + +#define PATFETCH_RAW(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; } + +#define PATUNFETCH p-- + +#define EXTEND_BUFFER \ + { char *old_buffer = bufp->buffer; \ + if (bufp->allocated == (1<<16)) goto too_big; \ + bufp->allocated *= 2; \ + if (bufp->allocated > (1<<16)) bufp->allocated = (1<<16); \ + if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \ + goto memory_exhausted; \ + c = bufp->buffer - old_buffer; \ + b += c; \ + if (fixup_jump) \ + fixup_jump += c; \ + if (laststart) \ + laststart += c; \ + begalt += c; \ + if (pending_exact) \ + pending_exact += c; \ + } + +static int store_jump (), insert_jump (); + +char * +re_compile_pattern (pattern, size, bufp) + char *pattern; + int size; + struct re_pattern_buffer *bufp; +{ + register char *b = bufp->buffer; + register char *p = pattern; + char *pend = pattern + size; + register unsigned c, c1; + char *p1; + unsigned char *translate = (unsigned char *) bufp->translate; + + /* address of the count-byte of the most recently inserted "exactn" command. + This makes it possible to tell whether a new exact-match character + can be added to that command or requires a new "exactn" command. */ + + char *pending_exact = 0; + + /* address of the place where a forward-jump should go + to the end of the containing expression. + Each alternative of an "or", except the last, ends with a forward-jump + of this sort. */ + + char *fixup_jump = 0; + + /* address of start of the most recently finished expression. + This tells postfix * where to find the start of its operand. */ + + char *laststart = 0; + + /* In processing a repeat, 1 means zero matches is allowed */ + + char zero_times_ok; + + /* In processing a repeat, 1 means many matches is allowed */ + + char many_times_ok; + + /* address of beginning of regexp, or inside of last \( */ + + char *begalt = b; + + /* Stack of information saved by \( and restored by \). + Four stack elements are pushed by each \(: + First, the value of b. + Second, the value of fixup_jump. + Third, the value of regnum. + Fourth, the value of begalt. */ + + int stackb[40]; + int *stackp = stackb; + int *stacke = stackb + 40; + int *stackt; + + /* Counts \('s as they are encountered. Remembered for the matching \), + where it becomes the "register number" to put in the stop_memory command */ + + int regnum = 1; + + bufp->fastmap_accurate = 0; + +#ifndef emacs +#ifndef SYNTAX_TABLE + /* + * Initialize the syntax table. + */ + init_syntax_once(); +#endif +#endif + + if (bufp->allocated == 0) + { + bufp->allocated = 28; + if (bufp->buffer) + /* EXTEND_BUFFER loses when bufp->allocated is 0 */ + bufp->buffer = (char *) realloc (bufp->buffer, 28); + else + /* Caller did not allocate a buffer. Do it for him */ + bufp->buffer = (char *) malloc (28); + if (!bufp->buffer) goto memory_exhausted; + begalt = b = bufp->buffer; + } + + while (p != pend) + { + if (b - bufp->buffer > bufp->allocated - 10) + /* Note that EXTEND_BUFFER clobbers c */ + EXTEND_BUFFER; + + PATFETCH (c); + + switch (c) + { + case '$': + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend) + goto normal_char; + /* Make operand of last vbar end before this `$'. */ + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = 0; + PATPUSH (endline); + break; + } + + /* $ means succeed if at end of line, but only in special contexts. + If randomly in the middle of a pattern, it is a normal character. */ + if (p == pend || *p == '\n' + || (obscure_syntax & RE_CONTEXT_INDEP_OPS) + || (obscure_syntax & RE_NO_BK_PARENS + ? *p == ')' + : *p == '\\' && p[1] == ')') + || (obscure_syntax & RE_NO_BK_VBAR + ? *p == '|' + : *p == '\\' && p[1] == '|')) + { + PATPUSH (endline); + break; + } + goto normal_char; + + case '^': + /* ^ means succeed if at beg of line, but only if no preceding pattern. */ + + if (laststart && p[-2] != '\n' + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (p != pattern + 1 + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + PATPUSH (begline); + begalt = b; + } + else + PATPUSH (begline); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern, char not special. */ + if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + /* If there is a sequence of repetition chars, + collapse it down to equivalent to just one. */ + zero_times_ok = 0; + many_times_ok = 0; + while (1) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + if (p == pend) + break; + PATFETCH (c); + if (c == '*') + ; + else if (!(obscure_syntax & RE_BK_PLUS_QM) + && (c == '+' || c == '?')) + ; + else if ((obscure_syntax & RE_BK_PLUS_QM) + && c == '\\') + { + int c1; + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + c = c1; + } + else + { + PATUNFETCH; + break; + } + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether 0 matches is allowed, + and whether 2 or more matches is allowed. */ + if (many_times_ok) + { + /* If more than one repetition is allowed, + put in a backward jump at the end. */ + store_jump (b, maybe_finalize_jump, laststart - 3); + b += 3; + } + insert_jump (on_failure_jump, laststart, b + 3, b); + pending_exact = 0; + b += 3; + if (!zero_times_ok) + { + /* At least one repetition required: insert before the loop + a skip over the initial on-failure-jump instruction */ + insert_jump (dummy_failure_jump, laststart, laststart + 6, b); + b += 3; + } + break; + + case '.': + laststart = b; + PATPUSH (anychar); + break; + + case '[': + while (b - bufp->buffer + > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH) + /* Note that EXTEND_BUFFER clobbers c */ + EXTEND_BUFFER; + + laststart = b; + if (*p == '^') + PATPUSH (charset_not), p++; + else + PATPUSH (charset); + p1 = p; + + PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + /* Clear the whole map */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + /* Read in characters and ranges, setting map bits */ + while (1) + { + PATFETCH (c); + if (c == ']' && p != p1 + 1) break; + if (*p == '-' && p[1] != ']') + { + PATFETCH (c1); + PATFETCH (c1); + while (c <= c1) + b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++; + } + else + { + b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH); + } + } + /* Discard any bitmap bytes that are all 0 at the end of the map. + Decrement the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + break; + + case '(': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_open; + + case ')': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_close; + + case '\n': + if (! (obscure_syntax & RE_NEWLINE_OR)) + goto normal_char; + else + goto handle_bar; + + case '|': + if (! (obscure_syntax & RE_NO_BK_VBAR)) + goto normal_char; + else + goto handle_bar; + + case '\\': + if (p == pend) goto invalid_pattern; + PATFETCH_RAW (c); + switch (c) + { + case '(': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_open: + if (stackp == stacke) goto nesting_too_deep; + if (regnum < RE_NREGS) + { + PATPUSH (start_memory); + PATPUSH (regnum); + } + *stackp++ = b - bufp->buffer; + *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0; + *stackp++ = regnum++; + *stackp++ = begalt - bufp->buffer; + fixup_jump = 0; + laststart = 0; + begalt = b; + break; + + case ')': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_close: + if (stackp == stackb) goto unmatched_close; + begalt = *--stackp + bufp->buffer; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + if (stackp[-1] < RE_NREGS) + { + PATPUSH (stop_memory); + PATPUSH (stackp[-1]); + } + stackp -= 2; + fixup_jump = 0; + if (*stackp) + fixup_jump = *stackp + bufp->buffer - 1; + laststart = *--stackp + bufp->buffer; + break; + + case '|': + if (obscure_syntax & RE_NO_BK_VBAR) + goto normal_backsl; + handle_bar: + insert_jump (on_failure_jump, begalt, b + 6, b); + pending_exact = 0; + b += 3; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = b; + b += 3; + laststart = 0; + begalt = b; + break; + +#ifdef emacs + case '=': + PATPUSH (at_dot); + break; + + case 's': + laststart = b; + PATPUSH (syntaxspec); + PATFETCH (c); + PATPUSH (syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATPUSH (notsyntaxspec); + PATFETCH (c); + PATPUSH (syntax_spec_code[c]); + break; +#endif /* emacs */ + + case 'w': + laststart = b; + PATPUSH (wordchar); + break; + + case 'W': + laststart = b; + PATPUSH (notwordchar); + break; + + case '<': + PATPUSH (wordbeg); + break; + + case '>': + PATPUSH (wordend); + break; + + case 'b': + PATPUSH (wordbound); + break; + + case 'B': + PATPUSH (notwordbound); + break; + + case '`': + PATPUSH (begbuf); + break; + + case '\'': + PATPUSH (endbuf); + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + c1 = c - '0'; + if (c1 >= regnum) + goto normal_char; + for (stackt = stackp - 2; stackt > stackb; stackt -= 4) + if (*stackt == c1) + goto normal_char; + laststart = b; + PATPUSH (duplicate); + PATPUSH (c1); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto handle_plus; + + default: + normal_backsl: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + if (translate) c = translate[c]; + goto normal_char; + } + break; + + default: + normal_char: + if (!pending_exact || pending_exact + *pending_exact + 1 != b + || *pending_exact == 0177 || *p == '*' || *p == '^' + || ((obscure_syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?'))) + { + laststart = b; + PATPUSH (exactn); + pending_exact = b; + PATPUSH (0); + } + PATPUSH (c); + (*pending_exact)++; + } + } + + if (fixup_jump) + store_jump (fixup_jump, jump, b); + + if (stackp != stackb) goto unmatched_open; + + bufp->used = b - bufp->buffer; + return 0; + + invalid_pattern: + return "Invalid regular expression"; + + unmatched_open: + return "Unmatched \\("; + + unmatched_close: + return "Unmatched \\)"; + + end_of_pattern: + return "Premature end of regular expression"; + + nesting_too_deep: + return "Nesting too deep"; + + too_big: + return "Regular expression too big"; + + memory_exhausted: + return "Memory exhausted"; +} + +/* Store where `from' points a jump operation to jump to where `to' points. + `opcode' is the opcode to store. */ + +static int +store_jump (from, opcode, to) + char *from, *to; + char opcode; +{ + from[0] = opcode; + from[1] = (to - (from + 3)) & 0377; + from[2] = (to - (from + 3)) >> 8; +} + +/* Open up space at char FROM, and insert there a jump to TO. + CURRENT_END gives te end of the storage no in use, + so we know how much data to copy up. + OP is the opcode of the jump to insert. + + If you call this function, you must zero out pending_exact. */ + +static int +insert_jump (op, from, to, current_end) + char op; + char *from, *to, *current_end; +{ + register char *pto = current_end + 3; + register char *pfrom = current_end; + while (pfrom != from) + *--pto = *--pfrom; + store_jump (from, op, to); +} + +/* Given a pattern, compute a fastmap from it. + The fastmap records which of the (1 << BYTEWIDTH) possible characters + can start a string that matches the pattern. + This fastmap is used by re_search to skip quickly over totally implausible text. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data area + as bufp->fastmap. + The other components of bufp describe the pattern to be used. */ + +void +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *pattern = (unsigned char *) bufp->buffer; + int size = bufp->used; + register char *fastmap = bufp->fastmap; + register unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + register int j, k; + unsigned char *translate = (unsigned char *) bufp->translate; + + unsigned char *stackb[NFAILURES]; + unsigned char **stackp = stackb; + + bzero (fastmap, (1 << BYTEWIDTH)); + bufp->fastmap_accurate = 1; + bufp->can_be_null = 0; + + while (p) + { + if (p == pend) + { + bufp->can_be_null = 1; + break; + } +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + case exactn: + if (translate) + fastmap[translate[p[1]]] = 1; + else + fastmap[p[1]] = 1; + break; + + case begline: + case before_dot: + case at_dot: + case after_dot: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + continue; + + case endline: + if (translate) + fastmap[translate['\n']] = 1; + else + fastmap['\n'] = 1; + if (bufp->can_be_null != 1) + bufp->can_be_null = 2; + break; + + case finalize_jump: + case maybe_finalize_jump: + case jump: + case dummy_failure_jump: + bufp->can_be_null = 1; + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += j + 1; /* The 1 compensates for missing ++ above */ + if (j > 0) + continue; + /* Jump backward reached implies we just went through + the body of a loop and matched nothing. + Opcode jumped to should be an on_failure_jump. + Just treat it like an ordinary jump. + For a * loop, it has pushed its failure point already; + if so, discard that as redundant. */ + if ((enum regexpcode) *p != on_failure_jump) + continue; + p++; + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += j + 1; /* The 1 compensates for missing ++ above */ + if (stackp != stackb && *stackp == p) + stackp--; + continue; + + case on_failure_jump: + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + *++stackp = p + j; + continue; + + case start_memory: + case stop_memory: + p++; + continue; + + case duplicate: + bufp->can_be_null = 1; + fastmap['\n'] = 1; + case anychar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (j != '\n') + fastmap[j] = 1; + if (bufp->can_be_null) + return; + /* Don't return; check the alternative paths + so we can set can_be_null if appropriate. */ + break; + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; +#endif /* emacs */ + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + + case charset_not: + /* Chars beyond end of map must be allowed */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + } + + /* Get here means we have successfully found the possible starting characters + of one path of the pattern. We need not follow this path any farther. + Instead, look at the next alternative remembered in the stack. */ + if (stackp != stackb) + p = *stackp--; + else + break; + } +} + +/* Like re_search_2, below, but only one string is specified. */ + +int +re_search (pbufp, string, size, startpos, range, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size); +} + +/* Like re_match_2 but tries first a match starting at index STARTPOS, + then at STARTPOS + 1, and so on. + RANGE is the number of places to try before giving up. + If RANGE is negative, the starting positions tried are + STARTPOS, STARTPOS - 1, etc. + It is up to the caller to make sure that range is not so large + as to take the starting position outside of the input strings. + +The value returned is the position at which the match was found, + or -1 if no match was found, + or -2 if error (such as failure stack overflow). */ + +int +re_search_2 (pbufp, string1, size1, string2, size2, startpos, range, regs, mstop) + struct re_pattern_buffer *pbufp; + char *string1, *string2; + int size1, size2; + int startpos; + register int range; + struct re_registers *regs; + int mstop; +{ + register char *fastmap = pbufp->fastmap; + register unsigned char *translate = (unsigned char *) pbufp->translate; + int total = size1 + size2; + int val; + + /* Update the fastmap now if not correct already */ + if (fastmap && !pbufp->fastmap_accurate) + re_compile_fastmap (pbufp); + + /* Don't waste time in a long search for a pattern + that says it is anchored. */ + if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf + && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + while (1) + { + /* If a fastmap is supplied, skip quickly over characters + that cannot possibly be the start of a match. + Note, however, that if the pattern can possibly match + the null string, we must test it at each starting point + so that we take the first null string we get. */ + + if (fastmap && startpos < total && pbufp->can_be_null != 1) + { + if (range > 0) + { + register int lim = 0; + register unsigned char *p; + int irange = range; + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + p = ((unsigned char *) + &(startpos >= size1 ? string2 - size1 : string1)[startpos]); + + if (translate) + { + while (range > lim && !fastmap[translate[*p++]]) + range--; + } + else + { + while (range > lim && !fastmap[*p++]) + range--; + } + startpos += irange - range; + } + else + { + register unsigned char c; + if (startpos >= size1) + c = string2[startpos - size1]; + else + c = string1[startpos]; + c &= 0xff; + if (translate ? !fastmap[translate[c]] : !fastmap[c]) + goto advance; + } + } + + if (range >= 0 && startpos == total + && fastmap && pbufp->can_be_null == 0) + return -1; + + val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop); + if (0 <= val) + { + if (val == -2) + return -2; + return startpos; + } + +#ifdef C_ALLOCA + alloca (0); +#endif /* C_ALLOCA */ + + advance: + if (!range) break; + if (range > 0) range--, startpos++; else range++, startpos--; + } + return -1; +} + +#ifndef emacs /* emacs never uses this */ +int +re_match (pbufp, string, size, pos, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, pos; + struct re_registers *regs; +{ + return re_match_2 (pbufp, 0, 0, string, size, pos, regs, size); +} +#endif /* emacs */ + +/* Maximum size of failure stack. Beyond this, overflow is an error. */ + +int re_max_failures = 2000; + +static int bcmp_translate(); +/* Match the pattern described by PBUFP + against data which is the virtual concatenation of STRING1 and STRING2. + SIZE1 and SIZE2 are the sizes of the two data strings. + Start the match at position POS. + Do not consider matching past the position MSTOP. + + If pbufp->fastmap is nonzero, then it had better be up to date. + + The reason that the data to match are specified as two components + which are to be regarded as concatenated + is so this function can be used directly on the contents of an Emacs buffer. + + -1 is returned if there is no match. -2 is returned if there is + an error (such as match stack overflow). Otherwise the value is the length + of the substring which was matched. */ + +int +re_match_2 (pbufp, string1, size1, string2, size2, pos, regs, mstop) + struct re_pattern_buffer *pbufp; + unsigned char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int mstop; +{ + register unsigned char *p = (unsigned char *) pbufp->buffer; + register unsigned char *pend = p + pbufp->used; + /* End of first string */ + unsigned char *end1; + /* End of second string */ + unsigned char *end2; + /* Pointer just past last char to consider matching */ + unsigned char *end_match_1, *end_match_2; + register unsigned char *d, *dend; + register int mcnt; + unsigned char *translate = (unsigned char *) pbufp->translate; + + /* Failure point stack. Each place that can handle a failure further down the line + pushes a failure point on this stack. It consists of two char *'s. + The first one pushed is where to resume scanning the pattern; + the second pushed is where to resume scanning the strings. + If the latter is zero, the failure point is a "dummy". + If a failure happens and the innermost failure point is dormant, + it discards that failure point and tries the next one. */ + + unsigned char *initial_stack[2 * NFAILURES]; + unsigned char **stackb = initial_stack; + unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES]; + + /* Information on the "contents" of registers. + These are pointers into the input strings; they record + just what was matched (on this attempt) by some part of the pattern. + The start_memory command stores the start of a register's contents + and the stop_memory command stores the end. + + At that point, regstart[regnum] points to the first character in the register, + regend[regnum] points to the first character beyond the end of the register, + regstart_seg1[regnum] is true iff regstart[regnum] points into string1, + and regend_seg1[regnum] is true iff regend[regnum] points into string1. */ + + unsigned char *regstart[RE_NREGS]; + unsigned char *regend[RE_NREGS]; + unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS]; + + /* Set up pointers to ends of strings. + Don't allow the second string to be empty unless both are empty. */ + if (!size2) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings */ + if (mstop <= size1) + { + end_match_1 = string1 + mstop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + mstop - size1; + } + + /* Initialize \) text positions to -1 + to mark ones that no \( or \) has been seen for. */ + + for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++) + regend[mcnt] = (unsigned char *) -1; + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. + `d' is advanced into the following input string whenever necessary, + but this happens before fetching; + therefore, at the beginning of the loop, + `d' can be pointing at the end of a string, + but it cannot equal string2. */ + + if (pos <= size1) + d = string1 + pos, dend = end_match_1; + else + d = string2 + pos - size1, dend = end_match_2; + +/* Write PREFETCH; just before fetching a character with *d. */ +#define PREFETCH \ + while (d == dend) \ + { if (dend == end_match_2) goto fail; /* end of string2 => failure */ \ + d = string2; /* end of string1 => advance to string2. */ \ + dend = end_match_2; } + + /* This loop loops over pattern commands. + It exits by returning from the function if match is complete, + or it drops through if match fails at this starting point in the input data. */ + + while (1) + { + if (p == pend) + /* End of pattern means we have succeeded! */ + { + /* If caller wants register contents data back, convert it to indices */ + if (regs) + { + regs->start[0] = pos; + if (dend == end_match_1) + regs->end[0] = d - string1; + else + regs->end[0] = d - string2 + size1; + for (mcnt = 1; mcnt < RE_NREGS; mcnt++) + { + if (regend[mcnt] == (unsigned char *) -1) + { + regs->start[mcnt] = -1; + regs->end[mcnt] = -1; + continue; + } + if (regstart_seg1[mcnt]) + regs->start[mcnt] = regstart[mcnt] - string1; + else + regs->start[mcnt] = regstart[mcnt] - string2 + size1; + if (regend_seg1[mcnt]) + regs->end[mcnt] = regend[mcnt] - string1; + else + regs->end[mcnt] = regend[mcnt] - string2 + size1; + } + } + if (dend == end_match_1) + return (d - string1 - pos); + else + return d - string2 + size1 - pos; + } + + /* Otherwise match next pattern command */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + + /* \( is represented by a start_memory, \) by a stop_memory. + Both of those commands contain a "register number" argument. + The text matched within the \( and \) is recorded under that number. + Then, \ turns into a `duplicate' command which + is followed by the numeric value of as the register number. */ + + case start_memory: + regstart[*p] = d; + regstart_seg1[*p++] = (dend == end_match_1); + break; + + case stop_memory: + regend[*p] = d; + regend_seg1[*p++] = (dend == end_match_1); + break; + + case duplicate: + { + int regno = *p++; /* Get which register to match against */ + register unsigned char *d2, *dend2; + + d2 = regstart[regno]; + dend2 = ((regstart_seg1[regno] == regend_seg1[regno]) + ? regend[regno] : end_match_1); + while (1) + { + /* Advance to next segment in register contents, if necessary */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */ + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* Advance to next segment in data being matched, if necessary */ + PREFETCH; + + /* mcnt gets # consecutive chars to compare */ + mcnt = dend - d; + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + /* Compare that many; failure if mismatch, else skip them. */ + if (translate ? bcmp_translate (d, d2, mcnt, translate) : bcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + case anychar: + /* fetch a data character */ + PREFETCH; + /* Match anything but a newline. */ + if ((translate ? translate[*d++] : *d++) == '\n') + goto fail; + break; + + case charset: + case charset_not: + { + /* Nonzero for charset_not */ + int not = 0; + register int c; + if (*(p - 1) == (unsigned char) charset_not) + not = 1; + + /* fetch a data character */ + PREFETCH; + + if (translate) + c = translate [*d]; + else + c = *d; + + if (c < *p * BYTEWIDTH + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + d++; + break; + } + + case begline: + if (d == string1 || d[-1] == '\n') + break; + goto fail; + + case endline: + if (d == end2 + || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n')) + break; + goto fail; + + /* "or" constructs ("|") are handled by starting each alternative + with an on_failure_jump that points to the start of the next alternative. + Each alternative except the last ends with a jump to the joining point. + (Actually, each jump except for the last one really jumps + to the following jump, because tensioning the jumps is a hassle.) */ + + /* The start of a stupid repeat has an on_failure_jump that points + past the end of the repeat text. + This makes a failure point so that, on failure to match a repetition, + matching restarts past as many repetitions have been found + with no way to fail and look for another one. */ + + /* A smart repeat is similar but loops back to the on_failure_jump + so that each repetition makes another failure point. */ + + case on_failure_jump: + if (stackp == stacke) + { + unsigned char **stackx; + if (stacke - stackb > re_max_failures * 2) + return -2; + stackx = (unsigned char **) alloca (2 * (stacke - stackb) + * sizeof (char *)); + bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *)); + stackp = stackx + (stackp - stackb); + stacke = stackx + 2 * (stacke - stackb); + stackb = stackx; + } + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + *stackp++ = mcnt + p; + *stackp++ = d; + break; + + /* The end of a smart repeat has an maybe_finalize_jump back. + Change it either to a finalize_jump or an ordinary jump. */ + + case maybe_finalize_jump: + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + { + register unsigned char *p2 = p; + /* Compare what follows with the begining of the repeat. + If we can establish that there is nothing that they would + both match, we can change to finalize_jump */ + while (p2 != pend + && (*p2 == (unsigned char) stop_memory + || *p2 == (unsigned char) start_memory)) + p2++; + if (p2 == pend) + p[-3] = (unsigned char) finalize_jump; + else if (*p2 == (unsigned char) exactn + || *p2 == (unsigned char) endline) + { + register int c = *p2 == (unsigned char) endline ? '\n' : p2[2]; + register unsigned char *p1 = p + mcnt; + /* p1[0] ... p1[2] are an on_failure_jump. + Examine what follows that */ + if (p1[3] == (unsigned char) exactn && p1[5] != c) + p[-3] = (unsigned char) finalize_jump; + else if (p1[3] == (unsigned char) charset + || p1[3] == (unsigned char) charset_not) + { + int not = p1[3] == (unsigned char) charset_not; + if (c < p1[4] * BYTEWIDTH + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + /* not is 1 if c would match */ + /* That means it is not safe to finalize */ + if (!not) + p[-3] = (unsigned char) finalize_jump; + } + } + } + p -= 2; + if (p[-1] != (unsigned char) finalize_jump) + { + p[-1] = (unsigned char) jump; + goto nofinalize; + } + + /* The end of a stupid repeat has a finalize-jump + back to the start, where another failure point will be made + which will point after all the repetitions found so far. */ + + case finalize_jump: + stackp -= 2; + + case jump: + nofinalize: + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += mcnt + 1; /* The 1 compensates for missing ++ above */ + break; + + case dummy_failure_jump: + if (stackp == stacke) + { + unsigned char **stackx + = (unsigned char **) alloca (2 * (stacke - stackb) + * sizeof (char *)); + bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *)); + stackp = stackx + (stackp - stackb); + stacke = stackx + 2 * (stacke - stackb); + stackb = stackx; + } + *stackp++ = 0; + *stackp++ = 0; + goto nofinalize; + + case wordbound: + if (d == string1 /* Points to first char */ + || d == end2 /* Points to end */ + || (d == end1 && size2 == 0)) /* Points to end */ + break; + if ((SYNTAX (d[-1]) == Sword) + != (SYNTAX (d == end1 ? *string2 : *d) == Sword)) + break; + goto fail; + + case notwordbound: + if (d == string1 /* Points to first char */ + || d == end2 /* Points to end */ + || (d == end1 && size2 == 0)) /* Points to end */ + goto fail; + if ((SYNTAX (d[-1]) == Sword) + != (SYNTAX (d == end1 ? *string2 : *d) == Sword)) + goto fail; + break; + + case wordbeg: + if (d == end2 /* Points to end */ + || (d == end1 && size2 == 0) /* Points to end */ + || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */ + goto fail; + if (d == string1 /* Points to first char */ + || SYNTAX (d[-1]) != Sword) /* prev char not letter */ + break; + goto fail; + + case wordend: + if (d == string1 /* Points to first char */ + || SYNTAX (d[-1]) != Sword) /* prev char not letter */ + goto fail; + if (d == end2 /* Points to end */ + || (d == end1 && size2 == 0) /* Points to end */ + || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */ + break; + goto fail; + +#ifdef emacs + case before_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + <= point) + goto fail; + break; + + case at_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + == point) + goto fail; + break; + + case after_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + >= point) + goto fail; + break; + + case wordchar: + mcnt = (int) Sword; + goto matchsyntax; + + case syntaxspec: + mcnt = *p++; + matchsyntax: + PREFETCH; + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail; + break; + + case notwordchar: + mcnt = (int) Sword; + goto matchnotsyntax; + + case notsyntaxspec: + mcnt = *p++; + matchnotsyntax: + PREFETCH; + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail; + break; +#else + case wordchar: + PREFETCH; + if (SYNTAX (*d++) == 0) goto fail; + break; + + case notwordchar: + PREFETCH; + if (SYNTAX (*d++) != 0) goto fail; + break; +#endif /* not emacs */ + + case begbuf: + if (d == string1) /* Note, d cannot equal string2 */ + break; /* unless string1 == string2. */ + goto fail; + + case endbuf: + if (d == end2 || (d == end1 && size2 == 0)) + break; + goto fail; + + case exactn: + /* Match the next few pattern characters exactly. + mcnt is how many characters to match. */ + mcnt = *p++; + if (translate) + { + do + { + PREFETCH; + if (translate[*d++] != *p++) goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH; + if (*d++ != *p++) goto fail; + } + while (--mcnt); + } + break; + } + continue; /* Successfully matched one pattern command; keep matching */ + + /* Jump here if any matching operation fails. */ + fail: + if (stackp != stackb) + /* A restart point is known. Restart there and pop it. */ + { + if (!stackp[-2]) + { /* If innermost failure point is dormant, flush it and keep looking */ + stackp -= 2; + goto fail; + } + d = *--stackp; + p = *--stackp; + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else break; /* Matching at this starting point really fails! */ + } + return -1; /* Failure to match */ +} + +static int +bcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + unsigned char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate [*p1++] != translate [*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points compatible with bsd4.2 regex library */ + +#ifndef emacs + +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + char *s; +{ + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + if (!(re_comp_buf.buffer = (char *) malloc (200))) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH))) + return "Memory exhausted"; + } + return re_compile_pattern (s, strlen (s), &re_comp_buf); +} + +int +re_exec (s) + char *s; +{ + int len = strlen (s); + return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0); +} + +#endif /* emacs */ + +#ifdef test + +#include + +/* Indexed by a character, gives the upper case equivalent of the character */ + +static char upcase[0400] = + { 000, 001, 002, 003, 004, 005, 006, 007, + 010, 011, 012, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 024, 025, 026, 027, + 030, 031, 032, 033, 034, 035, 036, 037, + 040, 041, 042, 043, 044, 045, 046, 047, + 050, 051, 052, 053, 054, 055, 056, 057, + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 072, 073, 074, 075, 076, 077, + 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137, + 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 + }; + +main (argc, argv) + int argc; + char **argv; +{ + char pat[80]; + struct re_pattern_buffer buf; + int i; + char c; + char fastmap[(1 << BYTEWIDTH)]; + + /* Allow a command argument to specify the style of syntax. */ + if (argc > 1) + obscure_syntax = atoi (argv[1]); + + buf.allocated = 40; + buf.buffer = (char *) malloc (buf.allocated); + buf.fastmap = fastmap; + buf.translate = upcase; + + while (1) + { + gets (pat); + + if (*pat) + { + re_compile_pattern (pat, strlen(pat), &buf); + + for (i = 0; i < buf.used; i++) + printchar (buf.buffer[i]); + + putchar ('\n'); + + printf ("%d allocated, %d used.\n", buf.allocated, buf.used); + + re_compile_fastmap (&buf); + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (fastmap[i]) printchar (i); + putchar ('\n'); + } + + gets (pat); /* Now read the string to match against */ + + i = re_match (&buf, pat, strlen (pat), 0, 0); + printf ("Match value %d.\n", i); + } +} + +#ifdef NOTDEF +print_buf (bufp) + struct re_pattern_buffer *bufp; +{ + int i; + + printf ("buf is :\n----------------\n"); + for (i = 0; i < bufp->used; i++) + printchar (bufp->buffer[i]); + + printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used); + + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->fastmap[i]) + printchar (i); + printf ("\nAllowed by translate: "); + if (bufp->translate) + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->translate[i]) + printchar (i); + printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't"); + printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not"); +} +#endif + +printchar (c) + char c; +{ + if (c < 041 || c >= 0177) + { + putchar ('\\'); + putchar (((c >> 6) & 3) + '0'); + putchar (((c >> 3) & 7) + '0'); + putchar ((c & 7) + '0'); + } + else + putchar (c); +} + +error (string) + char *string; +{ + puts (string); + exit (1); +} + +#endif /* test */ diff --git a/gdb/regex.h b/gdb/regex.h new file mode 100644 index 00000000000..d0d8a82835b --- /dev/null +++ b/gdb/regex.h @@ -0,0 +1,185 @@ +/* Definitions for data structures callers pass the regex library. + Copyright (C) 1985, 1989 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + + +/* Define number of parens for which we record the beginnings and ends. + This affects how much space the `struct re_registers' type takes up. */ +#ifndef RE_NREGS +#define RE_NREGS 10 +#endif + +/* These bits are used in the obscure_syntax variable to choose among + alternative regexp syntaxes. */ + +/* 1 means plain parentheses serve as grouping, and backslash + parentheses are needed for literal searching. + 0 means backslash-parentheses are grouping, and plain parentheses + are for literal searching. */ +#define RE_NO_BK_PARENS 1 + +/* 1 means plain | serves as the "or"-operator, and \| is a literal. + 0 means \| serves as the "or"-operator, and | is a literal. */ +#define RE_NO_BK_VBAR 2 + +/* 0 means plain + or ? serves as an operator, and \+, \? are literals. + 1 means \+, \? are operators and plain +, ? are literals. */ +#define RE_BK_PLUS_QM 4 + +/* 1 means | binds tighter than ^ or $. + 0 means the contrary. */ +#define RE_TIGHT_VBAR 8 + +/* 1 means treat \n as an _OR operator + 0 means treat it as a normal character */ +#define RE_NEWLINE_OR 16 + +/* 0 means that a special characters (such as *, ^, and $) always have + their special meaning regardless of the surrounding context. + 1 means that special characters may act as normal characters in some + contexts. Specifically, this applies to: + ^ - only special at the beginning, or after ( or | + $ - only special at the end, or before ) or | + *, +, ? - only special when not after the beginning, (, or | */ +#define RE_CONTEXT_INDEP_OPS 32 + +/* Now define combinations of bits for the standard possibilities. */ +#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS) +#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR) +#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR) +#define RE_SYNTAX_EMACS 0 + +/* This data structure is used to represent a compiled pattern. */ + +struct re_pattern_buffer + { + char *buffer; /* Space holding the compiled pattern commands. */ + int allocated; /* Size of space that buffer points to */ + int used; /* Length of portion of buffer actually occupied */ + char *fastmap; /* Pointer to fastmap, if any, or zero if none. */ + /* re_search uses the fastmap, if there is one, + to skip quickly over totally implausible characters */ + char *translate; /* Translate table to apply to all characters before comparing. + Or zero for no translation. + The translation is applied to a pattern when it is compiled + and to data when it is matched. */ + char fastmap_accurate; + /* Set to zero when a new pattern is stored, + set to one when the fastmap is updated from it. */ + char can_be_null; /* Set to one by compiling fastmap + if this pattern might match the null string. + It does not necessarily match the null string + in that case, but if this is zero, it cannot. + 2 as value means can match null string + but at end of range or before a character + listed in the fastmap. */ + }; + +/* Structure to store "register" contents data in. + + Pass the address of such a structure as an argument to re_match, etc., + if you want this information back. + + start[i] and end[i] record the string matched by \( ... \) grouping i, + for i from 1 to RE_NREGS - 1. + start[0] and end[0] record the entire string matched. */ + +struct re_registers + { + int start[RE_NREGS]; + int end[RE_NREGS]; + }; + +/* These are the command codes that appear in compiled regular expressions, one per byte. + Some command codes are followed by argument bytes. + A command code can specify any interpretation whatever for its arguments. + Zero-bytes may appear in the compiled regular expression. */ + +enum regexpcode + { + unused, + exactn, /* followed by one byte giving n, and then by n literal bytes */ + begline, /* fails unless at beginning of line */ + endline, /* fails unless at end of line */ + jump, /* followed by two bytes giving relative address to jump to */ + on_failure_jump, /* followed by two bytes giving relative address of place + to resume at in case of failure. */ + finalize_jump, /* Throw away latest failure point and then jump to address. */ + maybe_finalize_jump, /* Like jump but finalize if safe to do so. + This is used to jump back to the beginning + of a repeat. If the command that follows + this jump is clearly incompatible with the + one at the beginning of the repeat, such that + we can be sure that there is no use backtracking + out of repetitions already completed, + then we finalize. */ + dummy_failure_jump, /* jump, and push a dummy failure point. + This failure point will be thrown away + if an attempt is made to use it for a failure. + A + construct makes this before the first repeat. */ + anychar, /* matches any one character */ + charset, /* matches any one char belonging to specified set. + First following byte is # bitmap bytes. + Then come bytes for a bit-map saying which chars are in. + Bits in each byte are ordered low-bit-first. + A character is in the set if its bit is 1. + A character too large to have a bit in the map + is automatically not in the set */ + charset_not, /* similar but match any character that is NOT one of those specified */ + start_memory, /* starts remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + stop_memory, /* stops remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + duplicate, /* match a duplicate of something remembered. + Followed by one byte containing the index of the memory register. */ + before_dot, /* Succeeds if before dot */ + at_dot, /* Succeeds if at dot */ + after_dot, /* Succeeds if after dot */ + begbuf, /* Succeeds if at beginning of buffer */ + endbuf, /* Succeeds if at end of buffer */ + wordchar, /* Matches any word-constituent character */ + notwordchar, /* Matches any char that is not a word-constituent */ + wordbeg, /* Succeeds if at word beginning */ + wordend, /* Succeeds if at word end */ + wordbound, /* Succeeds if at a word boundary */ + notwordbound, /* Succeeds if not at a word boundary */ + syntaxspec, /* Matches any character whose syntax is specified. + followed by a byte which contains a syntax code, Sword or such like */ + notsyntaxspec /* Matches any character whose syntax differs from the specified. */ + }; + +extern char *re_compile_pattern (); +/* Is this really advertised? */ +extern void re_compile_fastmap (); +extern int re_search (), re_search_2 (); +extern int re_match (), re_match_2 (); + +/* 4.2 bsd compatibility (yuck) */ +extern char *re_comp (); +extern int re_exec (); + +#ifdef SYNTAX_TABLE +extern char *re_syntax_table; +#endif diff --git a/gdb/remote-eb.c b/gdb/remote-eb.c new file mode 100644 index 00000000000..a14090580ce --- /dev/null +++ b/gdb/remote-eb.c @@ -0,0 +1,932 @@ +/* Remote debugging interface for AMD 29000 EBMON on IBM PC, for GDB. + Copyright 1990-1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Jim Kingdon for Cygnus. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This is like remote.c but is for an esoteric situation-- + having a 29k board in a PC hooked up to a unix machine with + a serial line, and running ctty com1 on the PC, through which + the unix machine can run ebmon. Not to mention that the PC + has PC/NFS, so it can access the same executables that gdb can, + over the net in real time. */ + +#include +#include +#include "defs.h" +#include "tm-29k.h" +#include "param-no-tm.h" +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include +#include +#include +#include +#include "terminal.h" +#include "target.h" + +extern void add_syms_addr_command (); +extern struct value *call_function_by_hand(); + +extern struct target_ops eb_ops; /* Forward declaration */ + +#define LOG_FILE "eb.log" +#if defined (LOG_FILE) +FILE *log_file; +#endif + +static int timeout = 5; + +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + eb_open knows that we don't have a file open when the program + starts. */ +int eb_desc = -1; + +/* stream which is fdopen'd from eb_desc. Only valid when + eb_desc != -1. */ +FILE *eb_stream; + +/* Read a character from the remote system, doing all the fancy + timeout stuff. */ +static int +readchar () +{ + char buf; + + buf = '\0'; +#ifdef HAVE_TERMIO + /* termio does the timeout for us. */ + read (eb_desc, &buf, 1); +#else + alarm (timeout); + if (read (eb_desc, &buf, 1) < 0) + { + if (errno == EINTR) + error ("Timeout reading from remote system."); + else + perror_with_name ("remote"); + } + alarm (0); +#endif + + if (buf == '\0') + error ("Timeout reading from remote system."); +#if defined (LOG_FILE) + putc (buf & 0x7f, log_file); +#endif + return buf & 0x7f; +} + +/* Keep discarding input from the remote system, until STRING is found. + Let the user break out immediately. */ +static void +expect (string) + char *string; +{ + char *p = string; + + immediate_quit = 1; + while (1) + { + if (readchar() == *p) + { + p++; + if (*p == '\0') + { + immediate_quit = 0; + return; + } + } + else + p = string; + } +} + +/* Keep discarding input until we see the ebmon prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an expect_prompt(). Exception: eb_resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a eb_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ +static void +expect_prompt () +{ +#if defined (LOG_FILE) + /* This is a convenient place to do this. The idea is to do it often + enough that we never lose much data if we terminate abnormally. */ + fflush (log_file); +#endif + expect ("\n# "); +} + +/* Get a hex digit from the remote system & return its value. + If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ +static int +get_hex_digit (ignore_space) + int ignore_space; +{ + int ch; + while (1) + { + ch = readchar (); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch == ' ' && ignore_space) + ; + else + { + expect_prompt (); + error ("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from eb_desc and put it in *BYT. Accept any number + leading spaces. */ +static void +get_hex_byte (byt) + char *byt; +{ + int val; + + val = get_hex_digit (1) << 4; + val |= get_hex_digit (0); + *byt = val; +} + +/* Get N 32-bit words from remote, each preceded by a space, + and put them in registers starting at REGNO. */ +static void +get_hex_regs (n, regno) + int n; + int regno; +{ + long val; + int i; + + for (i = 0; i < n; i++) + { + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + get_hex_digit (j == 0); + supply_register (regno++, &val); + } +} + +/* Called when SIGALRM signal sent due to alarm() timeout. */ +#ifndef HAVE_TERMIO + +#ifndef __STDC__ +#define volatile /**/ +#endif +volatile int n_alarms; + +void +eb_timer () +{ +#if 0 + if (kiodebug) + printf ("eb_timer called\n"); +#endif + n_alarms++; +} +#endif + +/* malloc'd name of the program on the remote system. */ +static char *prog_name = NULL; + +/* Nonzero if we have loaded the file ("yc") and not yet issued a "gi" + command. "gi" is supposed to happen exactly once for each "yc". */ +static int need_gi = 0; + +/* Number of SIGTRAPs we need to simulate. That is, the next + NEED_ARTIFICIAL_TRAP calls to eb_wait should just return + SIGTRAP without actually waiting for anything. */ + +static int need_artificial_trap = 0; + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +void +eb_start (inferior_args) +char *inferior_args; +{ + /* OK, now read in the file. Y=read, C=COFF, D=no symbols + 0=start address, %s=filename. */ + + fprintf (eb_stream, "YC D,0:%s", prog_name); + + if (inferior_args != NULL) + fprintf(eb_stream, " %s", inferior_args); + + fprintf (eb_stream, "\n"); + fflush (eb_stream); + + expect_prompt (); + + need_gi = 1; +} + +/* Translate baud rates from integers to damn B_codes. Unix should + have outgrown this crap years ago, but even POSIX wouldn't buck it. */ + +#ifndef B19200 +#define B19200 EXTA +#endif +#ifndef B38400 +#define B38400 EXTB +#endif + +struct {int rate, damn_b;} baudtab[] = { + {0, B0}, + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {-1, -1}, +}; + +int damn_b (rate) + int rate; +{ + int i; + + for (i = 0; baudtab[i].rate != -1; i++) + if (rate == baudtab[i].rate) return baudtab[i].damn_b; + return B38400; /* Random */ +} + + +/* Open a connection to a remote debugger. + NAME is the filename used for communication, then a space, + then the name of the program as we should name it to EBMON. */ + +static int baudrate = 9600; +static char *dev_name; +void +eb_open (name, from_tty) + char *name; + int from_tty; +{ + TERMINAL sg; + + char *p; + + /* Find the first whitespace character, it separates dev_name from + prog_name. */ + if (name == 0) + goto erroid; + + for (p = name; + *p != '\0' && !isspace (*p); p++) + ; + if (*p == '\0') +erroid: + error ("\ +Please include the name of the device for the serial port,\n\ +the baud rate, and the name of the program to run on the remote system."); + dev_name = alloca (p - name + 1); + strncpy (dev_name, name, p - name); + dev_name[p - name] = '\0'; + + /* Skip over the whitespace after dev_name */ + for (; isspace (*p); p++) + /*EMPTY*/; + + if (1 != sscanf (p, "%d ", &baudrate)) + goto erroid; + + /* Skip the number and then the spaces */ + for (; isdigit (*p); p++) + /*EMPTY*/; + for (; isspace (*p); p++) + /*EMPTY*/; + + if (prog_name != NULL) + free (prog_name); + prog_name = savestring (p, strlen (p)); + + eb_close (0); + + eb_desc = open (dev_name, O_RDWR); + if (eb_desc < 0) + perror_with_name (dev_name); + ioctl (eb_desc, TIOCGETP, &sg); +#ifdef HAVE_TERMIO + sg.c_cc[VMIN] = 0; /* read with timeout. */ + sg.c_cc[VTIME] = timeout * 10; + sg.c_lflag &= ~(ICANON | ECHO); + sg.c_cflag = (sg.c_cflag & ~CBAUD) | damn_b (baudrate); +#else + sg.sg_ispeed = damn_b (baudrate); + sg.sg_ospeed = damn_b (baudrate); + sg.sg_flags |= RAW | ANYP; + sg.sg_flags &= ~ECHO; +#endif + + ioctl (eb_desc, TIOCSETP, &sg); + eb_stream = fdopen (eb_desc, "r+"); + + push_target (&eb_ops); + if (from_tty) + printf ("Remote %s debugging %s using %s\n", target_shortname, + prog_name, dev_name); + +#ifndef HAVE_TERMIO +#ifndef NO_SIGINTERRUPT + /* Cause SIGALRM's to make reads fail with EINTR instead of resuming + the read. */ + if (siginterrupt (SIGALRM, 1) != 0) + perror ("eb_open: error in siginterrupt"); +#endif + + /* Set up read timeout timer. */ + if ((void (*)) signal (SIGALRM, eb_timer) == (void (*)) -1) + perror ("eb_open: error in signal"); +#endif + +#if defined (LOG_FILE) + log_file = fopen (LOG_FILE, "w"); + if (log_file == NULL) + perror_with_name (LOG_FILE); +#endif + + /* Hello? Are you there? */ + write (eb_desc, "\n", 1); + + expect_prompt (); +} + +/* Close out all files and local state before this target loses control. */ + +void +eb_close (quitting) + int quitting; +{ + + /* Due to a bug in Unix, fclose closes not only the stdio stream, + but also the file descriptor. So we don't actually close + eb_desc. */ + if (eb_stream) + fclose (eb_stream); /* This also closes eb_desc */ + if (eb_desc >= 0) + /* close (eb_desc); */ + + /* Do not try to close eb_desc again, later in the program. */ + eb_stream = NULL; + eb_desc = -1; + +#if defined (LOG_FILE) + if (ferror (log_file)) + printf ("Error writing log file.\n"); + if (fclose (log_file) != 0) + printf ("Error closing log file.\n"); +#endif +} + +/* Terminate the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ +void +eb_detach (from_tty) + int from_tty; +{ + pop_target(); /* calls eb_close to do the real work */ + if (from_tty) + printf ("Ending remote %s debugging\n", target_shortname); +} + +/* Tell the remote machine to resume. */ + +void +eb_resume (step, sig) + int step, sig; +{ + if (step) + { + write (eb_desc, "t 1,s\n", 6); + /* Wait for the echo. */ + expect ("t 1,s\r"); + /* Then comes a line containing the instruction we stepped to. */ + expect ("\n@"); + /* Then we get the prompt. */ + expect_prompt (); + + /* Force the next eb_wait to return a trap. Not doing anything + about I/O from the target means that the user has to type + "continue" to see any. This should be fixed. */ + need_artificial_trap = 1; + } + else + { + if (need_gi) + { + need_gi = 0; + write (eb_desc, "gi\n", 3); + + /* Swallow the echo of "gi". */ + expect ("gi\r"); + } + else + { + write (eb_desc, "GR\n", 3); + /* Swallow the echo. */ + expect ("GR\r"); + } + } +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +int +eb_wait (status) + WAITTYPE *status; +{ + /* Strings to look for. '?' means match any single character. + Note that with the algorithm we use, the initial character + of the string cannot recur in the string, or we will not + find some cases of the string in the input. */ + + static char bpt[] = "Invalid interrupt taken - #0x50 - "; + /* It would be tempting to look for "\n[__exit + 0x8]\n" + but that requires loading symbols with "yc i" and even if + we did do that we don't know that the file has symbols. */ + static char exitmsg[] = "\n@????????I JMPTI GR121,LR0"; + char *bp = bpt; + char *ep = exitmsg; + + /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars. */ + char swallowed[50]; + /* Current position in swallowed. */ + char *swallowed_p = swallowed; + + int ch; + int ch_handled; + + int old_timeout = timeout; + + WSETEXIT ((*status), 0); + + if (need_artificial_trap != 0) + { + WSETSTOP ((*status), SIGTRAP); + need_artificial_trap--; + return 0; + } + + timeout = 0; /* Don't time out -- user program is running. */ + while (1) + { + ch_handled = 0; + ch = readchar (); + if (ch == *bp) + { + bp++; + if (*bp == '\0') + break; + ch_handled = 1; + + *swallowed_p++ = ch; + } + else + bp = bpt; + + if (ch == *ep || *ep == '?') + { + ep++; + if (*ep == '\0') + break; + + if (!ch_handled) + *swallowed_p++ = ch; + ch_handled = 1; + } + else + ep = exitmsg; + + if (!ch_handled) + { + char *p; + + /* Print out any characters which have been swallowed. */ + for (p = swallowed; p < swallowed_p; ++p) + putc (*p, stdout); + swallowed_p = swallowed; + + putc (ch, stdout); + } + } + expect_prompt (); + if (*bp== '\0') + WSETSTOP ((*status), SIGTRAP); + else + WSETEXIT ((*status), 0); + timeout = old_timeout; + + return 0; +} + +/* Return the name of register number REGNO + in the form input and output by EBMON. + + Returns a pointer to a static buffer containing the answer. */ +static char * +get_reg_name (regno) + int regno; +{ + static char buf[80]; + if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32) + sprintf (buf, "GR%03d", regno - GR96_REGNUM + 96); + else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128) + sprintf (buf, "LR%03d", regno - LR0_REGNUM); + else if (regno == Q_REGNUM) + strcpy (buf, "SR131"); + else if (regno >= BP_REGNUM && regno <= CR_REGNUM) + sprintf (buf, "SR%03d", regno - BP_REGNUM + 133); + else if (regno == ALU_REGNUM) + strcpy (buf, "SR132"); + else if (regno >= IPC_REGNUM && regno <= IPB_REGNUM) + sprintf (buf, "SR%03d", regno - IPC_REGNUM + 128); + else if (regno >= VAB_REGNUM && regno <= LRU_REGNUM) + sprintf (buf, "SR%03d", regno - VAB_REGNUM); + else if (regno == GR1_REGNUM) + strcpy (buf, "GR001"); + return buf; +} + +/* Read the remote registers into the block REGS. */ + +static void +eb_fetch_registers () +{ + int reg_index; + int regnum_index; + char tempbuf[10]; + int i; + +#if 0 + /* This should not be necessary, because one is supposed to read the + registers only when the inferior is stopped (at least with + ptrace() and why not make it the same for remote?). */ + /* ^A is the "normal character" used to make sure we are talking to EBMON + and not to the program being debugged. */ + write (eb_desc, "\001\n"); + expect_prompt (); +#endif + + write (eb_desc, "dw gr96,gr127\n", 14); + for (reg_index = 96, regnum_index = GR96_REGNUM; + reg_index < 128; + reg_index += 4, regnum_index += 4) + { + sprintf (tempbuf, "GR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (4, regnum_index); + expect ("\n"); + } + + for (i = 0; i < 128; i += 32) + { + /* The PC has a tendency to hang if we get these + all in one fell swoop ("dw lr0,lr127"). */ + sprintf (tempbuf, "dw lr%d\n", i); + write (eb_desc, tempbuf, strlen (tempbuf)); + for (reg_index = i, regnum_index = LR0_REGNUM + i; + reg_index < i + 32; + reg_index += 4, regnum_index += 4) + { + sprintf (tempbuf, "LR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (4, regnum_index); + expect ("\n"); + } + } + + write (eb_desc, "dw sr133,sr133\n", 15); + expect ("SR133 "); + get_hex_regs (1, BP_REGNUM); + expect ("\n"); + + write (eb_desc, "dw sr134,sr134\n", 15); + expect ("SR134 "); + get_hex_regs (1, FC_REGNUM); + expect ("\n"); + + write (eb_desc, "dw sr135,sr135\n", 15); + expect ("SR135 "); + get_hex_regs (1, CR_REGNUM); + expect ("\n"); + + write (eb_desc, "dw sr131,sr131\n", 15); + expect ("SR131 "); + get_hex_regs (1, Q_REGNUM); + expect ("\n"); + + write (eb_desc, "dw sr0,sr14\n", 12); + for (reg_index = 0, regnum_index = VAB_REGNUM; + regnum_index <= LRU_REGNUM; + regnum_index += 4, reg_index += 4) + { + sprintf (tempbuf, "SR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (reg_index == 12 ? 3 : 4, regnum_index); + expect ("\n"); + } + + /* There doesn't seem to be any way to get these. */ + { + int val = -1; + supply_register (FPE_REGNUM, &val); + supply_register (INT_REGNUM, &val); + supply_register (FPS_REGNUM, &val); + supply_register (EXO_REGNUM, &val); + } + + write (eb_desc, "dw gr1,gr1\n", 11); + expect ("GR001 "); + get_hex_regs (1, GR1_REGNUM); + expect_prompt (); +} + +/* Fetch register REGNO, or all registers if REGNO is -1. + Returns errno value. */ +int +eb_fetch_register (regno) + int regno; +{ + if (regno == -1) + eb_fetch_registers (); + else + { + char *name = get_reg_name (regno); + fprintf (eb_stream, "dw %s,%s\n", name, name); + expect (name); + expect (" "); + get_hex_regs (1, regno); + expect_prompt (); + } + return 0; +} + +/* Store the remote registers from the contents of the block REGS. */ + +static void +eb_store_registers () +{ + int i, j; + fprintf (eb_stream, "s gr1,%x\n", read_register (GR1_REGNUM)); + expect_prompt (); + + for (j = 0; j < 32; j += 16) + { + fprintf (eb_stream, "s gr%d,", j + 96); + for (i = 0; i < 15; ++i) + fprintf (eb_stream, "%x,", read_register (GR96_REGNUM + j + i)); + fprintf (eb_stream, "%x\n", read_register (GR96_REGNUM + j + 15)); + expect_prompt (); + } + + for (j = 0; j < 128; j += 16) + { + fprintf (eb_stream, "s lr%d,", j); + for (i = 0; i < 15; ++i) + fprintf (eb_stream, "%x,", read_register (LR0_REGNUM + j + i)); + fprintf (eb_stream, "%x\n", read_register (LR0_REGNUM + j + 15)); + expect_prompt (); + } + + fprintf (eb_stream, "s sr133,%x,%x,%x\n", read_register (BP_REGNUM), + read_register (FC_REGNUM), read_register (CR_REGNUM)); + expect_prompt (); + fprintf (eb_stream, "s sr131,%x\n", read_register (Q_REGNUM)); + expect_prompt (); + fprintf (eb_stream, "s sr0,"); + for (i = 0; i < 11; ++i) + fprintf (eb_stream, "%x,", read_register (VAB_REGNUM + i)); + fprintf (eb_stream, "%x\n", read_register (VAB_REGNUM + 11)); + expect_prompt (); +} + +/* Store register REGNO, or all if REGNO == 0. + Return errno value. */ +int +eb_store_register (regno) + int regno; +{ + if (regno == -1) + eb_store_registers (); + else + { + char *name = get_reg_name (regno); + fprintf (eb_stream, "s %s,%x\n", name, read_register (regno)); + /* Setting GR1 changes the numbers of all the locals, so + invalidate the register cache. Do this *after* calling + read_register, because we want read_register to return the + value that write_register has just stuffed into the registers + array, not the value of the register fetched from the + inferior. */ + if (regno == GR1_REGNUM) + registers_changed (); + expect_prompt (); + } + return 0; +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +void +eb_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +/* FIXME! Merge these two. */ +int +eb_xfer_inferior_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + if (write) + return eb_write_inferior_memory (memaddr, myaddr, len); + else + return eb_write_inferior_memory (memaddr, myaddr, len); +} + +void +eb_files_info () +{ + printf ("\tAttached to %s at %d baud and running program %s.\n", + dev_name, baudrate, prog_name); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns errno value. */ +int +eb_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i; + + for (i = 0; i < len; i++) + { + if ((i % 16) == 0) + fprintf (eb_stream, "sb %x,", memaddr + i); + if ((i % 16) == 15 || i == len - 1) + { + fprintf (eb_stream, "%x\n", ((unsigned char *)myaddr)[i]); + expect_prompt (); + } + else + fprintf (eb_stream, "%x,", ((unsigned char *)myaddr)[i]); + } + return 0; +} + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns errno value. */ +int +eb_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i; + + /* Number of bytes read so far. */ + int count; + + /* Starting address of this pass. */ + unsigned long startaddr; + + /* Number of bytes to read in this pass. */ + int len_this_pass; + + /* Note that this code works correctly if startaddr is just less + than UINT_MAX (well, really CORE_ADDR_MAX if there was such a + thing). That is, something like + eb_read_bytes (CORE_ADDR_MAX - 4, foo, 4) + works--it never adds len to memaddr and gets 0. */ + /* However, something like + eb_read_bytes (CORE_ADDR_MAX - 3, foo, 4) + doesn't need to work. Detect it and give up if there's an attempt + to do that. */ + if (((memaddr - 1) + len) < memaddr) + return EIO; + + startaddr = memaddr; + count = 0; + while (count < len) + { + len_this_pass = 16; + if ((startaddr % 16) != 0) + len_this_pass -= startaddr % 16; + if (len_this_pass > (len - count)) + len_this_pass = (len - count); + + fprintf (eb_stream, "db %x,%x\n", startaddr, + (startaddr - 1) + len_this_pass); + expect ("\n"); + + /* Look for 8 hex digits. */ + i = 0; + while (1) + { + if (isxdigit (readchar ())) + ++i; + else + { + expect_prompt (); + error ("Hex digit expected from remote system."); + } + if (i >= 8) + break; + } + + expect (" "); + + for (i = 0; i < len_this_pass; i++) + get_hex_byte (&myaddr[count++]); + + expect_prompt (); + + startaddr += len_this_pass; + } + return 0; +} + +/* Define the target subroutine names */ + +struct target_ops eb_ops = { + "amd-eb", "Remote serial AMD EBMON target", + eb_open, eb_close, + 0, eb_detach, eb_resume, eb_wait, + eb_fetch_register, eb_store_register, + eb_prepare_to_store, 0, 0, /* conv_to, conv_from */ + eb_xfer_inferior_memory, eb_files_info, + 0, 0, /* Breakpoints */ + 0, 0, 0, 0, 0, /* Terminal handling */ + 0, /* FIXME, kill */ + 0, add_syms_addr_command, /* load */ + call_function_by_hand, + 0, /* lookup_symbol */ + 0, /* create_inferior FIXME, eb_start here or something? */ + 0, /* mourn_inferior FIXME */ + process_stratum, 0, /* next */ + 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_remote_eb () +{ + add_target (&eb_ops); +} diff --git a/gdb/remote-multi.shar b/gdb/remote-multi.shar new file mode 100755 index 00000000000..86c9cf0217a --- /dev/null +++ b/gdb/remote-multi.shar @@ -0,0 +1,1313 @@ +#!/bin/sh +# This is a shell archive. +# Run the file through sh to extract its contents. +# shar: Shell Archiver +# Run the following text with /bin/sh to create: +# Remote_Makefile +# remote_gutils.c +# remote_inflow.c +# remote_server.c +# remote_utils.c +# This archive created: Fri Jun 23 17:06:55 1989 +cat << \SHAR_EOF > Remote_Makefile +# Makefile for the remote server for GDB, the GNU debugger. +# Copyright (C) 1986, 1989 Free Software Foundation, Inc. +# +# This file is part of GDB. +# +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +CFLAGS = -g +CC = cc + +SERVER = remote_server.o\ + remote_inflow.o\ + remote_utils.o\ + remote_gutils.o + +prog : $(SERVER) + $(CC) -g -o serve $(SERVER) +SHAR_EOF +cat << \SHAR_EOF > remote_gutils.c +/* General utility routines for the remote server for GDB, the GNU debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include "defs.h" + +void error (); +void fatal (); + +/* Chain of cleanup actions established with make_cleanup, + to be executed if an error happens. */ + +static struct cleanup *cleanup_chain; + +/* Nonzero means a quit has been requested. */ + +int quit_flag; + +/* Nonzero means quit immediately if Control-C is typed now, + rather than waiting until QUIT is executed. */ + +int immediate_quit; + +/* Add a new cleanup to the cleanup_chain, + and return the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. + Args are FUNCTION to clean up with, and ARG to pass to it. */ + +struct cleanup * +make_cleanup (function, arg) + void (*function) (); + int arg; +{ + register struct cleanup *new + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + register struct cleanup *old_chain = cleanup_chain; + + new->next = cleanup_chain; + new->function = function; + new->arg = arg; + cleanup_chain = new; + + return old_chain; +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +do_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + (*ptr->function) (ptr->arg); + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* Discard cleanups, not doing the actions they describe, + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +discard_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* This function is useful for cleanups. + Do + + foo = xmalloc (...); + old_chain = make_cleanup (free_current_contents, &foo); + + to arrange to free the object thus allocated. */ + +void +free_current_contents (location) + char **location; +{ + free (*location); +} + +/* Generally useful subroutines used throughout the program. */ + +/* Like malloc but get error if no storage available. */ + +char * +xmalloc (size) + long size; +{ + register char *val = (char *) malloc (size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Like realloc but get error if no storage available. */ + +char * +xrealloc (ptr, size) + char *ptr; + long size; +{ + register char *val = (char *) realloc (ptr, size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char *err; + char *combined; + + if (errno < sys_nerr) + err = sys_errlist[errno]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + error ("%s.", combined); +} + +/* Print the system error message for ERRCODE, and also mention STRING + as the file name for which the error was encountered. */ + +void +print_sys_errmsg (string, errcode) + char *string; + int errcode; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + char *err; + char *combined; + + if (errcode < sys_nerr) + err = sys_errlist[errcode]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + printf ("%s.\n", combined); +} + +void +quit () +{ + fflush (stdout); + ioctl (fileno (stdout), TIOCFLUSH, 0); + error ("Quit"); +} + +/* Control C comes here */ + +void +request_quit () +{ + quit_flag = 1; + if (immediate_quit) + quit (); +} + +/* Print an error message and return to command level. + STRING is the error message, used as a fprintf string, + and ARG is passed as an argument to it. */ + +void +error (string, arg1, arg2, arg3) + char *string; + int arg1, arg2, arg3; +{ + fflush (stdout); + fprintf (stderr, string, arg1, arg2, arg3); + fprintf (stderr, "\n"); + /************return_to_top_level ();************/ +} + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + STRING and ARG are passed to fprintf. */ + +void +fatal (string, arg) + char *string; + int arg; +{ + fprintf (stderr, "gdb: "); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + exit (1); +} + +/* Make a copy of the string at PTR with SIZE characters + (and add a null character at the end in the copy). + Uses malloc to get the space. Returns the address of the copy. */ + +char * +savestring (ptr, size) + char *ptr; + int size; +{ + register char *p = (char *) xmalloc (size + 1); + bcopy (ptr, p, size); + p[size] = 0; + return p; +} + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1; + register char *val = (char *) xmalloc (len); + strcpy (val, s1); + strcat (val, s2); + strcat (val, s3); + return val; +} + +void +print_spaces (n, file) + register int n; + register FILE *file; +{ + while (n-- > 0) + fputc (' ', file); +} + +/* Ask user a y-or-n question and return 1 iff answer is yes. + Takes three args which are given to printf to print the question. + The first, a control string, should end in "? ". + It should not say how to answer, because we do that. */ + +int +query (ctlstr, arg1, arg2) + char *ctlstr; +{ + register int answer; + + /* Automatically answer "yes" if input is not from a terminal. */ + /***********if (!input_from_terminal_p ()) + return 1; *************************/ + + while (1) + { + printf (ctlstr, arg1, arg2); + printf ("(y or n) "); + fflush (stdout); + answer = fgetc (stdin); + clearerr (stdin); /* in case of C-d */ + if (answer != '\n') + while (fgetc (stdin) != '\n') clearerr (stdin); + if (answer >= 'a') + answer -= 040; + if (answer == 'Y') + return 1; + if (answer == 'N') + return 0; + printf ("Please answer y or n.\n"); + } +} + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +int +parse_escape (string_ptr) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'e': + return 033; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') + { + i *= 8; + i += c - '0'; + } + else + { + (*string_ptr)--; + break; + } + } + return i; + } + default: + return c; + } +} + +void +printchar (ch, stream) + unsigned char ch; + FILE *stream; +{ + register int c = ch; + if (c < 040 || c >= 0177) + { + if (c == '\n') + fprintf (stream, "\\n"); + else if (c == '\b') + fprintf (stream, "\\b"); + else if (c == '\t') + fprintf (stream, "\\t"); + else if (c == '\f') + fprintf (stream, "\\f"); + else if (c == '\r') + fprintf (stream, "\\r"); + else if (c == 033) + fprintf (stream, "\\e"); + else if (c == '\a') + fprintf (stream, "\\a"); + else + fprintf (stream, "\\%03o", c); + } + else + { + if (c == '\\' || c == '"' || c == '\'') + fputc ('\\', stream); + fputc (c, stream); + } +} +SHAR_EOF +cat << \SHAR_EOF > remote_inflow.c +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. +*/ + +#include "defs.h" +#include "param.h" +#include "wait.h" +#include "frame.h" +#include "inferior.h" +/*************************** +#include "initialize.h" +****************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/***************Begin MY defs*********************/ +int quit_flag = 0; +char registers[REGISTER_BYTES]; + +/* Index within `registers' of the first byte of the space for + register N. */ + + +char buf2[MAX_REGISTER_RAW_SIZE]; +/***************End MY defs*********************/ + +#ifdef NEW_SUN_PTRACE +#include +#include +#endif + +extern char **environ; +extern int errno; +extern int inferior_pid; +void error(), quit(), perror_with_name(); +int query(); +void supply_register(), write_register(); +CORE_ADDR read_register(); + +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (allargs, env) + char **allargs; + char **env; +{ + int pid; + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + + /* exec is said to fail if the executable is open. */ + /****************close_exec_file ();*****************/ + + pid = vfork (); + if (pid < 0) + perror_with_name ("vfork"); + + if (pid == 0) + { + /* Run inferior in a separate process group. */ + setpgrp (getpid (), getpid ()); + +/* Not needed on Sun, at least, and loses there + because it clobbers the superior. */ +/*??? signal (SIGQUIT, SIG_DFL); + signal (SIGINT, SIG_DFL); */ + + errno = 0; + ptrace (0); + + execle ("/bin/sh", "sh", "-c", allargs, 0, env); + + fprintf (stderr, "Cannot exec /bin/sh: %s.\n", + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + /*************inferior_died ();****VK**************/ +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +unsigned char +resume (step, signal,status) + int step; + int signal; + char *status; +{ + int pid ; + WAITTYPE w; + + errno = 0; + ptrace (step ? 9 : 7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + pid = wait(&w); + if(pid != inferior_pid) + perror_with_name ("wait"); + + if(WIFEXITED(w)) + { + printf("\nchild exited with retcode = %x \n",WRETCODE(w)); + *status = 'E'; + return((unsigned char) WRETCODE(w)); + } + else if(!WIFSTOPPED(w)) + { + printf("\nchild did terminated with signal = %x \n",WTERMSIG(w)); + *status = 'T'; + return((unsigned char) WTERMSIG(w)); + } + else + { + printf("\nchild stopped with signal = %x \n",WSTOPSIG(w)); + *status = 'S'; + return((unsigned char) WSTOPSIG(w)); + } + +} + + +#ifdef NEW_SUN_PTRACE + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); + if (errno) + perror_with_name ("ptrace"); + /**********debugging begin **********/ + print_some_registers(&inferior_registers); + /**********debugging end **********/ + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); + if (errno) + perror_with_name ("ptrace"); + + bcopy (&inferior_registers, registers, 16 * 4); + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + bcopy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + bcopy (registers, &inferior_registers, 16 * 4); + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + if (errno) + perror_with_name ("ptrace"); + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); + if (errno) + perror_with_name ("ptrace"); +} + +#endif /* not NEW_SUN_PTRACE */ + + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + buffer[i] = ptrace (1, inferior_pid, addr, 0); + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); +} + +/* Copy LEN bytes of data from debugger 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. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + + if (count > 1) + { + buffer[count - 1] + = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +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."); + + fetch_inferior_registers(); + for (i = 0;i<18 ; i ++) + { + QUIT; + errno = 0; + value = read_register(i); + write_register ( i, value); + if (errno == 0) + { + printf (" Succeeded with register %d; value 0x%x (%d).\n", + i, value, value); + } + else + printf (" Failed with register %d.\n", i); + } +} + +void +initialize () +{ + + inferior_pid = 0; + + +} + + +/* Return the contents of register REGNO, + regarding it as an integer. */ + +CORE_ADDR +read_register (regno) + int regno; +{ + /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */ + return *(int *) ®isters[REGISTER_BYTE (regno)]; +} + +/* Store VALUE in the register number REGNO, regarded as an integer. */ + +void +write_register (regno, val) + int regno, val; +{ + /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */ + *(int *) ®isters[REGISTER_BYTE (regno)] = val; + + if (have_inferior_p ()) + store_inferior_registers (regno); +} + + +int +have_inferior_p () +{ + return inferior_pid != 0; +} + +print_some_registers(regs) +int regs[]; +{ + register int i; + for (i = 0; i < 18; i++) { + printf("reg[%d] = %x\n", i, regs[i]); + } +} + +SHAR_EOF +cat << \SHAR_EOF > remote_server.c +/* Main code for remote server for GDB, the GNU Debugger. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "param.h" +#include + +void read_inferior_memory(), fetch_inferior_registers(); +unsigned char resume(); +void kill_inferior(); +void initialize(), try_writing_regs_command(); +int create_inferior(), read_register(); + +extern char registers[]; +int inferior_pid; +extern char **environ; + +/* Descriptor for I/O to remote machine. */ +int remote_desc; +int kiodebug = 0; +int remote_debugging; + +void remote_send (); +void putpkt (); +void getpkt (); +void remote_open(); +void write_ok(); +void write_enn(); +void convert_ascii_to_int(); +void convert_int_to_ascii(); +void prepare_resume_reply(); +void decode_m_packet(); +void decode_M_packet(); + + +main(argc,argv) +int argc; char *argv[]; +{ + char ch,status, own_buf[2000], mem_buf[2000]; + int i=0; + unsigned char signal; + unsigned int mem_addr, len; + + initialize(); + printf("\nwill open serial link\n"); + remote_open("/dev/ttya",0); + + if(argc < 2) + { + printf("Enter name of program to be run with command line args\n"); + gets(own_buf); + inferior_pid = create_inferior(own_buf,environ); + printf("\nProcess %s created; pid = %d\n",own_buf,inferior_pid); + } + else + { + inferior_pid = create_inferior(argv[1],environ); + printf("\nProcess %s created; pid = %d\n",argv[1],inferior_pid); + } + + do { + getpkt(own_buf); + printf("\nPacket received is>:%s\n",own_buf); + i = 0; + ch = own_buf[i++]; + switch (ch) { + case 'h': /**********This is only for tweaking the gdb+ program *******/ + signal = resume(1,0,&status); + prepare_resume_reply(own_buf,status,signal); + break; + /*************end tweak*************************************/ + + case 'g': fetch_inferior_registers(); + convert_int_to_ascii(registers,own_buf,REGISTER_BYTES); + break; + case 'G': convert_ascii_to_int(&own_buf[1],registers,REGISTER_BYTES); + if(store_inferior_registers(-1)==0) + write_ok(own_buf); + else + write_enn(own_buf); + break; + case 'm': decode_m_packet(&own_buf[1],&mem_addr,&len); + read_inferior_memory(mem_addr,mem_buf,len); + convert_int_to_ascii(mem_buf,own_buf,len); + break; + case 'M': decode_M_packet(&own_buf[1],&mem_addr,&len,mem_buf); + if(write_inferior_memory(mem_addr,mem_buf,len)==0) + write_ok(own_buf); + else + write_enn(own_buf); + break; + case 'c': signal = resume(0,0,&status); + printf("\nSignal received is >: %0x \n",signal); + prepare_resume_reply(own_buf,status,signal); + break; + case 's': signal = resume(1,0,&status); + prepare_resume_reply(own_buf,status,signal); + break; + case 'k': kill_inferior(); + sprintf(own_buf,"q"); + putpkt(own_buf); + printf("\nObtained kill request...terminating\n"); + close(remote_desc); + exit(0); + case 't': try_writing_regs_command(); + own_buf[0] = '\0'; + break; + default : printf("\nUnknown option chosen by master\n"); + write_enn(own_buf); + break; + } + + putpkt(own_buf); + } while(1) ; + + close(remote_desc); + /** now get out of here**/ + printf("\nFinished reading data from serial link - Bye!\n"); + exit(0); + +} + +SHAR_EOF +cat << \SHAR_EOF > remote_utils.c +/* Remote utility routines for the remote server for GDB, the GNU debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "param.h" +#include +#include +#include +#include +#include +#include +#include + +extern int remote_desc; +extern int remote_debugging; +extern int kiodebug; + +void remote_open(); +void remote_send(); +void putpkt(); +void getpkt(); + +void write_ok(); +void write_enn(); +void convert_ascii_to_int(); +void convert_int_to_ascii(); +void prepare_resume_reply(); + +/* 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; +{ + struct sgttyb sg; + + remote_debugging = 0; + + remote_desc = open (name, O_RDWR); + if (remote_desc < 0) + printf("\ncould not open remote device\n"); + + ioctl (remote_desc, TIOCGETP, &sg); + sg.sg_flags = RAW; + 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 + perror ("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; +} + +/* Send the command in BUF to the remote machine, + and read the reply into BUF. + Report an error if we get an error reply. */ + +void +remote_send (buf) + char *buf; +{ + putpkt (buf); + getpkt (buf); + + if (buf[0] == 'E') + perror ("Remote failure reply: %s", buf); +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. */ + +void +putpkt (buf) + char *buf; +{ + int i; + unsigned 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. */ + +void +getpkt (buf) + char *buf; +{ + char *bp; + unsigned char csum, c, c1, c2; + extern kiodebug; + + while (1) + { + 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); +} + + +void +write_ok(buf) + char *buf; +{ + buf[0] = 'O'; + buf[1] = 'k'; + buf[2] = '\0'; +} + +void +write_enn(buf) + char *buf; +{ + buf[0] = 'E'; + buf[1] = 'N'; + buf[2] = 'N'; + buf[3] = '\0'; +} + +void +convert_int_to_ascii(from,to,n) +char *from, *to; int n; +{ + int nib ; + char ch; + while( n-- ) + { + ch = *from++; + nib = ((ch & 0xf0) >> 4)& 0x0f; + *to++ = tohex(nib); + nib = ch & 0x0f; + *to++ = tohex(nib); + } + *to++ = 0; +} + + +void +convert_ascii_to_int(from,to,n) +char *from, *to; int n; +{ + int nib1,nib2 ; + while( n-- ) + { + nib1 = fromhex(*from++); + nib2 = fromhex(*from++); + *to++ = (((nib1 & 0x0f)<< 4)& 0xf0) | (nib2 & 0x0f); + } +} + +void +prepare_resume_reply(buf,status,signal) +char *buf ,status; +unsigned char signal; +{ + int nib; + char ch; + + *buf++ = 'S'; + *buf++ = status; + nib = ((signal & 0xf0) >> 4) ; + *buf++ = tohex(nib); + nib = signal & 0x0f; + *buf++ = tohex(nib); + *buf++ = 0; +} + +void +decode_m_packet(from,mem_addr_ptr,len_ptr) +char *from; +unsigned int *mem_addr_ptr, *len_ptr; +{ + int i = 0, j = 0 ; + char ch; + *mem_addr_ptr = *len_ptr = 0; + /************debugging begin************/ + printf("\nIn decode_m_packet"); + /************debugging end************/ + + while((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex(ch) & 0x0f; + } + /************debugging begin************/ + printf("\nFinished mem_addr part"); + /************debugging end************/ + + for(j=0; j < 4; j++) + { + if((ch = from[i++]) == 0) + break; + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex(ch) & 0x0f; + } + /************debugging begin************/ + printf("\nFinished len_ptr part"); + /************debugging end************/ +} + +void +decode_M_packet(from,mem_addr_ptr,len_ptr,to) +char *from, *to; +unsigned int *mem_addr_ptr, *len_ptr; +{ + int i = 0, j = 0 ; + char ch; + *mem_addr_ptr = *len_ptr = 0; + /************debugging begin************/ + printf("\nIn decode_M_packet"); + /************debugging end************/ + + while((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex(ch) & 0x0f; + } + /************debugging begin************/ + printf("\nFinished mem_addr part: memaddr = %x",*mem_addr_ptr); + /************debugging end************/ + + while((ch = from[i++]) != ':') + { + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex(ch) & 0x0f; + } + /************debugging begin************/ + printf("\nFinished len_ptr part: len = %d",*len_ptr); + /************debugging end************/ + + convert_ascii_to_int(&from[i++],to,*len_ptr); + + /************debugging begin************/ + printf("\nmembuf : %x",*(int *)to); + /************debugging end************/ +} + +SHAR_EOF +# End of shell archive +exit 0 diff --git a/gdb/remote-nindy.c b/gdb/remote-nindy.c new file mode 100644 index 00000000000..5724f423977 --- /dev/null +++ b/gdb/remote-nindy.c @@ -0,0 +1,962 @@ +/* Memory-access and commands for remote NINDY process, for GDB. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Contributed by Intel Corporation. Modified from remote.c by Chris Benenati. + +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! +*/ + +/* +Except for the data cache routines, this file bears little resemblence +to remote.c. A new (although similar) protocol has been specified, and +portions of the code are entirely dependent on having an i80960 with a +NINDY ROM monitor at the other end of the line. +*/ + +/***************************************************************************** + * + * REMOTE COMMUNICATION PROTOCOL BETWEEN GDB960 AND THE NINDY ROM MONITOR. + * + * + * MODES OF OPERATION + * ----- -- --------- + * + * As far as NINDY is concerned, GDB is always in one of two modes: command + * mode or passthrough mode. + * + * In command mode (the default) pre-defined packets containing requests + * are sent by GDB to NINDY. NINDY never talks except in reponse to a request. + * + * Once the the user program is started, GDB enters passthrough mode, to give + * the user program access to the terminal. GDB remains in this mode until + * NINDY indicates that the program has stopped. + * + * + * PASSTHROUGH MODE + * ----------- ---- + * + * GDB writes all input received from the keyboard directly to NINDY, and writes + * all characters received from NINDY directly to the monitor. + * + * Keyboard input is neither buffered nor echoed to the monitor. + * + * GDB remains in passthrough mode until NINDY sends a single ^P character, + * to indicate that the user process has stopped. + * + * Note: + * GDB assumes NINDY performs a 'flushreg' when the user program stops. + * + * + * COMMAND MODE + * ------- ---- + * + * All info (except for message ack and nak) is transferred between gdb + * and the remote processor in messages of the following format: + * + * # + * + * where + * # is a literal character + * + * ASCII information; all numeric information is in the + * form of hex digits ('0'-'9' and lowercase 'a'-'f'). + * + * + * is a pair of ASCII hex digits representing an 8-bit + * checksum formed by adding together each of the + * characters in . + * + * The receiver of a message always sends a single character to the sender + * to indicate that the checksum was good ('+') or bad ('-'); the sender + * re-transmits the entire message over until a '+' is received. + * + * In response to a command NINDY always sends back either data or + * a result code of the form "Xnn", where "nn" are hex digits and "X00" + * means no errors. (Exceptions: the "s" and "c" commands don't respond.) + * + * SEE THE HEADER OF THE FILE "gdb.c" IN THE NINDY MONITOR SOURCE CODE FOR A + * FULL DESCRIPTION OF LEGAL COMMANDS. + * + * SEE THE FILE "stop.h" IN THE NINDY MONITOR SOURCE CODE FOR A LIST + * OF STOP CODES. + * + ******************************************************************************/ + +#include +#include +#include +#include + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "bfd.h" +#include "ieee-float.h" + +#include "wait.h" +#include +#include +#include +#include "nindy-share/ttycntl.h" +#include "nindy-share/demux.h" +#include "nindy-share/env.h" +#include "nindy-share/stop.h" + +extern int unlink(); +extern char *getenv(); +extern char *mktemp(); + +extern char *coffstrip(); +extern void add_syms_addr_command (); +extern value call_function_by_hand (); +extern void generic_mourn_inferior (); + +extern struct target_ops nindy_ops; +extern jmp_buf to_top_level; +extern FILE *instream; +extern struct ext_format ext_format_i960[]; /* i960-tdep.c */ + +extern char ninStopWhy (); + +int nindy_initial_brk; /* nonzero if want to send an initial BREAK to nindy */ +int nindy_old_protocol; /* nonzero if want to use old protocol */ +char *nindy_ttyname; /* name of tty to talk to nindy on, or null */ + +#define DLE '\020' /* Character NINDY sends to indicate user program has + * halted. */ +#define TRUE 1 +#define FALSE 0 + +int nindy_fd = 0; /* Descriptor for I/O to NINDY */ +static int have_regs = 0; /* 1 iff regs read since i960 last halted */ +static int regs_changed = 0; /* 1 iff regs were modified since last read */ + +extern char *exists(); +static void dcache_flush (), dcache_poke (), dcache_init(); +static int dcache_fetch (); + +/* FIXME, we can probably use the normal terminal_inferior stuff here. + We have to do terminal_inferior and then set up the passthrough + settings initially. Thereafter, terminal_ours and terminal_inferior + will automatically swap the settings around for us. */ + +/* Restore TTY to normal operation */ + +static TTY_STRUCT orig_tty; /* TTY attributes before entering passthrough */ + +static void +restore_tty() +{ + ioctl( 0, TIOCSETN, &orig_tty ); +} + + +/* Recover from ^Z or ^C while remote process is running */ + +static void (*old_ctrlc)(); /* Signal handlers before entering passthrough */ + +#ifdef SIGTSTP +static void (*old_ctrlz)(); +#endif + +static +#ifdef USG +void +#endif +cleanup() +{ + restore_tty(); + signal(SIGINT, old_ctrlc); +#ifdef SIGTSTP + signal(SIGTSTP, old_ctrlz); +#endif + error("\n\nYou may need to reset the 80960 and/or reload your program.\n"); +} + +/* Clean up anything that needs cleaning when losing control. */ + +static char *savename; + +static void +nindy_close (quitting) + int quitting; +{ + if (nindy_fd) + close (nindy_fd); + nindy_fd = 0; + + if (savename) + free (savename); + savename = 0; +} + +/* Open a connection to a remote debugger. + FIXME, there should be a way to specify the various options that are + now specified with gdb command-line options. (baud_rate, old_protocol, + and initial_brk) */ +void +nindy_open (name, from_tty) + char *name; /* "/dev/ttyXX", "ttyXX", or "XX": tty to be opened */ + int from_tty; +{ + + if (!name) + error_no_arg ("serial port device name"); + + nindy_close (0); + + have_regs = regs_changed = 0; + dcache_init(); + + /* Allow user to interrupt the following -- we could hang if + * there's no NINDY at the other end of the remote tty. + */ + immediate_quit++; + nindy_fd = ninConnect( name, baud_rate? baud_rate: "9600", + nindy_initial_brk, !from_tty, nindy_old_protocol ); + immediate_quit--; + + if ( nindy_fd < 0 ){ + nindy_fd = 0; + error( "Can't open tty '%s'", name ); + } + + savename = savestring (name, strlen (name)); + push_target (&nindy_ops); + target_fetch_registers(-1); +} + +/* User-initiated quit of nindy operations. */ + +static void +nindy_detach (name, from_tty) + char *name; + int from_tty; +{ + dont_repeat (); + if (name) + error ("Too many arguments"); + pop_target (); +} + +static void +nindy_files_info () +{ + printf("\tAttached to %s at %s bps%s%s.\n", savename, + baud_rate? baud_rate: "9600", + nindy_old_protocol? " in old protocol": "", + nindy_initial_brk? " with initial break": ""); +} + +/****************************************************************************** + * remote_load: + * Download an object file to the remote system by invoking the "comm960" + * utility. We look for "comm960" in $G960BIN, $G960BASE/bin, and + * DEFAULT_BASE/bin/HOST/bin where + * DEFAULT_BASE is defined in env.h, and + * HOST must be defined on the compiler invocation line. + ******************************************************************************/ + +static void +nindy_load( filename, from_tty ) + char *filename; + int from_tty; +{ + char *tmpfile; + struct cleanup *old_chain; + char *scratch_pathname; + int scratch_chan; + + if (!filename) + filename = get_exec_file (1); + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &scratch_pathname); + if (scratch_chan < 0) + perror_with_name (filename); + close (scratch_chan); /* Slightly wasteful FIXME */ + + have_regs = regs_changed = 0; + mark_breakpoints_out(); + inferior_pid = 0; + dcache_flush(); + + tmpfile = coffstrip(scratch_pathname); + if ( tmpfile ){ + old_chain = make_cleanup(unlink,tmpfile); + immediate_quit++; + ninDownload( tmpfile, !from_tty ); +/* FIXME, don't we want this merged in here? */ + immediate_quit--; + do_cleanups (old_chain); + } +} + + + +/* Return the number of characters in the buffer before the first DLE character. + */ + +static +int +non_dle( buf, n ) + char *buf; /* Character buffer; NOT '\0'-terminated */ + int n; /* Number of characters in buffer */ +{ + int i; + + for ( i = 0; i < n; i++ ){ + if ( buf[i] == DLE ){ + break; + } + } + return i; +} + +/* Tell the remote machine to resume. */ + +void +nindy_resume (step, siggnal) + int step, siggnal; +{ + if (siggnal != 0 && siggnal != stop_signal) + error ("Can't send signals to remote NINDY targets."); + + dcache_flush(); + if ( regs_changed ){ + nindy_store_registers (); + regs_changed = 0; + } + have_regs = 0; + ninGo( step ); +} + +/* Wait until the remote machine stops. While waiting, operate in passthrough + * mode; i.e., pass everything NINDY sends to stdout, and everything from + * stdin to NINDY. + * + * Return to caller, storing status in 'status' just as `wait' would. + */ + +void +nindy_wait( status ) + WAITTYPE *status; +{ + DEMUX_DECL; /* OS-dependent data needed by DEMUX... macros */ + char buf[500]; /* FIXME, what is "500" here? */ + int i, n; + unsigned char stop_exit; + unsigned char stop_code; + TTY_STRUCT tty; + long ip_value, fp_value, sp_value; /* Reg values from stop */ + + + WSETEXIT( (*status), 0 ); + + /* OPERATE IN PASSTHROUGH MODE UNTIL NINDY SENDS A DLE CHARACTER */ + + /* Save current tty attributes, set up signals to restore them. + */ + ioctl( 0, TIOCGETP, &orig_tty ); + old_ctrlc = signal( SIGINT, cleanup ); +#ifdef SIGTSTP + old_ctrlz = signal( SIGTSTP, cleanup ); +#endif + + /* Pass input from keyboard to NINDY as it arrives. + * NINDY will interpret and perform echo. + */ + tty = orig_tty; + TTY_NINDYTERM( tty ); + ioctl( 0, TIOCSETN, &tty ); + + while ( 1 ){ + /* Go to sleep until there's something for us on either + * the remote port or stdin. + */ + + DEMUX_WAIT( nindy_fd ); + + /* Pass input through to correct place */ + + n = DEMUX_READ( 0, buf, sizeof(buf) ); + if ( n ){ /* Input on stdin */ + write( nindy_fd, buf, n ); + } + + n = DEMUX_READ( nindy_fd, buf, sizeof(buf) ); + if ( n ){ /* Input on remote */ + /* Write out any characters in buffer preceding DLE */ + i = non_dle( buf, n ); + if ( i > 0 ){ + write( 1, buf, i ); + } + + if ( i != n ){ + /* There *was* a DLE in the buffer */ + stop_exit = ninStopWhy( &stop_code, + &ip_value, &fp_value, &sp_value); + if ( !stop_exit && (stop_code==STOP_SRQ) ){ + immediate_quit++; + ninSrq(); + immediate_quit--; + } else { + /* Get out of loop */ + supply_register (IP_REGNUM, &ip_value); + supply_register (FP_REGNUM, &fp_value); + supply_register (SP_REGNUM, &sp_value); + break; + } + } + } + } + + signal( SIGINT, old_ctrlc ); +#ifdef SIGTSTP + signal( SIGTSTP, old_ctrlz ); +#endif + restore_tty(); + + if ( stop_exit ){ /* User program exited */ + WSETEXIT( (*status), stop_code ); + } else { /* Fault or trace */ + switch (stop_code){ + case STOP_GDB_BPT: + case TRACE_STEP: + /* Make it look like a VAX trace trap */ + stop_code = SIGTRAP; + break; + default: + /* The target is not running Unix, and its + faults/traces do not map nicely into Unix signals. + Make sure they do not get confused with Unix signals + by numbering them with values higher than the highest + legal Unix signal. code in i960_print_fault(), + called via PRINT_RANDOM_SIGNAL, will interpret the + value. */ + stop_code += NSIG; + break; + } + WSETSTOP( (*status), stop_code ); + } +} + +/* Read the remote registers into the block REGS. */ + +/* This is the block that ninRegsGet and ninRegsPut handles. */ +struct nindy_regs { + char local_regs[16 * 4]; + char global_regs[16 * 4]; + char pcw_acw[2 * 4]; + char ip[4]; + char tcw[4]; + char fp_as_double[4 * 8]; +}; + +static int +nindy_fetch_registers(regno) + int regno; +{ + struct nindy_regs nindy_regs; + int regnum, inv; + double dub; + + immediate_quit++; + ninRegsGet( (char *) &nindy_regs ); + immediate_quit--; + + bcopy (nindy_regs.local_regs, ®isters[REGISTER_BYTE (R0_REGNUM)], 16*4); + bcopy (nindy_regs.global_regs, ®isters[REGISTER_BYTE (G0_REGNUM)], 16*4); + bcopy (nindy_regs.pcw_acw, ®isters[REGISTER_BYTE (PCW_REGNUM)], 2*4); + bcopy (nindy_regs.ip, ®isters[REGISTER_BYTE (IP_REGNUM)], 1*4); + bcopy (nindy_regs.tcw, ®isters[REGISTER_BYTE (TCW_REGNUM)], 1*4); + for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) { + dub = unpack_double (builtin_type_double, + &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)], + &inv); + /* dub now in host byte order */ + double_to_ieee_extended (ext_format_i960, &dub, + ®isters[REGISTER_BYTE (regnum)]); + } + + registers_fetched (); + return 0; +} + +static void +nindy_prepare_to_store() +{ + nindy_fetch_registers(-1); +} + +static int +nindy_store_registers(regno) + int regno; +{ + struct nindy_regs nindy_regs; + int regnum, inv; + double dub; + + bcopy (®isters[REGISTER_BYTE (R0_REGNUM)], nindy_regs.local_regs, 16*4); + bcopy (®isters[REGISTER_BYTE (G0_REGNUM)], nindy_regs.global_regs, 16*4); + bcopy (®isters[REGISTER_BYTE (PCW_REGNUM)], nindy_regs.pcw_acw, 2*4); + bcopy (®isters[REGISTER_BYTE (IP_REGNUM)], nindy_regs.ip, 1*4); + bcopy (®isters[REGISTER_BYTE (TCW_REGNUM)], nindy_regs.tcw, 1*4); + /* Float regs. Only works on IEEE_FLOAT hosts. */ + for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) { + ieee_extended_to_double (ext_format_i960, + ®isters[REGISTER_BYTE (regnum)], &dub); + /* dub now in host byte order */ + /* FIXME-someday, the arguments to unpack_double are backward. + It expects a target double and returns a host; we pass the opposite. + This mostly works but not quite. */ + dub = unpack_double (builtin_type_double, &dub, &inv); + /* dub now in target byte order */ + bcopy ((char *)&dub, &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)], + 8); + } + + immediate_quit++; + ninRegsPut( (char *) &nindy_regs ); + immediate_quit--; + return 0; +} + +/* Read a word from remote address ADDR and return it. + * This goes through the data cache. + */ +int +nindy_fetch_word (addr) + CORE_ADDR addr; +{ + return dcache_fetch (addr); +} + +/* Write a word WORD into remote address ADDR. + This goes through the data cache. */ + +void +nindy_store_word (addr, word) + CORE_ADDR addr; + int word; +{ + dcache_poke (addr, word); +} + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. Copy to inferior if + WRITE is nonzero. Returns the length copied. + + This is stolen almost directly from infptrace.c's child_xfer_memory, + which also deals with a word-oriented memory interface. Sometime, + FIXME, rewrite this to not use the word-oriented routines. */ + +int +nindy_xfer_inferior_memory(memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int)sizeof (int)) { + /* Need part of initial word -- fetch it. */ + buffer[0] = nindy_fetch_word (addr); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = nindy_fetch_word (addr + (count - 1) * sizeof (int)); + } + + /* 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; + nindy_store_word (addr, buffer[i]); + if (errno) + return 0; + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + buffer[i] = nindy_fetch_word (addr); + if (errno) + return 0; + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + } + return len; +} + +/* 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. + */ +static +struct dcache_block * +dcache_hit (addr) + unsigned int 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. */ +static +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 or keep it on the valid list, + and return its address. The caller should store into the block + the address and data that it describes, then remque it from the + free list and insert it into the valid list. This procedure + prevents errors from creeping in if a ninMemGet is interrupted + (which used to put garbage blocks in the valid list...). */ +static +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 and put + it on the free list. */ + db = dcache_valid.last; + remque (db); + insque (db, &dcache_free); + } + + 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. */ +static +int +dcache_fetch (addr) + CORE_ADDR addr; +{ + register struct dcache_block *db; + + db = dcache_hit (addr); + if (db == 0) + { + db = dcache_alloc (); + immediate_quit++; + ninMemGet(addr & ~0xf, (unsigned char *)db->data, 16); + immediate_quit--; + db->addr = addr & ~0xf; + remque (db); /* Off the free list */ + insque (db, &dcache_valid); /* On the valid list */ + } + return (dcache_value (db, addr)); +} + +/* Write the word at ADDR both in the data cache and in the remote machine. */ +static void +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 (); + immediate_quit++; + ninMemGet(addr & ~0xf, (unsigned char *)db->data, 16); + immediate_quit--; + db->addr = addr & ~0xf; + remque (db); /* Off the free list */ + insque (db, &dcache_valid); /* On the valid list */ + } + + /* Modify the word in the cache. */ + db->data[(addr>>2)&3] = data; + + /* Send the changed word. */ + immediate_quit++; + ninMemPut(addr, (unsigned char *)&data, 4); + immediate_quit--; +} + +/* The cache itself. */ +struct dcache_block the_cache[DCACHE_SIZE]; + +/* Initialize the data cache. */ +static void +dcache_init () +{ + register i; + register struct dcache_block *db; + + db = the_cache; + dcache_free.next = dcache_free.last = &dcache_free; + dcache_valid.next = dcache_valid.last = &dcache_valid; + for (i=0;i +#include +#include +#include +#include +#include +#include +#include +#define free bogon_free /* Sun claims "int free()" not void */ +#include +#undef free +#include /* UTek's doesn't #incl this */ +#include +#include +#include "xdr_ptrace.h" +#include "xdr_ld.h" +#include "xdr_rdb.h" +#include "dbgRpcLib.h" + +/* get rid of value.h if possible */ +#include +#include + +extern value call_function_by_hand (); +extern void symbol_file_command (); +extern void add_syms_addr_command (); +extern int stop_soon_quietly; /* for wait_for_inferior */ + +static int net_ptrace_clnt_call (); /* Forward decl */ +static enum clnt_stat net_clnt_call (); /* Forward decl */ +extern struct target_ops vx_ops, vx_run_ops; /* Forward declaration */ + +/* Saved name of target host and called function for "info files". + Both malloc'd. */ + +static char *vx_host; +static char *vx_running; /* Called function */ + +/* Nonzero means target that is being debugged remotely has a floating + point processor. */ + +static int target_has_fp; + +/* Default error message when the network is forking up. */ + +static const char rpcerr[] = "network target debugging: rpc error"; + +CLIENT *pClient; /* client used in net debugging */ +static int ptraceSock = RPC_ANYSOCK; + +enum clnt_stat net_clnt_call(); +static void parse_args (); + +static struct timeval rpcTimeout = { 10, 0 }; + +static char *skip_white_space (); +static char *find_white_space (); + +/* Tell the VxWorks target system to download a file. + The load addresses of the text, data, and bss segments are + stored in pTextAddr, pDataAddr, and *pBssAddr (respectively). + Returns 0 for success, -1 for failure. */ + +static int +net_load (filename, pTextAddr, pDataAddr, pBssAddr) + char *filename; + CORE_ADDR *pTextAddr; + CORE_ADDR *pDataAddr; + CORE_ADDR *pBssAddr; + { + enum clnt_stat status; + struct ldfile ldstruct; + struct timeval load_timeout; + + bzero ((char *) &ldstruct, sizeof (ldstruct)); + + /* We invoke clnt_call () here directly, instead of through + net_clnt_call (), because we need to set a large timeout value. + The load on the target side can take quite a while, easily + more than 10 seconds. The user can kill this call by typing + CTRL-C if there really is a problem with the load. + + Do not change the tv_sec value without checking -- select() imposes + a limit of 10**8 on it for no good reason that I can see... */ + + load_timeout.tv_sec = 99999999; /* A large number, effectively inf. */ + load_timeout.tv_usec = 0; + + status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile, + &ldstruct, load_timeout); + + if (status == RPC_SUCCESS) + { + if (*ldstruct.name == NULL) /* load failed on VxWorks side */ + return -1; + *pTextAddr = ldstruct.txt_addr; + *pDataAddr = ldstruct.data_addr; + *pBssAddr = ldstruct.bss_addr; + return 0; + } + else + return -1; + } + +/* returns 0 if successful, errno if RPC failed or VxWorks complains. */ + +static int +net_break (addr, procnum) + int addr; + u_long procnum; + { + enum clnt_stat status; + int break_status; + Rptrace ptrace_in; /* XXX This is stupid. It doesn't need to be a ptrace + structure. How about something smaller? */ + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + break_status = 0; + + ptrace_in.addr = addr; + ptrace_in.pid = inferior_pid; + + status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int, + &break_status); + + if (status != RPC_SUCCESS) + return errno; + + if (break_status == -1) + return ENOMEM; + return break_status; /* probably (FIXME) zero */ + } + +/* returns 0 if successful, errno otherwise */ + +int +vx_insert_breakpoint (addr) + int addr; + { + return net_break (addr, VX_BREAK_ADD); + } + +/* returns 0 if successful, errno otherwise */ + +int +vx_remove_breakpoint (addr) + int addr; + { + return net_break (addr, VX_BREAK_DELETE); + } + +/* Call a function on the VxWorks target system. + ARGS is a vector of values of arguments (NARGS of them). + FUNCTION is a value, the function to be called. + Returns a struct value * representing what the function returned. + May fail to return, if a breakpoint or signal is hit + during the execution of the function. */ + +#ifdef FIXME +/* FIXME, function calls are really fried. GO back to manual method. */ +value +vx_call_function (function, nargs, args) + value function; + int nargs; + value *args; +{ + register CORE_ADDR sp; + register int i; + CORE_ADDR start_sp; + static REGISTER_TYPE dummy[] = CALL_DUMMY; + REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)]; + CORE_ADDR old_sp; + struct type *value_type; + unsigned char struct_return; + CORE_ADDR struct_addr; + struct inferior_status inf_status; + struct cleanup *old_chain; + CORE_ADDR funaddr; + int using_gcc; + + save_inferior_status (&inf_status, 1); + old_chain = make_cleanup (restore_inferior_status, &inf_status); + + /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers + (and POP_FRAME for restoring them). (At least on most machines) + they are saved on the stack in the inferior. */ + PUSH_DUMMY_FRAME; + + old_sp = sp = read_register (SP_REGNUM); + +#if 1 INNER_THAN 2 /* Stack grows down */ + sp -= sizeof dummy; + start_sp = sp; +#else /* Stack grows up */ + start_sp = sp; + sp += sizeof dummy; +#endif + + funaddr = find_function_addr (function, &value_type); + + { + struct block *b = block_for_pc (funaddr); + /* If compiled without -g, assume GCC. */ + using_gcc = b == NULL || BLOCK_GCC_COMPILED (b); + } + + /* Are we returning a value using a structure return or a normal + value return? */ + + struct_return = using_struct_return (function, funaddr, value_type, + using_gcc); + + /* Create a call sequence customized for this function + and the number of arguments for it. */ + bcopy (dummy, dummy1, sizeof dummy); + FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args, + value_type, using_gcc); + +#if CALL_DUMMY_LOCATION == ON_STACK + write_memory (start_sp, dummy1, sizeof dummy); + +#else /* Not on stack. */ +#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END + /* Convex Unix prohibits executing in the stack segment. */ + /* Hope there is empty room at the top of the text segment. */ + { + static checked = 0; + if (!checked) + for (start_sp = text_end - sizeof dummy; start_sp < text_end; ++start_sp) + if (read_memory_integer (start_sp, 1) != 0) + error ("text segment full -- no place to put call"); + checked = 1; + sp = old_sp; + start_sp = text_end - sizeof dummy; + write_memory (start_sp, dummy1, sizeof dummy); + } +#else /* After text_end. */ + { + int errcode; + sp = old_sp; + start_sp = text_end; + errcode = target_write_memory (start_sp, dummy1, sizeof dummy); + if (errcode != 0) + error ("Cannot write text segment -- call_function failed"); + } +#endif /* After text_end. */ +#endif /* Not on stack. */ + +#ifdef STACK_ALIGN + /* If stack grows down, we must leave a hole at the top. */ + { + int len = 0; + + /* Reserve space for the return structure to be written on the + stack, if necessary */ + + if (struct_return) + len += TYPE_LENGTH (value_type); + + for (i = nargs - 1; i >= 0; i--) + len += TYPE_LENGTH (VALUE_TYPE (value_arg_coerce (args[i]))); +#ifdef CALL_DUMMY_STACK_ADJUST + len += CALL_DUMMY_STACK_ADJUST; +#endif +#if 1 INNER_THAN 2 + sp -= STACK_ALIGN (len) - len; +#else + sp += STACK_ALIGN (len) - len; +#endif + } +#endif /* STACK_ALIGN */ + + /* Reserve space for the return structure to be written on the + stack, if necessary */ + + if (struct_return) + { +#if 1 INNER_THAN 2 + sp -= TYPE_LENGTH (value_type); + struct_addr = sp; +#else + struct_addr = sp; + sp += TYPE_LENGTH (value_type); +#endif + } + +#if defined (REG_STRUCT_HAS_ADDR) + { + /* This is a machine like the sparc, where we need to pass a pointer + to the structure, not the structure itself. */ + if (REG_STRUCT_HAS_ADDR (using_gcc)) + for (i = nargs - 1; i >= 0; i--) + if (TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_STRUCT) + { + CORE_ADDR addr; +#if !(1 INNER_THAN 2) + /* The stack grows up, so the address of the thing we push + is the stack pointer before we push it. */ + addr = sp; +#endif + /* Push the structure. */ + sp = value_push (sp, args[i]); +#if 1 INNER_THAN 2 + /* The stack grows down, so the address of the thing we push + is the stack pointer after we push it. */ + addr = sp; +#endif + /* The value we're going to pass is the address of the thing + we just pushed. */ + args[i] = value_from_long (builtin_type_long, (LONGEST) addr); + } + } +#endif /* REG_STRUCT_HAS_ADDR. */ + +#ifdef PUSH_ARGUMENTS + PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr); +#else /* !PUSH_ARGUMENTS */ + for (i = nargs - 1; i >= 0; i--) + sp = value_arg_push (sp, args[i]); +#endif /* !PUSH_ARGUMENTS */ + +#ifdef CALL_DUMMY_STACK_ADJUST +#if 1 INNER_THAN 2 + sp -= CALL_DUMMY_STACK_ADJUST; +#else + sp += CALL_DUMMY_STACK_ADJUST; +#endif +#endif /* CALL_DUMMY_STACK_ADJUST */ + + /* Store the address at which the structure is supposed to be + written. Note that this (and the code which reserved the space + above) assumes that gcc was used to compile this function. Since + it doesn't cost us anything but space and if the function is pcc + it will ignore this value, we will make that assumption. + + Also note that on some machines (like the sparc) pcc uses a + convention like gcc's. */ + + if (struct_return) + STORE_STRUCT_RETURN (struct_addr, sp); + + /* Write the stack pointer. This is here because the statements above + might fool with it. On SPARC, this write also stores the register + window into the right place in the new stack frame, which otherwise + wouldn't happen. (See write_inferior_registers in sparc-xdep.c.) */ + write_register (SP_REGNUM, sp); + + /* Figure out the value returned by the function. */ + { + char retbuf[REGISTER_BYTES]; + + /* Execute the stack dummy routine, calling FUNCTION. + When it is done, discard the empty frame + after storing the contents of all regs into retbuf. */ + run_stack_dummy (start_sp + CALL_DUMMY_START_OFFSET, retbuf); + + do_cleanups (old_chain); + + return value_being_returned (value_type, retbuf, struct_return); + } +} +/* should return a value of some sort */ + +value +vx_call_function (funcAddr, nargs, args, valueType) + char *funcAddr; + int nargs; + value *args; + struct type * valueType; +{ + int i; + func_call funcInfo; + arg_value *argValue; + enum clnt_stat status; + register int len; + arg_value funcReturn; + value gdbValue; + + argValue = (arg_value *) xmalloc (nargs * sizeof (arg_value)); + + bzero (argValue, nargs * sizeof (arg_value)); + bzero (&funcReturn, sizeof (funcReturn)); + + for (i = nargs - 1; i >= 0; i--) + { + len = TYPE_LENGTH (VALUE_TYPE (args [i])); + + switch (TYPE_CODE (VALUE_TYPE (args[i]))) + { + /* XXX put other types here. Where's CHAR, etc??? */ + + case TYPE_CODE_FLT: + argValue[i].type = T_FLOAT; + break; + case TYPE_CODE_INT: + case TYPE_CODE_PTR: + case TYPE_CODE_ENUM: + case TYPE_CODE_FUNC: + argValue[i].type = T_INT; + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_ARRAY: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_VOID: + case TYPE_CODE_SET: + case TYPE_CODE_RANGE: + case TYPE_CODE_PASCAL_ARRAY: + case TYPE_CODE_MEMBER: /* C++ */ + case TYPE_CODE_METHOD: /* C++ */ + case TYPE_CODE_REF: /* C++ */ + default: + error ("No corresponding VxWorks type for %d. CHECK IT OUT!!!\n", + TYPE_CODE(VALUE_TYPE(args[i]))); + } /* switch */ + if (TYPE_CODE(VALUE_TYPE(args[i])) == TYPE_CODE_FUNC) + argValue[i].arg_value_u.v_int = VALUE_ADDRESS(args[i]); + else + bcopy (VALUE_CONTENTS (args[i]), (char *) &argValue[i].arg_value_u, + len); + } + + /* XXX what should the type of this function addr be? + * XXX Both in gdb and vxWorks + */ + funcInfo.func_addr = (int) funcAddr; + funcInfo.args.args_len = nargs; + funcInfo.args.args_val = argValue; + + status = net_clnt_call (VX_CALL_FUNC, xdr_func_call, (char *) &funcInfo, + xdr_arg_value, &funcReturn); + + free ((char *) argValue); + + if (status == RPC_SUCCESS) + { + /* XXX this assumes that vxWorks ALWAYS returns an int, and that + * XXX gdb isn't expecting anything more + */ + + /******************* + if (funcReturn.type == T_UNKNOWN) + return YYYXXX...; + *******************/ + gdbValue = allocate_value (valueType); + bcopy (&funcReturn.arg_value_u.v_int, VALUE_CONTENTS (gdbValue), + sizeof (int)); + return gdbValue; + } + else + error (rpcerr); + } +#endif /* FIXME */ + +/* Start an inferior process and sets inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. + Returns process id. Errors reported with error(). + On VxWorks, we ignore exec_file. */ + +void +vx_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + enum clnt_stat status; + arg_array passArgs; + TASK_START taskStart; + + bzero ((char *) &passArgs, sizeof (passArgs)); + bzero ((char *) &taskStart, sizeof (taskStart)); + + /* parse arguments, put them in passArgs */ + + parse_args (args, &passArgs); + + if (passArgs.arg_array_len == 0) + error ("You must specify a function name to run, and arguments if any"); + + status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs, + xdr_TASK_START, &taskStart); + + if ((status != RPC_SUCCESS) || (taskStart.status == -1)) + error ("Can't create process on remote target machine"); + + /* Save the name of the running function */ + vx_running = savestring (passArgs.arg_array_val[0], + strlen (passArgs.arg_array_val[0])); + +#ifdef CREATE_INFERIOR_HOOK + CREATE_INFERIOR_HOOK (pid); +#endif + + push_target (&vx_run_ops); + inferior_pid = taskStart.pid; + +#if defined (START_INFERIOR_HOOK) + START_INFERIOR_HOOK (); +#endif + + /* We will get a trace trap after one instruction. + Insert breakpoints and continue. */ + + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* remote_start(args); */ + /* trap_expected = 0; */ + stop_soon_quietly = 1; + wait_for_inferior (); /* Get the task spawn event */ + stop_soon_quietly = 0; + + /* insert_step_breakpoint (); FIXME, do we need this? */ + proceed(-1, -1, 0); +} + +/* Fill ARGSTRUCT in argc/argv form with the arguments from the + argument string ARGSTRING. */ + +static void +parse_args (arg_string, arg_struct) + register char *arg_string; + arg_array *arg_struct; +{ + register int arg_count = 0; /* number of arguments */ + register int arg_index = 0; + register char *p0; + + bzero ((char *) arg_struct, sizeof (arg_array)); + + /* first count how many arguments there are */ + + p0 = arg_string; + while (*p0 != '\0') + { + if (*(p0 = skip_white_space (p0)) == '\0') + break; + p0 = find_white_space (p0); + arg_count++; + } + + arg_struct->arg_array_len = arg_count; + arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1) + * sizeof (char *)); + + /* now copy argument strings into arg_struct. */ + + while (*(arg_string = skip_white_space (arg_string))) + { + p0 = find_white_space (arg_string); + arg_struct->arg_array_val[arg_index++] = savestring (arg_string, + p0 - arg_string); + arg_string = p0; + } + + arg_struct->arg_array_val[arg_count] = NULL; +} + +/* Advance a string pointer across whitespace and return a pointer + to the first non-white character. */ + +static char * +skip_white_space (p) + register char *p; +{ + while (*p == ' ' || *p == '\t') + p++; + return p; +} + +/* Search for the first unquoted whitespace character in a string. + Returns a pointer to the character, or to the null terminator + if no whitespace is found. */ + +static char * +find_white_space (p) + register char *p; +{ + register int c; + + while ((c = *p) != ' ' && c != '\t' && c) + { + if (c == '\'' || c == '"') + { + while (*++p != c && *p) + { + if (*p == '\\') + p++; + } + if (!*p) + break; + } + p++; + } + return p; +} + +/* Poll the VxWorks target system for an event related + to the debugged task. + Returns -1 if remote wait failed, task status otherwise. */ + +int +net_wait (pEvent) + RDB_EVENT *pEvent; +{ + int pid; + enum clnt_stat status; + + bzero ((char *) pEvent, sizeof (RDB_EVENT)); + + pid = inferior_pid; + status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, pEvent); + + return (status == RPC_SUCCESS)? pEvent->status: -1; +} + +/* Suspend the remote task. + Returns -1 if suspend fails on target system, 0 otherwise. */ + +int +net_quit () +{ + int pid; + int quit_status; + enum clnt_stat status; + + quit_status = 0; + + /* don't let rdbTask suspend itself by passing a pid of 0 */ + + if ((pid = inferior_pid) == 0) + return -1; + + status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int, + &quit_status); + + return (status == RPC_SUCCESS)? quit_status: -1; +} + +/* Read a register or registers from the remote system. */ + +int +vx_read_register (regno) + int regno; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + + /* FIXME, eventually only get the ones we need. */ + registers_fetched (); + + ptrace_in.pid = inferior_pid; + ptrace_out.info.more_data = (caddr_t) &inferior_registers; + status = net_ptrace_clnt_call (PTRACE_GETREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + +#ifdef I80960 + + bcopy ((char *) inferior_registers.r_lreg, + ®isters[REGISTER_BYTE (R0_REGNUM)], 16 * sizeof (int)); + bcopy ((char *) inferior_registers.r_greg, + ®isters[REGISTER_BYTE (G0_REGNUM)], 16 * sizeof (int)); + + /* Don't assume that a location in registers[] is properly aligned. */ + + bcopy ((char *) &inferior_registers.r_pcw, + ®isters[REGISTER_BYTE (PCW_REGNUM)], sizeof (int)); + bcopy ((char *) &inferior_registers.r_acw, + ®isters[REGISTER_BYTE (ACW_REGNUM)], sizeof (int)); + bcopy ((char *) &inferior_registers.r_lreg[2], /* r2 (RIP) -> IP */ + ®isters[REGISTER_BYTE (IP_REGNUM)], sizeof (int)); + bcopy ((char *) &inferior_registers.r_tcw, + ®isters[REGISTER_BYTE (TCW_REGNUM)], sizeof (int)); + + /* If the target has floating point registers, fetch them. + Otherwise, zero the floating point register values in + registers[] for good measure, even though we might not + need to. */ + + if (target_has_fp) + { + ptrace_in.pid = inferior_pid; + ptrace_out.info.more_data = (caddr_t) &inferior_fp_registers; + status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + REGISTER_RAW_SIZE (FP0_REGNUM) * 4); + } + else + { + bzero ((char *) ®isters[REGISTER_BYTE (FP0_REGNUM)], + REGISTER_RAW_SIZE (FP0_REGNUM) * 4); + } + +#else /* not 960, thus must be 68000: FIXME! */ + + bcopy (&inferior_registers, registers, 16 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + + if (target_has_fp) + { + ptrace_in.pid = inferior_pid; + ptrace_out.info.more_data = (caddr_t) &inferior_fp_registers; + status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); + bcopy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + } + else + { + bzero (®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); + bzero (®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + } +#endif /* various architectures */ + + return 0; +} + +/* Prepare to store registers. Since we will store all of them, + read out their current values now. */ + +void +vx_prepare_to_store () +{ + vx_read_register (-1); +} + + +/* 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). */ + /* FIXME, look at REGNO to save time here */ + +vx_write_register (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + +#ifdef I80960 + + bcopy (®isters[REGISTER_BYTE (R0_REGNUM)], + (char *) inferior_registers.r_lreg, 16 * sizeof (int)); + bcopy (®isters[REGISTER_BYTE (G0_REGNUM)], + (char *) inferior_registers.r_greg, 16 * sizeof (int)); + + /* Don't assume that a location in registers[] is properly aligned. */ + + bcopy (®isters[REGISTER_BYTE (PCW_REGNUM)], + (char *) &inferior_registers.r_pcw, sizeof (int)); + bcopy (®isters[REGISTER_BYTE (ACW_REGNUM)], + (char *) &inferior_registers.r_acw, sizeof (int)); + bcopy (®isters[REGISTER_BYTE (TCW_REGNUM)], + (char *) &inferior_registers.r_tcw, sizeof (int)); + +#else /* not 960 -- assume 68k -- FIXME */ + + bcopy (registers, &inferior_registers, 16 * 4); + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + +#endif /* Different register sets */ + + ptrace_in.pid = inferior_pid; + ptrace_in.info.ttype = REGS; + ptrace_in.info.more_data = (caddr_t) &inferior_registers; + + /* XXX change second param to be a proc number */ + status = net_ptrace_clnt_call (PTRACE_SETREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + + /* Store floating point registers if the target has them. */ + + if (target_has_fp) + { +#ifdef I80960 + + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); + +#else /* not 960 -- assume 68k -- FIXME */ + + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + +#endif /* Different register sets */ + + ptrace_in.pid = inferior_pid; + ptrace_in.info.ttype = FPREGS; + ptrace_in.info.more_data = (caddr_t) &inferior_fp_registers; + + status = net_ptrace_clnt_call (PTRACE_SETFPREGS, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + return -1; + } + } + return 0; +} + +/* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. WRITE is true if writing to the + inferior. + Result is the number of bytes written or read (zero if error). The + protocol allows us to return a negative count, indicating that we can't + handle the current address but can handle one N bytes further, but + vxworks doesn't give us that information. */ + +int +vx_xfer_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + C_bytes data; + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + + ptrace_in.pid = inferior_pid; /* XXX pid unnecessary for READDATA */ + ptrace_in.addr = (int) memaddr; /* Where from */ + ptrace_in.data = len; /* How many bytes */ + + if (write) + { + ptrace_in.info.ttype = DATA; + ptrace_in.info.more_data = (caddr_t) &data; + + data.bytes = (caddr_t) myaddr; /* Where from */ + data.len = len; /* How many bytes (again, for XDR) */ + + /* XXX change second param to be a proc number */ + status = net_ptrace_clnt_call (PTRACE_WRITEDATA, &ptrace_in, &ptrace_out); + } + else + { + ptrace_out.info.more_data = (caddr_t) &data; + data.bytes = myaddr; /* Where to */ + data.len = len; /* How many (again, for XDR) */ + + /* XXX change second param to be a proc number */ + status = net_ptrace_clnt_call (PTRACE_READDATA, &ptrace_in, &ptrace_out); + } + + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + return 0; /* No bytes moved */ + } + return len; /* Moved *all* the bytes */ +} + +void +vx_files_info () +{ + printf ("\tAttached to host `%s'", vx_host); + printf (", which has %sfloating point", target_has_fp? "": "no "); + printf (".\n"); +} + +void +vx_run_files_info () +{ + printf ("\tRunning %s VxWorks process 0x%x", + vx_running? "child": "attached", + inferior_pid); + if (vx_running) + printf (", function `%s'", vx_running); + printf(".\n"); +} + +void +vx_resume (step, siggnal) + int step; + int siggnal; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + + if (siggnal != 0 && siggnal != stop_signal) + error ("Cannot send signals to VxWorks processes"); + + bzero ((char *) &ptrace_in, sizeof (ptrace_in)); + bzero ((char *) &ptrace_out, sizeof (ptrace_out)); + + ptrace_in.pid = inferior_pid; + ptrace_in.addr = 1; /* Target side insists on this, or it panics. */ + + /* XXX change second param to be a proc number */ + status = net_ptrace_clnt_call (step? PTRACE_SINGLESTEP: PTRACE_CONT, + &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Resuming remote process"); + } +} + +void +vx_mourn_inferior () +{ + pop_target (); /* Pop back to no-child state */ + generic_mourn_inferior (); +} + + +/* This function allows the addition of incrementally linked object files. */ + +void +vx_load_command (arg_string, from_tty) + char* arg_string; + int from_tty; +{ + CORE_ADDR text_addr; + CORE_ADDR data_addr; + CORE_ADDR bss_addr; + + if (arg_string == 0) + error ("The load command takes a file name"); + + arg_string = tilde_expand (arg_string); + make_cleanup (free, arg_string); + + dont_repeat (); + + QUIT; + immediate_quit++; + if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1) + error ("Load failed on target machine"); + immediate_quit--; + + /* FIXME, for now we ignore data_addr and bss_addr. */ + symbol_file_add (arg_string, from_tty, text_addr, 0); +} + +#ifdef FIXME /* Not ready for prime time */ +/* Single step the target program at the source or machine level. + Takes an error exit if rpc fails. + Returns -1 if remote single-step operation fails, else 0. */ + +static int +net_step () +{ + enum clnt_stat status; + int step_status; + SOURCE_STEP source_step; + + source_step.taskId = inferior_pid; + + if (step_range_end) + { + source_step.startAddr = step_range_start; + source_step.endAddr = step_range_end; + } + else + { + source_step.startAddr = 0; + source_step.endAddr = 0; + } + + status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step, + xdr_int, &step_status); + + if (status == RPC_SUCCESS) + return step_status; + else + error (rpcerr); +} +#endif + +/* Emulate ptrace using RPC calls to the VxWorks target system. + Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise. */ + +static int +net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut) + enum ptracereq request; + Rptrace *pPtraceIn; + Ptrace_return *pPtraceOut; +{ + enum clnt_stat status; + + status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return, + pPtraceOut); + + if (status != RPC_SUCCESS) + return -1; + + return 0; +} + +/* Query the target for the name of the file from which VxWorks was + booted. pBootFile is the address of a pointer to the buffer to + receive the file name; if the pointer pointed to by pBootFile is + NULL, memory for the buffer will be allocated by XDR. + Returns -1 if rpc failed, 0 otherwise. */ + +int +net_get_boot_file (pBootFile) + char **pBootFile; +{ + enum clnt_stat status; + + status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0, + xdr_wrapstring, pBootFile); + return (status == RPC_SUCCESS) ? 0 : -1; +} + +/* Fetch a list of loaded object modules from the VxWorks target. + Returns -1 if rpc failed, 0 otherwise + There's no way to check if the returned loadTable is correct. + VxWorks doesn't check it. */ + +int +net_get_symbols (pLoadTable) + ldtabl *pLoadTable; /* return pointer to ldtabl here */ +{ + enum clnt_stat status; + + bzero ((char *) pLoadTable, sizeof (struct ldtabl)); + + status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable); + return (status == RPC_SUCCESS) ? 0 : -1; +} + +/* Look up a symbol in the VxWorks target's symbol table. + Returns status of symbol read on target side (0=success, -1=fail) + Returns -1 and complain()s if rpc fails. */ + +struct complaint cant_contact_target = + {"Lost contact with VxWorks target", 0, 0}; + +int +vx_lookup_symbol (name, pAddr) + char *name; /* symbol name */ + CORE_ADDR *pAddr; +{ + enum clnt_stat status; + SYMBOL_ADDR symbolAddr; + + *pAddr = 0; + bzero ((char *) &symbolAddr, sizeof (symbolAddr)); + + status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name, + xdr_SYMBOL_ADDR, &symbolAddr); + if (status != RPC_SUCCESS) { + complain (&cant_contact_target, 0); + return -1; + } + + *pAddr = symbolAddr.addr; + return symbolAddr.status; +} + +/* Check to see if the VxWorks target has a floating point coprocessor. + Returns 1 if target has floating point processor, 0 otherwise. + Calls error() if rpc fails. */ + +int +net_check_for_fp () +{ + enum clnt_stat status; + bool_t fp = 0; /* true if fp processor is present on target board */ + + status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp); + if (status != RPC_SUCCESS) + error (rpcerr); + + return (int) fp; +} + +/* Establish an RPC connection with the VxWorks target system. + Calls error () if unable to establish connection. */ + +void +net_connect (host) + char *host; +{ + struct sockaddr_in destAddr; + struct hostent *destHost; + + /* get the internet address for the given host */ + + if ((destHost = (struct hostent *) gethostbyname (host)) == NULL) + error ("Invalid hostname. Couldn't find remote host address."); + + bzero (&destAddr, sizeof (destAddr)); + + destAddr.sin_addr.s_addr = * (u_long *) destHost->h_addr; + destAddr.sin_family = AF_INET; + destAddr.sin_port = 0; /* set to actual port that remote + ptrace is listening on. */ + + /* Create a tcp client transport on which to issue + calls to the remote ptrace server. */ + + ptraceSock = RPC_ANYSOCK; + pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0); + /* FIXME, here is where we deal with different version numbers of the proto */ + + if (pClient == NULL) + { + clnt_pcreateerror ("\tnet_connect"); + error ("Couldn't connect to remote target."); + } +} + +/* Sleep for the specified number of milliseconds + * (assumed to be less than 1000). + * If select () is interrupted, returns immediately; + * takes an error exit if select () fails for some other reason. + */ + +static void +sleep_ms (ms) + long ms; +{ + struct timeval select_timeout; + int status; + + select_timeout.tv_sec = 0; + select_timeout.tv_usec = ms * 1000; + + status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &select_timeout); + + if (status < 0 && errno != EINTR) + perror_with_name ("select"); +} + +/* 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. */ + +/* For network debugging with VxWorks. + * VxWorks knows when tasks hit breakpoints, receive signals, exit, etc, + * so vx_wait() receives this information directly from + * VxWorks instead of trying to figure out what happenned via a wait() call. + */ + +static int +vx_wait (status) + int *status; +{ + register int pid; + WAITTYPE w; + RDB_EVENT rdbEvent; + int quit_failed; + + do + { + /* If CTRL-C is hit during this loop, + suspend the inferior process. */ + + quit_failed = 0; + if (quit_flag) + { + quit_failed = (net_quit () == -1); + quit_flag = 0; + } + + /* If a net_quit () or net_wait () call has failed, + allow the user to break the connection with the target. + We can't simply error () out of this loop, since the + data structures representing the state of the inferior + are in an inconsistent state. */ + + if (quit_failed || net_wait (&rdbEvent) == -1) + { + terminal_ours (); + if (query ("Can't %s. Disconnect from target system? ", + (quit_failed) ? "suspend remote task" + : "get status of remote task")) + { + target_mourn_inferior(); + error ("Use the \"target\" command to reconnect."); + } + else + { + terminal_inferior (); + continue; + } + } + + pid = rdbEvent.taskId; + if (pid == 0) + { + sleep_ms (200); /* FIXME Don't kill the network too badly */ + } + else if (pid != inferior_pid) + fatal ("Bad pid for debugged task: 0x%x\n", pid); + } while (pid == 0); + + /* FIXME, eventually do more then SIGTRAP on everything... */ + switch (rdbEvent.eventType) + { + case EVENT_EXIT: + WSETEXIT (w, 0); + /* FIXME is it possible to distinguish between a + XXX normal vs abnormal exit in VxWorks? */ + break; + + case EVENT_START: /* Task was just started. */ + WSETSTOP (w, SIGTRAP); + break; + + case EVENT_STOP: + WSETSTOP (w, SIGTRAP); + /* XXX was it stopped by a signal? act accordingly */ + break; + + case EVENT_BREAK: /* Breakpoint was hit. */ + WSETSTOP (w, SIGTRAP); + break; + + case EVENT_SUSPEND: /* Task was suspended, probably by ^C. */ + WSETSTOP (w, SIGINT); + break; + + case EVENT_BUS_ERR: /* Task made evil nasty reference. */ + WSETSTOP (w, SIGBUS); + break; + + case EVENT_ZERO_DIV: /* Division by zero */ + WSETSTOP (w, SIGFPE); /* Like Unix, call it a float exception. */ + + case EVENT_SIGNAL: + /* The target is not running Unix, and its + faults/traces do not map nicely into Unix signals. + Make sure they do not get confused with Unix signals + by numbering them with values higher than the highest + legal Unix signal. code in the arch-dependent PRINT_RANDOM_SIGNAL + routine will interpret the value for wait_for_inferior. */ + WSETSTOP (w, rdbEvent.sigType + NSIG); + break; + } /* switch */ + *status = *(int *)&w; /* Grumble union wait crap Grumble */ + return pid; +} + +static int +symbol_stub (arg) + int arg; +{ + char *bootFile = (char *)arg; + symbol_file_command (bootFile, 0); + return 1; +} + +static int +add_symbol_stub (arg) + int arg; +{ + struct ldfile *pLoadFile = (struct ldfile *)arg; + + printf("\t%s: ", pLoadFile->name); + symbol_file_add (pLoadFile->name, 0, pLoadFile->txt_addr, 0); + printf ("ok\n"); + return 1; +} +/* Target command for VxWorks target systems. + + Used in vxgdb. Takes the name of a remote target machine + running vxWorks and connects to it to initialize remote network + debugging. */ + +static void +vx_open (args, from_tty) + char *args; + int from_tty; +{ + extern int close (); + char *bootFile; + extern char *source_path; + struct ldtabl loadTable; + struct ldfile *pLoadFile; + int i; + extern CLIENT *pClient; + + if (!args) + error_no_arg ("target machine name"); + + unpush_target (&vx_ops); + printf ("Attaching remote machine across net...\n"); + fflush (stdout); + + /* Allow the user to kill the connect attempt by typing ^C. + Wait until the call to target_has_fp () completes before + disallowing an immediate quit, since even if net_connect () + is successful, the remote debug server might be hung. */ + + immediate_quit++; + + net_connect (args); + target_has_fp = net_check_for_fp (); + printf_filtered ("Connected to %s.\n", args); + + immediate_quit--; + + push_target (&vx_ops); + + /* Save a copy of the target host's name. */ + vx_host = savestring (args, strlen (args)); + + /* Find out the name of the file from which the target was booted + and load its symbol table. */ + + printf_filtered ("Looking in Unix path for all loaded modules:\n"); + bootFile = NULL; + if (!net_get_boot_file (&bootFile)) + { + if (*bootFile) { + printf_filtered ("\t%s: ", bootFile); + if (catch_errors (symbol_stub, (int)bootFile, + "Error reading symbols from boot file")) + puts_filtered ("ok\n"); + } else if (from_tty) + printf ("VxWorks kernel symbols not loaded.\n"); + } + else + error ("Can't retrieve boot file name from target machine."); + + clnt_freeres (pClient, xdr_wrapstring, &bootFile); + + if (net_get_symbols (&loadTable) != 0) + error ("Can't read loaded modules from target machine"); + + i = 0-1; + while (++i < loadTable.tbl_size) + { + QUIT; /* FIXME, avoids clnt_freeres below: mem leak */ + pLoadFile = &loadTable.tbl_ent [i]; +#ifdef WRS_ORIG + { + register int desc; + struct cleanup *old_chain; + char *fullname = NULL; + + desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname); + if (desc < 0) + perror_with_name (pLoadFile->name); + old_chain = make_cleanup (close, desc); + add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr, + pLoadFile->bss_addr); + do_cleanups (old_chain); + } +#else + /* Botches, FIXME: + (1) Searches the PATH, not the source path. + (2) data and bss are assumed to be at the usual offsets from text. */ + catch_errors (add_symbol_stub, (int)pLoadFile, (char *)0); +#endif + } + printf_filtered ("Done.\n"); + + clnt_freeres (pClient, xdr_ldtabl, &loadTable); +} + +/* attach_command -- + takes a task started up outside of gdb and ``attaches'' to it. + This stops it cold in its tracks and allows us to start tracing it. */ + +static void +vx_attach (args, from_tty) + char *args; + int from_tty; +{ + int pid; + char *cptr = 0; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + int status; + + dont_repeat(); + + if (!args) + error_no_arg ("process-id to attach"); + + pid = strtol (args, &cptr, 0); + if ((cptr == args) || (*cptr != '\0')) + error ("Invalid process-id -- give a single number in decimal or 0xhex"); + + if (from_tty) + printf ("Attaching pid 0x%x.\n", pid); + + bzero ((char *)&ptrace_in, sizeof (ptrace_in)); + bzero ((char *)&ptrace_out, sizeof (ptrace_out)); + ptrace_in.pid = pid; + + status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out); + if (status == -1) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Attaching remote process"); + } + + /* It worked... */ + push_target (&vx_run_ops); + inferior_pid = pid; + vx_running = 0; + +#if defined (START_INFERIOR_HOOK) + START_INFERIOR_HOOK (); +#endif + + mark_breakpoints_out (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* We will get a task spawn event immediately. */ + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + wait_for_inferior (); + stop_soon_quietly = 0; + normal_stop (); +} + + +/* detach_command -- + takes a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via the normal ptrace (PTRACE_TRACEME). */ + +static void +vx_detach (args, from_tty) + char *args; + int from_tty; +{ + Rptrace ptrace_in; + Ptrace_return ptrace_out; + int signal = 0; + int status; + + if (args) + error ("Argument given to VxWorks \"detach\"."); + + if (from_tty) + printf ("Detaching pid 0x%x.\n", inferior_pid); + + if (args) /* FIXME, should be possible to leave suspended */ + signal = atoi (args); + + bzero ((char *)&ptrace_in, sizeof (ptrace_in)); + bzero ((char *)&ptrace_out, sizeof (ptrace_out)); + ptrace_in.pid = inferior_pid; + + status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out); + if (status == -1) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Detaching VxWorks process"); + } + + inferior_pid = 0; + pop_target (); /* go back to non-executing VxWorks connection */ +} + +/* vx_kill -- takes a running task and wipes it out. */ + +static void +vx_kill (args, from_tty) + char *args; + int from_tty; +{ + Rptrace ptrace_in; + Ptrace_return ptrace_out; + int status; + + if (args) + error ("Argument given to VxWorks \"kill\"."); + + if (from_tty) + printf ("Killing pid 0x%x.\n", inferior_pid); + + bzero ((char *)&ptrace_in, sizeof (ptrace_in)); + bzero ((char *)&ptrace_out, sizeof (ptrace_out)); + ptrace_in.pid = inferior_pid; + + status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out); + if (status == -1) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Killing VxWorks process"); + } + + /* If it gives good status, the process is *gone*, no events remain. */ + inferior_pid = 0; + pop_target (); /* go back to non-executing VxWorks connection */ +} + +/* Clean up from the VxWorks process target as it goes away. */ + +void +vx_proc_close (quitting) + int quitting; +{ + inferior_pid = 0; /* No longer have a process. */ + if (vx_running) + free (vx_running); + vx_running = 0; +} + +/* Cross-net conversion of floats to and from extended form. + (This is needed because different target machines have different + extended floating point formats.) */ + +/* Convert from an extended float to a double. + + The extended float is stored as raw data pointed to by FROM. + Return the converted value as raw data in the double pointed to by TO. +*/ + +static void +vx_convert_to_virtual (regno, from, to) + int regno; + char *from; + char *to; +{ + enum clnt_stat status; + + if (REGISTER_CONVERTIBLE (regno)) + { + if (!target_has_fp) { + *(double *)to = 0.0; /* Skip the trouble if no float anyway */ + return; + } + + status = net_clnt_call (VX_CONV_FROM_68881, xdr_ext_fp, from, + xdr_double, to); + + if (status == RPC_SUCCESS) + return; + else + error (rpcerr); + } + else + bcopy (from, to, REGISTER_VIRTUAL_SIZE (regno)); +} + + +/* The converse: convert from a double to an extended float. + + The double is stored as raw data pointed to by FROM. + Return the converted value as raw data in the extended + float pointed to by TO. +*/ + +static void +vx_convert_from_virtual (regno, from, to) + int regno; + char *from; + char *to; +{ + enum clnt_stat status; + + if (REGISTER_CONVERTIBLE (regno)) + { + if (!target_has_fp) { + bzero (to, REGISTER_RAW_SIZE (FP0_REGNUM)); /* Shrug */ + return; + } + + status = net_clnt_call (VX_CONV_TO_68881, xdr_double, from, + xdr_ext_fp, to); + if (status == RPC_SUCCESS) + return; + else + error (rpcerr); + } + else + bcopy (from, to, REGISTER_VIRTUAL_SIZE (regno)); +} + +/* Make an RPC call to the VxWorks target. + Returns RPC status. */ + +static enum clnt_stat +net_clnt_call (procNum, inProc, in, outProc, out) + enum ptracereq procNum; + xdrproc_t inProc; + char *in; + xdrproc_t outProc; + char *out; +{ + enum clnt_stat status; + + status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout); + + if (status != RPC_SUCCESS) + clnt_perrno (status); + + return status; +} + +/* Clean up before losing control. */ + +void +vx_close (quitting) + int quitting; +{ + if (pClient) + clnt_destroy (pClient); /* The net connection */ + pClient = 0; + + if (vx_host) + free (vx_host); /* The hostname */ + vx_host = 0; +} + + +/* Target ops structure for accessing memory and such over the net */ + +struct target_ops vx_ops = { + "vxworks", "VxWorks target memory via RPC over TCP/IP", + vx_open, vx_close, vx_attach, 0, /* vx_detach, */ + 0, 0, /* resume, wait */ + 0, 0, /* read_reg, write_reg */ + 0, vx_convert_to_virtual, vx_convert_from_virtual, /* prep_to_store, */ + vx_xfer_memory, vx_files_info, + 0, 0, /* insert_breakpoint, remove_breakpoint */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, /* vx_kill, */ + vx_load_command, add_syms_addr_command, + 0, /* call_function */ + vx_lookup_symbol, + vx_create_inferior, 0, /* mourn_inferior */ + core_stratum, 0, /* next */ + 1, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */ + OPS_MAGIC, /* Always the last thing */ +}; + +/* Target ops structure for accessing VxWorks child processes over the net */ + +struct target_ops vx_run_ops = { + "vxprocess", "VxWorks process", + vx_open, vx_proc_close, 0, vx_detach, /* vx_attach */ + vx_resume, vx_wait, + vx_read_register, vx_write_register, + vx_prepare_to_store, vx_convert_to_virtual, vx_convert_from_virtual, + vx_xfer_memory, vx_run_files_info, + vx_insert_breakpoint, vx_remove_breakpoint, + 0, 0, 0, 0, 0, /* terminal stuff */ + vx_kill, + vx_load_command, add_syms_addr_command, + call_function_by_hand, /* FIXME, calling fns is maybe botched? */ + vx_lookup_symbol, + 0, vx_mourn_inferior, + process_stratum, 0, /* next */ + 0, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + /* all_mem is off to avoid spurious msg in "i files" */ + OPS_MAGIC, /* Always the last thing */ +}; +/* ==> Remember when reading at end of file, there are two "ops" structs here. */ + +void +_initialize_vx () +{ + add_target (&vx_ops); + add_target (&vx_run_ops); +} diff --git a/gdb/saber.suppress b/gdb/saber.suppress new file mode 100644 index 00000000000..19fac4d5f2d --- /dev/null +++ b/gdb/saber.suppress @@ -0,0 +1,411 @@ + + +/* Options for project */ +unsetopt ansi +setopt auto_compile +unsetopt auto_reload +setopt auto_replace +unsetopt batch_load +unsetopt batch_run +unsetopt cc_prog +setopt ccargs -g +unsetopt create_file +unsetopt debug_child +unsetopt echo +setopt edit_jobs 5 +unsetopt eight_bit +setopt line_edit +setopt line_meta +setopt lint_load 2 +setopt lint_run 2 +setopt list_action +setopt load_flags -I. -g -I.. -I../vx-share +unsetopt long_not_int +unsetopt make_args +setopt make_hfiles +unsetopt make_offset +unsetopt make_prog +setopt make_symbol # +setopt mem_config 16384 +unsetopt mem_trace +setopt num_proc 1 +unsetopt page_cmds +setopt page_list 19 +unsetopt page_load +unsetopt path +setopt proto_path . /s2/saber_dir30/sun4-40/proto /s2/saber_dir30/sun4-40/../common/proto +unsetopt preprocessor +setopt program_name a.out +unsetopt print_custom +setopt print_pointer +setopt print_string 20 +unsetopt save_memory +setopt sbrk_size 1048576 +setopt src_err 3 +setopt src_step 1 +setopt src_stop 3 +setopt sys_load_flags -L/lib -L/usr/lib -L/usr/local/lib -I/usr/include -Dunix -Dsun -Dsparc +unsetopt tab_stop +unsetopt terse_suppress +unsetopt terse_where +setopt unset_value 191 +unsetopt win_fork_nodup +setopt win_no_raise +unsetopt win_message_list +unsetopt win_project_list +/* Suppressions for project */ +suppress 6 in read_huge_number +/* Over/underflow */ +suppress 8 in read_huge_number +/* Over/underflow */ +suppress 22 +/* Pointer subtraction */ +suppress 22 in free_all_psymtabs +/* Pointer subtraction */ +suppress 22 in free_all_symtabs +/* Pointer subtraction */ +suppress 56 in print_string +/* Information lost */ +suppress 65 "../bfd/bfd.c":379 +/* Too many function arguments */ +suppress 65 on printf_filtered +/* Too many function arguments */ +suppress 65 on fprintf_filtered +/* Too many function arguments */ +suppress 65 on vfprintf_filtered +/* Too many function arguments */ +suppress 65 on query +/* Too many function arguments */ +suppress 65 on fatal_dump_core +/* Too many function arguments */ +suppress 65 on fatal +/* Too many function arguments */ +suppress 65 on error +/* Too many function arguments */ +suppress 65 on noprocess +/* Too many function arguments */ +suppress 65 +/* Too many function arguments */ +suppress 66 on say +/* Too few function arguments */ +suppress 66 on printf_filtered +/* Too few function arguments */ +suppress 66 on fprintf_filtered +/* Too few function arguments */ +suppress 66 on vfprintf_filtered +/* Too few function arguments */ +suppress 66 on query +/* Too few function arguments */ +suppress 66 on fatal_dump_core +/* Too few function arguments */ +suppress 66 on fatal +/* Too few function arguments */ +suppress 66 on error +/* Too few function arguments */ +suppress 67 on printf_filtered +/* Signed/unsigned argument mismatch */ +suppress 67 on fprintf_filtered +/* Signed/unsigned argument mismatch */ +suppress 67 on vfprintf_filtered +/* Signed/unsigned argument mismatch */ +suppress 67 on query +/* Signed/unsigned argument mismatch */ +suppress 67 on fatal_dump_core +/* Signed/unsigned argument mismatch */ +suppress 67 on fatal +/* Signed/unsigned argument mismatch */ +suppress 67 on error +/* Signed/unsigned argument mismatch */ +suppress 67 +/* Signed/unsigned argument mismatch */ +suppress 68 on bfd_get_section_contents +/* Benign argument mismatch */ +suppress 68 on _do_getblong +/* Benign argument mismatch */ +suppress 68 on supply_register +/* Benign argument mismatch */ +suppress 68 on target_write_memory +/* Benign argument mismatch */ +suppress 68 on write_register_bytes +/* Benign argument mismatch */ +suppress 68 on read_register_bytes +/* Benign argument mismatch */ +suppress 68 on read_memory +/* Benign argument mismatch */ +suppress 68 on say +/* Benign argument mismatch */ +suppress 68 on printf_filtered +/* Benign argument mismatch */ +suppress 68 on fprintf_filtered +/* Benign argument mismatch */ +suppress 68 on vfprintf_filtered +/* Benign argument mismatch */ +suppress 68 on query +/* Benign argument mismatch */ +suppress 68 on fatal_dump_core +/* Benign argument mismatch */ +suppress 68 on fatal +/* Benign argument mismatch */ +suppress 68 on error +/* Benign argument mismatch */ +suppress 68 in find_solib +/* Benign argument mismatch */ +suppress 68 on child_wait +/* Benign argument mismatch */ +suppress 68 on xrealloc +/* Benign argument mismatch */ +suppress 68 on myread +/* Benign argument mismatch */ +suppress 68 in do_cleanups +/* Benign argument mismatch */ +suppress 68 on make_cleanup +/* Benign argument mismatch */ +suppress 68 on target_read_memory +/* Benign argument mismatch */ +suppress 69 on printf_filtered +/* Serious argument mismatch */ +suppress 69 on fprintf_filtered +/* Serious argument mismatch */ +suppress 69 on vfprintf_filtered +/* Serious argument mismatch */ +suppress 69 on query +/* Serious argument mismatch */ +suppress 69 on fatal_dump_core +/* Serious argument mismatch */ +suppress 69 on fatal +/* Serious argument mismatch */ +suppress 69 on error +/* Serious argument mismatch */ +suppress 70 on printf_filtered +/* Passing illegal enumeration value */ +suppress 70 on fprintf_filtered +/* Passing illegal enumeration value */ +suppress 70 on vfprintf_filtered +/* Passing illegal enumeration value */ +suppress 70 on query +/* Passing illegal enumeration value */ +suppress 70 on fatal_dump_core +/* Passing illegal enumeration value */ +suppress 70 on fatal +/* Passing illegal enumeration value */ +suppress 70 on error +/* Passing illegal enumeration value */ +suppress 110 in printf_filtered +/* Signed/unsigned memory retrieval */ +suppress 110 in fprintf_filtered +/* Signed/unsigned memory retrieval */ +suppress 110 in vfprintf_filtered +/* Signed/unsigned memory retrieval */ +suppress 110 in query +/* Signed/unsigned memory retrieval */ +suppress 110 in fatal_dump_core +/* Signed/unsigned memory retrieval */ +suppress 110 in fatal +/* Signed/unsigned memory retrieval */ +suppress 110 in error +/* Signed/unsigned memory retrieval */ +suppress 112 in printf_filtered +/* Memory retrieval */ +suppress 112 in fprintf_filtered +/* Memory retrieval */ +suppress 112 in vfprintf_filtered +/* Memory retrieval */ +suppress 112 in query +/* Memory retrieval */ +suppress 112 in fatal_dump_core +/* Memory retrieval */ +suppress 112 in fatal +/* Memory retrieval */ +suppress 112 in error +/* Memory retrieval */ +suppress 112 +/* Memory retrieval */ +suppress 112 ../symtab.c +/* Memory retrieval */ +suppress 112 in child_xfer_memory +/* Memory retrieval */ +suppress 165 in frame_saved_pc +/* Dereference */ +suppress 165 in get_prev_frame_info +/* Dereference */ +suppress 167 in get_prev_frame_info +/* Selection */ +suppress 167 in frame_saved_pc +/* Selection */ +suppress 442 in try_baudrate +/* Escape has null value */ +suppress 529 in read_range_type +/* Statement not reached */ +suppress 529 in process_one_symbol +/* Statement not reached */ +suppress 529 in unpack_double +/* Statement not reached */ +suppress 529 in wait_for_inferior +/* Statement not reached */ +suppress 529 in do_registers_info +/* Statement not reached */ +suppress 529 in value_from_register +/* Statement not reached */ +suppress 530 "../environ.c":69 +/* Empty body of statement */ +suppress 530 "../remote-eb.c":333 +/* Empty body of statement */ +suppress 530 "../remote-eb.c":331 +/* Empty body of statement */ +suppress 530 "../remote-eb.c":324 +/* Empty body of statement */ +suppress 530 "../dbxread.c":792 +/* Empty body of statement */ +suppress 530 +/* Empty body of statement */ +suppress 530 "../dbxread.c":796 +/* Empty body of statement */ +suppress 546 in net_quit +/* Function exits through bottom */ +suppress 546 in net_wait +/* Function exits through bottom */ +suppress 546 in vx_remove_breakpoint +/* Function exits through bottom */ +suppress 546 in vx_insert_breakpoint +/* Function exits through bottom */ +suppress 546 in value_less +/* Function exits through bottom */ +suppress 546 in value_equal +/* Function exits through bottom */ +suppress 546 in unpack_long +/* Function exits through bottom */ +suppress 558 in read_range_type +/* Constant in conditional */ +suppress 558 in process_one_symbol +/* Constant in conditional */ +suppress 558 in read_dbx_symtab +/* Constant in conditional */ +suppress 558 in vx_write_register +/* Constant in conditional */ +suppress 558 in vx_read_register +/* Constant in conditional */ +suppress 558 in unpack_double +/* Constant in conditional */ +suppress 558 in wait_for_inferior +/* Constant in conditional */ +suppress 558 in do_registers_info +/* Constant in conditional */ +suppress 558 in value_from_register +/* Constant in conditional */ +suppress 560 in solib_address +/* Assignment within conditional */ +suppress 560 in solib_info +/* Assignment within conditional */ +suppress 560 in solib_add +/* Assignment within conditional */ +suppress 560 in read_type +/* Assignment within conditional */ +suppress 560 in type_print_base +/* Assignment within conditional */ +suppress 560 in type_print_derivation_info +/* Assignment within conditional */ +suppress 560 in block_depth +/* Assignment within conditional */ +suppress 560 in select_source_symtab +/* Assignment within conditional */ +suppress 560 in clear_value_history +/* Assignment within conditional */ +suppress 560 in clear_displays +/* Assignment within conditional */ +suppress 560 in initialize_main +/* Assignment within conditional */ +suppress 560 in echo_command +/* Assignment within conditional */ +suppress 560 in unset_in_environ +/* Assignment within conditional */ +suppress 560 in set_in_environ +/* Assignment within conditional */ +suppress 560 in get_in_environ +/* Assignment within conditional */ +suppress 560 in do_setshow_command +/* Assignment within conditional */ +suppress 560 in breakpoint_1 +/* Assignment within conditional */ +suppress 590 on sig +/* Unused formal parameter */ +suppress 590 in nindy_create_inferior +/* Unused formal parameter */ +suppress 590 in add_to_section_table +/* Unused formal parameter */ +suppress 590 in vx_create_inferior +/* Unused formal parameter */ +suppress 590 in host_convert_from_virtual +/* Unused formal parameter */ +suppress 590 in host_convert_to_virtual +/* Unused formal parameter */ +suppress 590 on siggnal +/* Unused formal parameter */ +suppress 590 in init_sig +/* Unused formal parameter */ +suppress 590 in nindy_resume +/* Unused formal parameter */ +suppress 590 in set_history_size_command +/* Unused formal parameter */ +suppress 590 in not_just_help_class_command +/* Unused formal parameter */ +suppress 590 on regno +/* Unused formal parameter */ +suppress 590 on from_tty +/* Unused formal parameter */ +suppress 590 on args +/* Unused formal parameter */ +suppress 590 in process_symbol_pair +/* Unused formal parameter */ +suppress 591 in print_scalar_formatted +/* Unused automatic variable */ +suppress 592 on rcsid +/* Unused static */ +suppress 592 on check_break_insn_size +/* Unused static */ +suppress 594 in call_function_by_hand +/* Set but not used */ +suppress 594 in record_latest_value +/* Set but not used */ +suppress 594 in bpstat_stop_status +/* Set but not used */ +suppress 595 in coffstrip +/* Used before set */ +suppress 652 ../bfd.h +/* Declaration has no effect */ +suppress 652 /usr/include/machine/reg.h +/* Declaration has no effect */ + +/* Signals caught and ignored */ +catch HUP +catch QUIT +catch ILL +catch TRAP +catch IOT +catch EMT +catch FPE +catch KILL +catch BUS +catch SEGV +catch SYS +catch PIPE +catch TERM +catch URG +catch STOP +catch TSTP +catch TTIN +catch TTOU +catch IO +catch XCPU +catch XFSZ +catch VTALRM +catch PROF +catch LOST +catch USR1 +catch USR2 +ignore INT +ignore ALRM +ignore CONT +ignore CHLD +ignore WINCH + +/* Status of project */ diff --git a/gdb/signals.h b/gdb/signals.h new file mode 100644 index 00000000000..a6218d9e9fb --- /dev/null +++ b/gdb/signals.h @@ -0,0 +1,34 @@ +/* Signal handler definitions for GDB, the GNU Debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* This file is almost the same as including except that it + eliminates certain signal names when job control is not supported, + (or, on some systems, when job control is there but doesn't work + the way GDB expects it to work). */ + +#include + +#ifdef NO_JOB_CONTROL +# undef SIGTSTP +# undef SIGSTOP +# undef SIGCONT +# undef SIGTTIN +# undef SIGTTOU +#endif diff --git a/gdb/signame.c b/gdb/signame.c new file mode 100755 index 00000000000..740da408b8f --- /dev/null +++ b/gdb/signame.c @@ -0,0 +1,246 @@ +/* Convert between signal names and numbers. + Copyright (C) 1990 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include "signame.h" + +#ifdef __STDC__ +#define CONST const +#else +#define CONST +#endif + +#ifdef SYS_SIGLIST_MISSING +/* There is too much variation in Sys V signal numbers and names, so + we must initialize them at runtime. */ + +static CONST char undoc[] = "unknown signal"; + +CONST char *sys_siglist[NSIG]; +#endif /* SYS_SIGLIST_MISSING */ + +/* Table of abbreviations for signals. Note: A given number can + appear more than once with different abbreviations. */ +typedef struct + { + int number; + CONST char *abbrev; + } num_abbrev; +static num_abbrev sig_table[NSIG*2]; +/* Number of elements of sig_table used. */ +static int sig_table_nelts = 0; + +/* Enter signal number NUMBER into the tables with ABBREV and NAME. */ +static void +init_sig (number, abbrev, name) + int number; + CONST char *abbrev; + CONST char *name; +{ +#ifdef SYS_SIGLIST_MISSING + sys_siglist[number] = name; +#endif + sig_table[sig_table_nelts].number = number; + sig_table[sig_table_nelts++].abbrev = abbrev; +} + +static void init_sigs () +{ +#ifdef SYS_SIGLIST_MISSING + /* Initialize signal names. */ + for (i = 0; i < NSIG; i++) + sys_siglist[i] = undoc; +#endif /* SYS_SIGLIST_MISSING */ + + /* Initialize signal names. */ +#if defined (SIGHUP) + init_sig (SIGHUP, "HUP", "Hangup"); +#endif +#if defined (SIGINT) + init_sig (SIGINT, "INT", "Interrupt"); +#endif +#if defined (SIGQUIT) + init_sig (SIGQUIT, "QUIT", "Quit"); +#endif +#if defined (SIGILL) + init_sig (SIGILL, "ILL", "Illegal Instruction"); +#endif +#if defined (SIGTRAP) + init_sig (SIGTRAP, "TRAP", "Trace/breakpoint trap"); +#endif + /* If SIGIOT == SIGABRT, we want to print it as SIGABRT because + SIGABRT is in ANSI and POSIX.1 and SIGIOT isn't. */ +#if defined (SIGABRT) + init_sig (SIGABRT, "ABRT", "Aborted"); +#endif +#if defined (SIGIOT) + init_sig (SIGIOT, "IOT", "IOT trap"); +#endif +#if defined (SIGEMT) + init_sig (SIGEMT, "EMT", "EMT trap"); +#endif +#if defined (SIGFPE) + init_sig (SIGFPE, "FPE", "Floating point exception"); +#endif +#if defined (SIGKILL) + init_sig (SIGKILL, "KILL", "Killed"); +#endif +#if defined (SIGBUS) + init_sig (SIGBUS, "BUS", "Bus error"); +#endif +#if defined (SIGSEGV) + init_sig (SIGSEGV, "SEGV", "Segmentation fault"); +#endif +#if defined (SIGSYS) + init_sig (SIGSYS, "SYS", "Bad system call"); +#endif +#if defined (SIGPIPE) + init_sig (SIGPIPE, "PIPE", "Broken pipe"); +#endif +#if defined (SIGALRM) + init_sig (SIGALRM, "ALRM", "Alarm clock"); +#endif +#if defined (SIGTERM) + init_sig (SIGTERM, "TERM", "Terminated"); +#endif +#if defined (SIGUSR1) + init_sig (SIGUSR1, "USR1", "User defined signal 1"); +#endif +#if defined (SIGUSR2) + init_sig (SIGUSR2, "USR2", "User defined signal 2"); +#endif + /* If SIGCLD == SIGCHLD, we want to print it as SIGCHLD because that + is what is in POSIX.1. */ +#if defined (SIGCHLD) + init_sig (SIGCHLD, "CHLD", "Child exited"); +#endif +#if defined (SIGCLD) + init_sig (SIGCLD, "CLD", "Child exited"); +#endif +#if defined (SIGPWR) + init_sig (SIGPWR, "PWR", "Power failure"); +#endif +#if defined (SIGTSTP) + init_sig (SIGTSTP, "TSTP", "Stopped"); +#endif +#if defined (SIGTTIN) + init_sig (SIGTTIN, "TTIN", "Stopped (tty input)"); +#endif +#if defined (SIGTTOU) + init_sig (SIGTTOU, "TTOU", "Stopped (tty output)"); +#endif +#if defined (SIGSTOP) + init_sig (SIGSTOP, "STOP", "Stopped (signal)"); +#endif +#if defined (SIGXCPU) + init_sig (SIGXCPU, "XCPU", "CPU time limit exceeded"); +#endif +#if defined (SIGXFSZ) + init_sig (SIGXFSZ, "XFSZ", "File size limit exceeded"); +#endif +#if defined (SIGVTALRM) + init_sig (SIGVTALRM, "VTALRM", "Virtual timer expired"); +#endif +#if defined (SIGPROF) + init_sig (SIGPROF, "PROF", "Profiling timer expired"); +#endif +#if defined (SIGWINCH) + /* "Window size changed" might be more accurate, but even if that + is all that it means now, perhaps in the future it will be + extended to cover other kinds of window changes. */ + init_sig (SIGWINCH, "WINCH", "Window changed"); +#endif +#if defined (SIGCONT) + init_sig (SIGCONT, "CONT", "Continued"); +#endif +#if defined (SIGURG) + init_sig (SIGURG, "URG", "Urgent I/O condition"); +#endif +#if defined (SIGIO) + /* "I/O pending" has also been suggested. A disadvantage is + that signal only happens when the process has + asked for it, not everytime I/O is pending. Another disadvantage + is the confusion from giving it a different name than under Unix. */ + init_sig (SIGIO, "IO", "I/O possible"); +#endif +#if defined (SIGWIND) + init_sig (SIGWIND, "WIND", "SIGWIND"); +#endif +#if defined (SIGPHONE) + init_sig (SIGPHONE, "PHONE", "SIGPHONE"); +#endif +#if defined (SIGPOLL) + init_sig (SIGPOLL, "POLL", "I/O possible"); +#endif +#if defined (SIGLOST) + init_sig (SIGLOST, "LOST", "Resource lost"); +#endif +} + +/* Return the abbreviation for signal NUMBER. */ +char * +sig_abbrev (number) + int number; +{ + int i; + + for (i = 0; i < sig_table_nelts; i++) + if (sig_table[i].number == number) + return (char *)sig_table[i].abbrev; + return NULL; +} + +/* Return the signal number for an ABBREV, or -1 if there is no + signal by that name. */ +int +sig_number (abbrev) + CONST char *abbrev; +{ + int i; + + /* Skip over "SIG" if present. */ + if (abbrev[0] == 'S' && abbrev[1] == 'I' && abbrev[2] == 'G') + abbrev += 3; + + for (i = 0; i < sig_table_nelts; i++) + if (abbrev[0] == sig_table[i].abbrev[0] + && strcmp (abbrev, sig_table[i].abbrev) == 0) + return sig_table[i].number; + return -1; +} + +#if defined (SYS_SIGLIST_MISSING) +/* Print to standard error the name of SIGNAL, preceded by MESSAGE and + a colon, and followed by a newline. */ +void +psignal (signal, message) + unsigned signal; + CONST char *message; +{ + if (signal <= 0 || signal >= NSIG) + fprintf (stderr, "%s: unknown signal", message); + else + fprintf (stderr, "%s: %s\n", message, sys_siglist[signal]); +} +#endif + +void +_initialize_signame () +{ + init_sigs (); +} diff --git a/gdb/signame.h b/gdb/signame.h new file mode 100755 index 00000000000..83edfa858fa --- /dev/null +++ b/gdb/signame.h @@ -0,0 +1,41 @@ +/* Convert between signal names and numbers. + Copyright (C) 1990 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Names for signals from 0 to NSIG-1. */ +extern char *sys_siglist[]; + +#ifdef __STDC__ +/* Return the abbreviation (e.g. ABRT, FPE, etc.) for signal NUMBER. + Do not return this as a const char *. The caller might want to + assign it to a char *. */ +char *sig_abbrev (int number); + +/* Return the signal number for an ABBREV, or -1 if there is no + signal by that name. */ +int sig_number (const char *abbrev); + +/* Print to standard error the name of SIGNAL, preceded by MESSAGE and + a colon, and followed by a newline. */ +void psignal (unsigned signal, const char *message); + +#else + +char *sig_abbrev (); +int sig_number (); +void psignal (); + +#endif diff --git a/gdb/sparc-opcode.h b/gdb/sparc-opcode.h new file mode 100755 index 00000000000..473ab6f0d02 --- /dev/null +++ b/gdb/sparc-opcode.h @@ -0,0 +1,641 @@ +/* Table of opcodes for the sparc. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + +GAS/GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS/GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS or GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ +struct sparc_opcode +{ + const char *name; + unsigned long int match; /* Bits that must be set. */ + unsigned long int lose; /* Bits that must not be set. */ + const char *args; + char flags; +}; + +#define F_DELAYED 1 /* Delayed branch */ +#define F_ALIAS 2 /* Alias for a "real" instruction */ + +/* + All sparc opcodes are 32 bits, except for the `set' instruction (really + a macro), which is 64 bits. It is handled as a special case. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character + for each operand of the instruction. + +Kinds of operands: + # Number used by optimizer. It is ignored. + 1 rs1 register. + 2 rs2 register. + d rd register. + e frs1 floating point register. + f frs2 floating point register. + g frsd floating point register. + b crs1 coprocessor register + c crs2 coprocessor register + D crsd coprocessor register + h 22 high bits. + i 13 bit Immediate. + l 22 bit PC relative immediate. + L 30 bit PC relative immediate. + a Annul. The annul bit is set. + A Alternate address space. Stored as 8 bits. + C Coprocessor state register. + F floating point state register. + p Processor state register. + q Floating point queue. + r Single register that is both rs1 and rsd. + Q Coprocessor queue. + S Special case. + t Trap base register. + w Window invalid mask register. + y Y register. + +*/ + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic must be + consecutive. If they aren't, the assembler will bomb at runtime. + + * The disassembler should not care about the order of the opcodes. */ + +static struct sparc_opcode sparc_opcodes[] = +{ + +{ "ldd", 0xc1980000, 0x0060201f, "[1],D", 0 }, /* ldd [rs1+%g0],d */ +{ "ldd", 0xc1982000, 0x00601fff, "[1],D", 0 }, /* ldd [rs1+0],d */ +{ "ldd", 0xc1982000, 0x00600000, "[1+i],D", 0 }, +{ "ldd", 0xc1982000, 0x00600000, "[i+1],D", 0 }, +{ "ldd", 0xc1980000, 0x00602000, "[1+2],D", 0 }, +{ "ldd", 0xc1180000, 0x00e0201f, "[1],g", 0 }, /* ldd [rs1+%g0],d */ +{ "ldd", 0xc1182000, 0x00e01fff, "[1],g", 0 }, /* ldd [rs1+0],d */ +{ "ldd", 0xc1182000, 0x00e00000, "[1+i],g", 0 }, +{ "ldd", 0xc1182000, 0x00e00000, "[i+1],g", 0 }, +{ "ldd", 0xc1180000, 0x00e02000, "[1+2],g", 0 }, +{ "ldd", 0xc0180000, 0x01e0201f, "[1],d", 0 }, /* ldd [rs1+%g0],d */ +{ "ldd", 0xc0182000, 0x01e01fff, "[1],d", 0 }, /* ldd [rs1+0],d */ +{ "ldd", 0xc0182000, 0x01e00000, "[1+i],d", 0 }, +{ "ldd", 0xc0182000, 0x01e00000, "[i+1],d", 0 }, +{ "ldd", 0xc0180000, 0x01e02000, "[1+2],d", 0 }, +{ "ld", 0xc1880000, 0x0070201f, "[1],C", 0 }, /* ld [rs1+%g0],d */ +{ "ld", 0xc1882000, 0x00701fff, "[1],C", 0 }, /* ld [rs1+0],d */ +{ "ld", 0xc1882000, 0x00700000, "[1+i],C", 0 }, +{ "ld", 0xc1882000, 0x00700000, "[i+1],C", 0 }, +{ "ld", 0xc1880000, 0x00702000, "[1+2],C", 0 }, +{ "ld", 0xc1800000, 0x0078201f, "[1],D", 0 }, /* ld [rs1+%g0],d */ +{ "ld", 0xc1802000, 0x00781fff, "[1],D", 0 }, /* ld [rs1+0],d */ +{ "ld", 0xc1802000, 0x00780000, "[1+i],D", 0 }, +{ "ld", 0xc1802000, 0x00780000, "[i+1],D", 0 }, +{ "ld", 0xc1800000, 0x00782000, "[1+2],D", 0 }, +{ "ld", 0xc1080000, 0x00f0201f, "[1],F", 0 }, /* ld [rs1+%g0],d */ +{ "ld", 0xc1082000, 0x00f01fff, "[1],F", 0 }, /* ld [rs1+0],d */ +{ "ld", 0xc1082000, 0x00f00000, "[1+i],F", 0 }, +{ "ld", 0xc1082000, 0x00f00000, "[i+1],F", 0 }, +{ "ld", 0xc1080000, 0x00f02000, "[1+2],F", 0 }, +{ "ld", 0xc1000000, 0x00f8201f, "[1],g", 0 }, /* ld [rs1+%g0],d */ +{ "ld", 0xc1002000, 0x00f81fff, "[1],g", 0 }, /* ld [rs1+0],d */ +{ "ld", 0xc1002000, 0x00f80000, "[1+i],g", 0 }, +{ "ld", 0xc1002000, 0x00f80000, "[i+1],g", 0 }, +{ "ld", 0xc1000000, 0x00f82000, "[1+2],g", 0 }, +{ "ld", 0xc0000000, 0x01f8201f, "[1],d", 0 }, /* ld [rs1+%g0],d */ +{ "ld", 0xc0002000, 0x01f81fff, "[1],d", 0 }, /* ld [rs1+0],d */ +{ "ld", 0xc0002000, 0x01f80000, "[1+i],d", 0 }, +{ "ld", 0xc0002000, 0x01f80000, "[i+1],d", 0 }, +{ "ld", 0xc0000000, 0x01f82000, "[1+2],d", 0 }, +{ "ldstuba", 0xc0d80000, 0x0100201f, "[1]A,d", 0 }, /* ldstuba [rs1+%g0],d */ +{ "ldstuba", 0xc0d80000, 0x01002000, "[1+2]A,d", 0 }, +{ "ldsha", 0xc0d00000, 0x0128201f, "[1]A,d", 0 }, /* ldsha [rs1+%g0],d */ +{ "ldsha", 0xc0d00000, 0x01282000, "[1+2]A,d", 0 }, +{ "ldsba", 0xc0c80000, 0x0130201f, "[1]A,d", 0 }, /* ldsba [rs1+%g0],d */ +{ "ldsba", 0xc0c80000, 0x01302000, "[1+2]A,d", 0 }, +{ "ldda", 0xc0980000, 0x0160201f, "[1]A,d", 0 }, /* ldda [rs1+%g0],d */ +{ "ldda", 0xc0980000, 0x01602000, "[1+2]A,d", 0 }, +{ "lduha", 0xc0900000, 0x0168201f, "[1]A,d", 0 }, /* lduha [rs1+%g0],d */ +{ "lduha", 0xc0900000, 0x01682000, "[1+2]A,d", 0 }, +{ "ldstub", 0xc0680000, 0x0190201f, "[1],d", 0 }, /* ldstub [rs1+%g0],d */ +{ "ldstub", 0xc0682000, 0x01900000, "[1+i],d", 0 }, +{ "ldstub", 0xc0682000, 0x01900000, "[i+1],d", 0 }, +{ "ldstub", 0xc0680000, 0x01902000, "[1+2],d", 0 }, +{ "lda", 0xc0800000, 0x0178201f, "[1]A,d", 0 }, /* lda [rs1+%g0],d */ +{ "lda", 0xc0800000, 0x01782000, "[1+2]A,d", 0 }, +{ "ldsh", 0xc0500000, 0x0000000d, "[1],d", 0 }, /* ldsh [rs1+%g0],d */ +{ "ldsh", 0xc0502000, 0x01a81fff, "[1],d", 0 }, /* ldsh [rs1+0],d */ +{ "ldsh", 0xc0502000, 0x01a80000, "[1+i],d", 0 }, +{ "ldsh", 0xc0502000, 0x01a80000, "[i+1],d", 0 }, +{ "ldsh", 0xc0500000, 0x01a82000, "[1+2],d", 0 }, +{ "ldsb", 0xc0480000, 0x01b0201f, "[1],d", 0 }, /* ldsb [rs1+%g0],d */ +{ "ldsb", 0xc0482000, 0x01b01fff, "[1],d", 0 }, /* ldsb [rs1+0],d */ +{ "ldsb", 0xc0482000, 0x01b00000, "[1+i],d", 0 }, +{ "ldsb", 0xc0482000, 0x01b00000, "[i+1],d", 0 }, +{ "ldsb", 0xc0480000, 0x01b02000, "[1+2],d", 0 }, +{ "ldub", 0xc0080000, 0x01f0201f, "[1],d", 0 }, /* ldub [rs1+%g0],d */ +{ "ldub", 0xc0082000, 0x01f01fff, "[1],d", 0 }, /* ldub [rs1+0],d */ +{ "ldub", 0xc0082000, 0x01f00000, "[1+i],d", 0 }, +{ "ldub", 0xc0082000, 0x01f00000, "[i+1],d", 0 }, +{ "ldub", 0xc0080000, 0x01f02000, "[1+2],d", 0 }, +{ "lduba", 0xc0880000, 0x0170201f, "[1]A,d", 0 }, /* lduba [rs1+%g0],d */ +{ "lduba", 0xc0880000, 0x01702000, "[1+2]A,d", 0 }, +{ "lduh", 0xc0102000, 0x01e80000, "[1+i],d", 0 }, +{ "lduh", 0xc0102000, 0x01e80000, "[i+1],d", 0 }, +{ "lduh", 0xc0100000, 0x01e8201f, "[1],d", 0 }, /* lduh [rs1+%g0],d */ +{ "lduh", 0xc0102000, 0x01e81fff, "[1],d", 0 }, /* lduh [rs1+0],d */ +{ "lduh", 0xc0100000, 0x01e82000, "[1+2],d", 0 }, + +{ "st", 0xc0200000, 0x01d8201f, "d,[1]", 0 }, /* st d,[rs1+%g0] */ +{ "st", 0xc0202000, 0x01d81fff, "d,[1]", 0 }, /* st d,[rs1+0] */ +{ "st", 0xc0202000, 0x01d80000, "d,[1+i]", 0 }, +{ "st", 0xc0202000, 0x01d80000, "d,[i+1]", 0 }, +{ "st", 0xc0200000, 0x01d82000, "d,[1+2]", 0 }, +{ "st", 0xc1200000, 0x00d8201f, "g,[1]", 0 }, /* st d[rs1+%g0] */ +{ "st", 0xc1202000, 0x00d81fff, "g,[1]", 0 }, /* st d,[rs1+0] */ +{ "st", 0xc1202000, 0x00d80000, "g,[1+i]", 0 }, +{ "st", 0xc1202000, 0x00d80000, "g,[i+1]", 0 }, +{ "st", 0xc1200000, 0x00d82000, "g,[1+2]", 0 }, +{ "st", 0xc1280000, 0x00d0201f, "F,[1]", 0 }, /* st %fsr,[rs1+%g0] */ +{ "st", 0xc1282000, 0x00d01fff, "F,[1]", 0 }, /* st %fsr,[rs1+0] */ +{ "st", 0xc1282000, 0x00d00000, "F,[1+i]", 0 }, +{ "st", 0xc1282000, 0x00d00000, "F,[i+1]", 0 }, +{ "st", 0xc1280000, 0x00d02000, "F,[1+2]", 0 }, +{ "st", 0xc1a00000, 0x0058201f, "D,[1]", 0 }, /* st d,[rs1+%g0] */ +{ "st", 0xc1a02000, 0x00581fff, "D,[1]", 0 }, /* st d,[rs1+0] */ +{ "st", 0xc1a02000, 0x00580000, "D,[1+i]", 0 }, +{ "st", 0xc1a02000, 0x00580000, "D,[i+1]", 0 }, +{ "st", 0xc1a00000, 0x00582000, "D,[1+2]", 0 }, +{ "st", 0xc1a80000, 0x0050201f, "C,[1]", 0 }, /* st d,[rs1+%g0] */ +{ "st", 0xc1a82000, 0x00501fff, "C,[1]", 0 }, /* st d,[rs1+0] */ +{ "st", 0xc1a82000, 0x00500000, "C,[1+i]", 0 }, +{ "st", 0xc1a82000, 0x00500000, "C,[i+1]", 0 }, +{ "st", 0xc1a80000, 0x00502000, "C,[1+2]", 0 }, +{ "sta", 0xc0a00000, 0x0108201f, "d,[1]A", 0 }, /* sta d,[rs1+%g0] */ +{ "sta", 0xc0a00000, 0x01082000, "d,[1+2]A", 0 }, + +{ "stb", 0xc0280000, 0x01d0201f, "d,[1]", 0 }, /* stb d,[rs1+%g0] */ +{ "stb", 0xc0282000, 0x01d01fff, "d,[1]", 0 }, /* stb d,[rs1+0] */ +{ "stb", 0xc0282000, 0x01d00000, "d,[1+i]", 0 }, +{ "stb", 0xc0282000, 0x01d00000, "d,[i+1]", 0 }, +{ "stb", 0xc0280000, 0x01d02000, "d,[1+2]", 0 }, +{ "stba", 0xc0a80000, 0x01002000, "d,[1+2]A", 0 }, +{ "stba", 0xc0a80000, 0x0100201f, "d,[1]A", 0 }, /* stba d,[rs1+%g0] */ + +{ "std", 0xc0380000, 0x01c0201f, "d,[1]", 0 }, /* std d,[rs1+%g0] */ +{ "std", 0xc0382000, 0x01c01fff, "d,[1]", 0 }, /* std d,[rs1+0] */ +{ "std", 0xc0382000, 0x01c00000, "d,[1+i]", 0 }, +{ "std", 0xc0382000, 0x01c00000, "d,[i+1]", 0 }, +{ "std", 0xc0380000, 0x01c02000, "d,[1+2]", 0 }, +{ "std", 0xc1380000, 0x00c0201f, "g,[1]", 0 }, /* std d,[rs1+%g0] */ +{ "std", 0xc1382000, 0x00c01fff, "g,[1]", 0 }, /* std d,[rs1+0] */ +{ "std", 0xc1382000, 0x00c00000, "g,[1+i]", 0 }, +{ "std", 0xc1382000, 0x00c00000, "g,[i+1]", 0 }, +{ "std", 0xc1380000, 0x00c02000, "g,[1+2]", 0 }, +{ "std", 0xc1300000, 0x00c8201f, "q,[1]", 0 }, /* std d,[rs1+%g0] */ +{ "std", 0xc1302000, 0x00c81fff, "q,[1]", 0 }, /* std d,[rs1+0] */ +{ "std", 0xc1302000, 0x00c80000, "q,[1+i]", 0 }, +{ "std", 0xc1302000, 0x00c80000, "q,[i+1]", 0 }, +{ "std", 0xc1300000, 0x00c82000, "q,[1+2]", 0 }, +{ "std", 0xc1b80000, 0x0040201f, "D,[1]", 0 }, /* std d,[rs1+%g0] */ +{ "std", 0xc1b82000, 0x00401fff, "D,[1]", 0 }, /* std d,[rs1+0] */ +{ "std", 0xc1b82000, 0x00400000, "D,[1+i]", 0 }, +{ "std", 0xc1b82000, 0x00400000, "D,[i+1]", 0 }, +{ "std", 0xc1b80000, 0x00402000, "D,[1+2]", 0 }, +{ "std", 0xc1b00000, 0x0048201f, "Q,[1]", 0 }, /* std d,[rs1+%g0] */ +{ "std", 0xc1b02000, 0x00481fff, "Q,[1]", 0 }, /* std d,[rs1+0] */ +{ "std", 0xc1b02000, 0x00480000, "Q,[1+i]", 0 }, +{ "std", 0xc1b02000, 0x00480000, "Q,[i+1]", 0 }, +{ "std", 0xc1b00000, 0x00482000, "Q,[1+2]", 0 }, +{ "stda", 0xc0b80000, 0x01402000, "d,[1+2]A", 0 }, +{ "stda", 0xc0b80000, 0x0140201f, "d,[1]A", 0 }, /* stda d,[rs1+%g0] */ + +{ "sth", 0xc0300000, 0x01c8201f, "d,[1]", 0 }, /* sth d,[rs1+%g0] */ +{ "sth", 0xc0302000, 0x01c81fff, "d,[1]", 0 }, /* sth d,[rs1+0] */ +{ "sth", 0xc0300000, 0x01c82000, "d,[1+2]", 0 }, +{ "sth", 0xc0302000, 0x01c80000, "d,[1+i]", 0 }, +{ "sth", 0xc0302000, 0x01c80000, "d,[i+1]", 0 }, +{ "stha", 0xc0b00000, 0x0148201f, "d,[1]A", 0 }, /* stha d,[rs1+%g0] */ +{ "stha", 0xc0b00000, 0x01482000, "d,[1+2]A", 0 }, + +{ "swap", 0xc0780000, 0x0180201f, "[1],d", 0 }, /* swap [rs1+%g0],d */ +{ "swap", 0xc0782000, 0x01801fff, "[1],d", 0 }, /* swap [rs1+0],d */ +{ "swap", 0xc0782000, 0x01800000, "[1+i],d", 0 }, +{ "swap", 0xc0782000, 0x01800000, "[i+1],d", 0 }, +{ "swap", 0xc0780000, 0x01802000, "[1+2],d", 0 }, +{ "swapa", 0xc0f80000, 0x01002000, "[1+2]A,d", 0 }, +{ "swapa", 0xc0f80000, 0x0100201f, "[1]A,d", 0 }, /* swapa [rs1+%g0],d */ + +{ "restore", 0x81e80000, 0x7e17e01f, "", 0 }, /* restore %g0,%g0,%g0 */ +{ "restore", 0x81e82000, 0x7e14dfff, "", 0 }, /* restore %g0,0,%g0 */ +{ "restore", 0x81e82000, 0x00000000, "1,i,d", 0 }, +{ "restore", 0x81e80000, 0x00000000, "1,2,d", 0 }, +{ "rett", 0x81c82000, 0x40300000, "1+i", F_DELAYED }, +{ "rett", 0x81c82000, 0x40300000, "i+1", F_DELAYED }, +{ "rett", 0x81c80000, 0x40302000, "1+2", F_DELAYED }, +{ "rett", 0x81c82000, 0x40301fff, "1", F_DELAYED}, /* rett X,0 */ +{ "rett", 0x81c80000, 0x4030201f, "1", F_DELAYED}, /* rett X,%g0 */ +{ "save", 0x81e02000, 0x40180000, "1,i,d", 0 }, +{ "save", 0x81e00000, 0x40180000, "1,2,d", 0 }, + +{ "ret", 0x81c7e008, 0x00001ff7, "", F_DELAYED }, /* jmpl %i7+8,%g0 */ +{ "retl", 0x81c3e008, 0x00001ff7, "", F_DELAYED }, /* jmpl %o7+8,%g0 */ + +{ "jmpl", 0x81c00000, 0x4038201f, "1,d", F_DELAYED }, /* jmpl rs1+%g0,d */ +{ "jmpl", 0x81c02000, 0x4037c000, "i,d", F_DELAYED }, /* jmpl %g0+i,d */ +{ "jmpl", 0x81c02000, 0x40380000, "1+i,d", F_DELAYED }, +{ "jmpl", 0x81c02000, 0x40380000, "i+1,d", F_DELAYED }, +{ "jmpl", 0x81c00000, 0x40382000, "1+2,d", F_DELAYED }, +{ "wr", 0x81982000, 0x40600000, "1,i,t", 0 }, +{ "wr", 0x81980000, 0x40600000, "1,2,t", 0 }, +{ "wr", 0x81902000, 0x40680000, "1,i,w", 0 }, +{ "wr", 0x81900000, 0x40680000, "1,2,w", 0 }, +{ "wr", 0x81882000, 0x40700000, "1,i,p", 0 }, +{ "wr", 0x81880000, 0x40700000, "1,2,p", 0 }, +{ "wr", 0x81802000, 0x40780000, "1,i,y", 0 }, +{ "wr", 0x81800000, 0x40780000, "1,2,y", 0 }, + +{ "rd", 0x81580000, 0x40a00000, "t,d", 0 }, +{ "rd", 0x81500000, 0x40a80000, "w,d", 0 }, +{ "rd", 0x81480000, 0x40b00000, "p,d", 0 }, +{ "rd", 0x81400000, 0x40b80000, "y,d", 0 }, + +{ "sra", 0x81382000, 0x00000000, "1,i,d", 0 }, +{ "sra", 0x81380000, 0x00000000, "1,2,d", 0 }, +{ "srl", 0x81302000, 0x40c80000, "1,i,d", 0 }, +{ "srl", 0x81300000, 0x40c80000, "1,2,d", 0 }, +{ "sll", 0x81282000, 0x40d00000, "1,i,d", 0 }, +{ "sll", 0x81280000, 0x40d00000, "1,2,d", 0 }, + +{ "mulscc", 0x81202000, 0x40d80000, "1,i,d", 0 }, +{ "mulscc", 0x81200000, 0x40d80000, "1,2,d", 0 }, + +{ "clr", 0x80100000, 0x4e87e01f, "d", F_ALIAS }, /* or %g0,%g0,d */ +{ "clr", 0x80102000, 0x41efdfff, "d", F_ALIAS }, /* or %g0,0,d */ +{ "clr", 0xc0200000, 0x3fd8001f, "[1]", F_ALIAS }, /* st %g0,[rs1+%g0] */ +{ "clr", 0xc0202000, 0x3fd81fff, "[1]", F_ALIAS }, /* st %g0,[rs1+0] */ +{ "clr", 0xc0202000, 0x3fd80000, "[1+i]", F_ALIAS }, +{ "clr", 0xc0202000, 0x3fd80000, "[i+1]", F_ALIAS }, +{ "clr", 0xc0200000, 0x3fd80000, "[1+2]", F_ALIAS }, + +{ "clrb", 0xc0280000, 0x3fd0001f, "[1]", F_ALIAS },/* stb %g0,[rs1+%g0] */ +{ "clrb", 0xc0282000, 0x3fd00000, "[1+i]", F_ALIAS }, +{ "clrb", 0xc0282000, 0x3fd00000, "[i+1]", F_ALIAS }, +{ "clrb", 0xc0280000, 0x3fd00000, "[1+2]", F_ALIAS }, + +{ "clrh", 0xc0300000, 0x3fc8001f, "[1]", F_ALIAS },/* sth %g0,[rs1+%g0] */ +{ "clrh", 0xc0300000, 0x3fc80000, "[1+2]", F_ALIAS }, +{ "clrh", 0xc0302000, 0x3fc80000, "[1+i]", F_ALIAS }, +{ "clrh", 0xc0302000, 0x3fc80000, "[i+1]", F_ALIAS }, + +{ "orncc", 0x80b02000, 0x04048000, "1,i,d", 0 }, +{ "orncc", 0x80b00000, 0x04048000, "1,2,d", 0 }, + +{ "tst", 0x80900000, 0x7f6fe000, "2", 0 }, /* orcc %g0, rs2, %g0 */ +{ "tst", 0x80900000, 0x7f68201f, "1", 0 }, /* orcc rs1, %g0, %g0 */ +{ "tst", 0x80902000, 0x7f681fff, "1", 0 }, /* orcc rs1, 0, %g0 */ + +{ "orcc", 0x80902000, 0x41680000, "1,i,d", 0 }, +{ "orcc", 0x80902000, 0x41680000, "i,1,d", 0 }, +{ "orcc", 0x80900000, 0x41680000, "1,2,d", 0 }, +{ "orn", 0x80302000, 0x41c80000, "1,i,d", 0 }, +{ "orn", 0x80300000, 0x41c80000, "1,2,d", 0 }, + +{ "mov", 0x81800000, 0x4078201f, "1,y", F_ALIAS }, /* wr rs1,%g0,%y */ +{ "mov", 0x81802000, 0x40781fff, "1,y", F_ALIAS }, /* wr rs1,0,%y */ +{ "mov", 0x81802000, 0x40780000, "i,y", F_ALIAS }, +{ "mov", 0x81400000, 0x40b80000, "y,d", F_ALIAS }, /* rd %y,d */ +{ "mov", 0x81980000, 0x4060201f, "1,t", F_ALIAS }, /* wr rs1,%g0,%tbr */ +{ "mov", 0x81982000, 0x40601fff, "1,t", F_ALIAS }, /* wr rs1,0,%tbr */ +{ "mov", 0x81982000, 0x40600000, "i,t", F_ALIAS }, +{ "mov", 0x81580000, 0x40a00000, "t,d", F_ALIAS }, /* rd %tbr,d */ +{ "mov", 0x81900000, 0x4068201f, "1,w", F_ALIAS }, /* wr rs1,%g0,%wim */ +{ "mov", 0x81902000, 0x40681fff, "1,w", F_ALIAS }, /* wr rs1,0,%wim */ +{ "mov", 0x81902000, 0x40680000, "i,w", F_ALIAS }, +{ "mov", 0x81500000, 0x40a80000, "w,d", F_ALIAS }, /* rd %wim,d */ +{ "mov", 0x81880000, 0x4070201f, "1,p", F_ALIAS }, /* wr rs1,%g0,%psr */ +{ "mov", 0x81882000, 0x40701fff, "1,p", F_ALIAS }, /* wr rs1,0,%psr */ +{ "mov", 0x81882000, 0x40700000, "i,p", F_ALIAS }, +{ "mov", 0x81480000, 0x40b00000, "p,d", F_ALIAS }, /* rd %psr,d */ + +{ "mov", 0x80102000, 0x41efc000, "i,d", 0 }, /* or %g0,i,d */ +{ "mov", 0x80100000, 0x41efe000, "2,d", 0 }, /* or %g0,rs2,d */ +{ "mov", 0x80102000, 0x41e81fff, "1,d", 0 }, /* or rs1,0,d */ +{ "mov", 0x80100000, 0x41e8201f, "1,d", 0 }, /* or rs1,%g0,d */ + +{ "or", 0x80102000, 0x40800000, "1,i,d", 0 }, +{ "or", 0x80102000, 0x40800000, "i,1,d", 0 }, +{ "or", 0x80100000, 0x40800000, "1,2,d", 0 }, + +{ "bset", 0x80102000, 0x40800000, "i,r", F_ALIAS },/* or rd,i,rd */ +{ "bset", 0x80100000, 0x40800000, "2,r", F_ALIAS },/* or rd,rs2,rd */ + +{ "andncc", 0x80a82000, 0x41500000, "1,i,d", 0 }, +{ "andncc", 0x80a80000, 0x41500000, "1,2,d", 0 }, +{ "andn", 0x80282000, 0x41d00000, "1,i,d", 0 }, +{ "andn", 0x80280000, 0x41d00000, "1,2,d", 0 }, + +{ "bclr", 0x80282000, 0x41d00000, "i,r", F_ALIAS },/* andn rd,i,rd */ +{ "bclr", 0x80280000, 0x41d00000, "2,r", F_ALIAS },/* andn rd,rs2,rd */ + +{ "cmp", 0x80a02000, 0x7d580000, "1,i", 0 }, /* subcc rs1,i,%g0 */ +{ "cmp", 0x80a00000, 0x7d580000, "1,2", 0 }, /* subcc rs1,rs2,%g0 */ + +{ "subcc", 0x80a02000, 0x41580000, "1,i,d", 0 }, +{ "subcc", 0x80a00000, 0x41580000, "1,2,d", 0 }, +{ "sub", 0x80202000, 0x41d80000, "1,i,d", 0 }, +{ "sub", 0x80200000, 0x41d80000, "1,2,d", 0 }, +{ "subx", 0x80602000, 0x41980000, "1,i,d", 0 }, +{ "subx", 0x80600000, 0x41980000, "1,2,d", 0 }, +{ "subxcc", 0x80e02000, 0x41180000, "1,i,d", 0 }, +{ "subxcc", 0x80e00000, 0x41180000, "1,2,d", 0 }, + +{ "andcc", 0x80882000, 0x41700000, "1,i,d", 0 }, +{ "andcc", 0x80882000, 0x41700000, "i,1,d", 0 }, +{ "andcc", 0x80880000, 0x41700000, "1,2,d", 0 }, +{ "and", 0x80082000, 0x41f00000, "1,i,d", 0 }, +{ "and", 0x80082000, 0x41f00000, "i,1,d", 0 }, +{ "and", 0x80080000, 0x41f00000, "1,2,d", 0 }, + +{ "inc", 0x80002001, 0x41f81ffe, "r", F_ALIAS }, /* add rs1,1,rsd */ +{ "inccc", 0x80802001, 0x41781ffe, "r", F_ALIAS }, /* addcc rd,1,rd */ +{ "dec", 0x80202001, 0x41d81ffe, "r", F_ALIAS }, /* sub rd,1,rd */ +{ "deccc", 0x80a02001, 0x41581ffe, "r", F_ALIAS }, /* subcc rd,1,rd */ + +{ "btst", 0x80882000, 0x41700000, "i,1", F_ALIAS },/* andcc rs1,i,%g0 */ +{ "btst", 0x80880000, 0x41700000, "1,2", F_ALIAS },/* andcc rs1,rs2,%0 */ + +{ "neg", 0x80200000, 0x41d80000, "r", F_ALIAS }, /* sub %0,rd,rd */ +{ "neg", 0x80200000, 0x41d80000, "2,d", F_ALIAS }, /* sub %0,rs2,rd */ + +{ "addxcc", 0x80c02000, 0x41380000, "1,i,d", 0 }, +{ "addxcc", 0x80c02000, 0x41380000, "i,1,d", 0 }, +{ "addxcc", 0x80c00000, 0x41380000, "1,2,d", 0 }, +{ "addcc", 0x80802000, 0x41780000, "1,i,d", 0 }, +{ "addcc", 0x80802000, 0x41780000, "i,1,d", 0 }, +{ "addcc", 0x80800000, 0x41780000, "1,2,d", 0 }, +{ "addx", 0x80402000, 0x41b80000, "1,i,d", 0 }, +{ "addx", 0x80402000, 0x41b80000, "i,1,d", 0 }, +{ "addx", 0x80400000, 0x41b80000, "1,2,d", 0 }, +{ "add", 0x80002000, 0x41f80000, "1,i,d", 0 }, +{ "add", 0x80002000, 0x41f80000, "i,1,d", 0 }, +{ "add", 0x80000000, 0x41f80000, "1,2,d", 0 }, + +{ "call", 0x9fc00000, 0x4038201f, "1", F_DELAYED }, /* jmpl rs1+%g0, %o7 */ +{ "call", 0x9fc00000, 0x4038201f, "1,#", F_DELAYED }, +{ "call", 0x40000000, 0x80000000, "L", F_DELAYED }, +{ "call", 0x40000000, 0x80000000, "L,#", F_DELAYED }, + +{ "jmp", 0x81c00000, 0x7e38201f, "1", F_DELAYED }, /* jmpl rs1+%g0,%g0 */ +{ "jmp", 0x81c02000, 0x7e3fc000, "i", F_DELAYED }, /* jmpl %g0+i,%g0 */ +{ "jmp", 0x81c00000, 0x7e382000, "1+2", F_DELAYED }, /* jmpl rs1+rs2,%g0 */ +{ "jmp", 0x81c02000, 0x7e380000, "1+i", F_DELAYED }, /* jmpl rs1+i,%g0 */ +{ "jmp", 0x81c02000, 0x7e380000, "i+1", F_DELAYED }, /* jmpl i+rs1,%g0 */ + +{ "nop", 0x01000000, 0xfeffffff, "", 0 }, /* sethi 0, %g0 */ + +{ "set", 0x01000000, 0xc0c00000, "Sh,d", F_ALIAS }, + +{ "sethi", 0x01000000, 0xc0c00000, "h,d", 0 }, + +{ "taddcctv", 0x81102000, 0x40e00000, "1,i,d", 0 }, +{ "taddcctv", 0x81100000, 0x40e00000, "1,2,d", 0 }, +{ "taddcc", 0x81002000, 0x40f80000, "1,i,d", 0 }, +{ "taddcc", 0x81000000, 0x40f80000, "1,2,d", 0 }, + +/* Conditional instructions. + + Because this part of the table was such a mess earlier, I have + macrofied it so that all the branches and traps are generated from + a single-line description of each condition value. */ + +#define ANNUL 0x20000000 +#define IMMED 0x00002000 +#define RS1_G0 0x0007C000 +#define RS2_G0 0x0000001F + +/* Define two branches -- one annulled, one without */ +#define br(opcode, mask, lose, flags) \ + { opcode, mask+ANNUL, lose, ",al", flags }, \ + { opcode, mask , lose, "l", flags } + +/* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */ +#define tr(opcode, mask, lose, flags) \ + {opcode, mask+IMMED, lose+RS1_G0 , "i", flags }, /* %g0 + imm */ \ + {opcode, mask+IMMED, lose , "1+i", flags }, /* rs1 + imm */ \ + {opcode, mask , lose+IMMED , "1+2", flags }, /* rs1 + rs2 */ \ + {opcode, mask , lose+IMMED+RS2_G0, "1", flags } /* rs1 + %g0 */ + +/* Define both branches and traps based on condition mask */ +#ifdef __STDC__ +#define cond(bop, top, mask, flags) \ + br(#bop, 0x00800000+(mask << 25), 0xC1400000, F_DELAYED|flags), \ + tr(#top, 0x81d00000+(mask << 25), 0x40280000, flags) +#else +#define cond(bop, top, mask, flags) \ + br("bop", 0x00800000+(mask << 25), 0xC1400000, F_DELAYED|flags), \ + tr("top", 0x81d00000+(mask << 25), 0x40280000, flags) +#endif + +/* Define all the conditions, all the branches, all the traps. */ +cond (bvc, tvc, 0xF, 0), +cond (bvs, tvs, 0x7, 0), +cond (bpos, tpos, 0xE, 0), +cond (bneg, tneg, 0x6, 0), +cond (bcc, tcc, 0xD, 0), +cond (bcs, tcs, 0x5, 0), +cond (blu, tlu, 0x5, F_ALIAS), /* for cs */ +cond (bgeu, tgeu, 0xD, F_ALIAS), /* for cc */ +cond (bgu, tgu, 0xC, 0), +cond (bleu, tleu, 0x4, 0), +cond (bge, tge, 0xB, 0), +cond (bl, tl, 0x3, 0), +cond (bg, tg, 0xA, 0), +cond (ble, tle, 0x2, 0), +cond (be, te, 0x1, 0), +cond (bz, tz, 0x1, F_ALIAS), /* for e */ +cond (bne, tne, 0x9, 0), +cond (bnz, tnz, 0x9, F_ALIAS), /* for ne */ +cond (b, t, 0x8, 0), +cond (ba, ta, 0x8, F_ALIAS), /* for nothing */ +cond (bn, tn, 0x0, 0), + +#undef cond +#undef br +#undef tr + +{ "tsubcc", 0x81080000, 0x40f00000, "1,2,d", 0 }, +{ "tsubcc", 0x81082000, 0x40f00000, "1,i,d", 0 }, +{ "tsubcctv", 0x80580000, 0x40a00000, "1,2,d", 0 }, +{ "tsubcctv", 0x80582000, 0x40a00000, "1,i,d", 0 }, + +{ "unimp", 0x00000000, 0xFFFFFFFF, "l", 0 }, + +{ "iflush", 0x81d80000, 0x40202000, "1+2", 0 }, +{ "iflush", 0x81d82000, 0x40200000, "1+i", 0 }, + +{ "xnorcc", 0x80b80000, 0x41400000, "1,2,d", 0 }, +{ "xnorcc", 0x80b82000, 0x41400000, "1,i,d", 0 }, +{ "xnorcc", 0x80b82000, 0x41400000, "i,1,d", 0 }, +{ "xorcc", 0x80980000, 0x41600000, "1,2,d", 0 }, +{ "xorcc", 0x80982000, 0x41600000, "1,i,d", 0 }, +{ "xorcc", 0x80982000, 0x41600000, "i,1,d", 0 }, +{ "xnor", 0x80380000, 0x41c00000, "1,2,d", 0 }, +{ "xnor", 0x80382000, 0x41c00000, "1,i,d", 0 }, +{ "xnor", 0x80382000, 0x41c00000, "i,1,d", 0 }, +{ "xor", 0x80180000, 0x41e00000, "1,2,d", 0 }, +{ "xor", 0x80182000, 0x41e00000, "1,i,d", 0 }, +{ "xor", 0x80182000, 0x41e00000, "i,1,d", 0 }, + +{ "not", 0x80380000, 0x41c00000, "r", F_ALIAS }, /* xnor rd,%0,rd */ +{ "not", 0x80380000, 0x41c00000, "1,d", F_ALIAS }, /* xnor rs1,%0,rd */ + +{ "btog", 0x80180000, 0x41e02000, "2,r", F_ALIAS }, /* xor rd,rs2,rd */ +{ "btog", 0x80182000, 0x41e00000, "i,r", F_ALIAS }, /* xor rd,i,rd */ + +{ "fpop1", 0x81a00000, 0x40580000, "[1+2],d", 0 }, +{ "fpop2", 0x81a80000, 0x40500000, "[1+2],d", 0 }, + +/* Someday somebody should give these the same treatment as the branches + above. FIXME someday. */ + +{ "fb", 0x31800000, 0xc0400000, ",al", F_DELAYED }, +{ "fb", 0x11800000, 0xc0400000, "l", F_DELAYED }, +{ "fba", 0x31800000, 0xc0400000, ",al", F_DELAYED|F_ALIAS }, +{ "fba", 0x11800000, 0xc0400000, "l", F_DELAYED|F_ALIAS }, +{ "fbn", 0x21800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbn", 0x01800000, 0xc0400000, "l", F_DELAYED }, +{ "fbu", 0x2f800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbu", 0x0f800000, 0xc0400000, "l", F_DELAYED }, +{ "fbg", 0x2d800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbg", 0x0d800000, 0xc0400000, "l", F_DELAYED }, +{ "fbug", 0x2b800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbug", 0x0b800000, 0xc0400000, "l", F_DELAYED }, +{ "fbl", 0x29800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbl", 0x09800000, 0xc0400000, "l", F_DELAYED }, +{ "fbul", 0x27800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbul", 0x07800000, 0xc0400000, "l", F_DELAYED }, +{ "fblg", 0x25800000, 0xc0400000, ",al", F_DELAYED }, +{ "fblg", 0x05800000, 0xc0400000, "l", F_DELAYED }, +{ "fbne", 0x23800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbne", 0x03800000, 0xc0400000, "l", F_DELAYED }, +{ "fbe", 0x33800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbe", 0x13800000, 0xc0400000, "l", F_DELAYED }, +{ "fbue", 0x35800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbue", 0x15800000, 0xc0400000, "l", F_DELAYED }, +{ "fbge", 0x37800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbge", 0x17800000, 0xc0400000, "l", F_DELAYED }, +{ "fbuge", 0x39800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbuge", 0x19800000, 0xc0400000, "l", F_DELAYED }, +{ "fble", 0x3b800000, 0xc0400000, ",al", F_DELAYED }, +{ "fble", 0x1b800000, 0xc0400000, "l", F_DELAYED }, +{ "fbule", 0x3d800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbule", 0x1d800000, 0xc0400000, "l", F_DELAYED }, +{ "fbo", 0x3f800000, 0xc0400000, ",al", F_DELAYED }, +{ "fbo", 0x1f800000, 0xc0400000, "l", F_DELAYED }, + +{ "cba", 0x31c00000, 0xce000000, ",al", F_DELAYED }, +{ "cba", 0x11c00000, 0xce000000, "l", F_DELAYED }, +{ "cbn", 0x21c00000, 0xde000000, ",al", F_DELAYED }, +{ "cbn", 0x01c00000, 0xde000000, "l", F_DELAYED }, +{ "cb3", 0x2fc00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb3", 0x0fc00000, 0xc0000000, "l", F_DELAYED }, +{ "cb2", 0x2dc00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb2", 0x0dc00000, 0xc0000000, "l", F_DELAYED }, +{ "cb23", 0x2bc00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb23", 0x0bc00000, 0xc0000000, "l", F_DELAYED }, +{ "cb1", 0x29c00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb1", 0x09c00000, 0xc0000000, "l", F_DELAYED }, +{ "cb13", 0x27c00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb13", 0x07c00000, 0xc0000000, "l", F_DELAYED }, +{ "cb12", 0x25c00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb12", 0x05c00000, 0xc0000000, "l", F_DELAYED }, +{ "cb123", 0x23c00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb123", 0x03c00000, 0xc0000000, "l", F_DELAYED }, +{ "cb0", 0x33c00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb0", 0x13c00000, 0xc0000000, "l", F_DELAYED }, +{ "cb03", 0x35c00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb03", 0x15c00000, 0xc0000000, "l", F_DELAYED }, +{ "cb02", 0x37c00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb02", 0x17c00000, 0xc0000000, "l", F_DELAYED }, +{ "cb023", 0x39c00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb023", 0x19c00000, 0xc0000000, "l", F_DELAYED }, +{ "cb01", 0x3bc00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb01", 0x1bc00000, 0xc0000000, "l", F_DELAYED }, +{ "cb013", 0x3dc00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb013", 0x1dc00000, 0xc0000000, "l", F_DELAYED }, +{ "cb012", 0x3fc00000, 0xc0000000, ",al", F_DELAYED }, +{ "cb012", 0x1fc00000, 0xc0000000, "l", F_DELAYED }, + +{ "fstoi", 0x81a01a20, 0x400025c0, "f,g", 0 }, +{ "fdtoi", 0x81a01a40, 0x400025a0, "f,g", 0 }, +{ "fxtoi", 0x81a01a60, 0x40002580, "f,g", 0 }, + +{ "fitox", 0x81a01980, 0x40002660, "f,g", 0 }, +{ "fitod", 0x81a01900, 0x400026e0, "f,g", 0 }, +{ "fitos", 0x81a01880, 0x40002660, "f,g", 0 }, + +{ "fstod", 0x81a01920, 0x400026c0, "f,g", 0 }, +{ "fstox", 0x81a019a0, 0x40002640, "f,g", 0 }, +{ "fdtos", 0x81a018c0, 0x40002720, "f,g", 0 }, +{ "fdtox", 0x81a019c0, 0x40002620, "f,g", 0 }, +{ "fxtos", 0x81a018e0, 0x40002700, "f,g", 0 }, +{ "fxtod", 0x81a01960, 0x40002680, "f,g", 0 }, + +{ "fdivx", 0x81a009e0, 0x40083600, "e,f,g", 0 }, +{ "fdivd", 0x81a009c0, 0x40003620, "e,f,g", 0 }, +{ "fdivs", 0x81a009a0, 0x40003640, "e,f,g", 0 }, + +{ "fmuls", 0x81a00920, 0x400036c0, "e,f,g", 0 }, +{ "fmuld", 0x81a00940, 0x400036a0, "e,f,g", 0 }, +{ "fmulx", 0x81a00960, 0x40003680, "e,f,g", 0 }, + +{ "fsqrts", 0x81a00520, 0x40003ac0, "f,g", 0 }, +{ "fsqrtd", 0x81a00540, 0x40003aa8, "f,g", 0 }, +{ "fsqrtx", 0x81a00560, 0x40003a80, "f,g", 0 }, + +{ "fabss", 0x81a00120, 0x40003ec0, "f,g", 0 }, +{ "fnegs", 0x81a000a0, 0x40003f40, "f,g", 0 }, +{ "fmovs", 0x81a00020, 0x40003fc0, "f,g", 0 }, + +{ "fsubx", 0x81a008e0, 0x40003700, "e,f,g", 0 }, +{ "fsubd", 0x81a008c0, 0x40003720, "e,f,g", 0 }, +{ "fsubs", 0x81a008a0, 0x40003740, "e,f,g", 0 }, + +{ "faddx", 0x81a00860, 0x40003780, "e,f,g", 0 }, +{ "faddd", 0x81a00840, 0x400037a0, "e,f,g", 0 }, +{ "fadds", 0x81a00820, 0x400037c0, "e,f,g", 0 }, + +{ "fcmpex", 0x81a80ae0, 0x40003500, "e,f", 0 }, +{ "fcmped", 0x81a80ac0, 0x40003520, "e,f", 0 }, +{ "fcmpes", 0x81a80aa0, 0x40003540, "e,f", 0 }, +{ "fcmpx", 0x81a80a60, 0x40003580, "e,f", 0 }, +{ "fcmpd", 0x81a80a40, 0x400035a0, "e,f", 0 }, +{ "fcmps", 0x81a80a20, 0x400035c0, "e,f", 0 }, + +{ "cpop1", 0x81b00000, 0x40480000, "[1+2],d", 0 }, +{ "cpop2", 0x81b80000, 0x40400000, "[1+2],d", 0 }, +}; + +#define NUMOPCODES ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])) + diff --git a/gdb/sparc-pinsn.c b/gdb/sparc-pinsn.c new file mode 100644 index 00000000000..39d62af29f6 --- /dev/null +++ b/gdb/sparc-pinsn.c @@ -0,0 +1,465 @@ +/* Disassembler for the sparc. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB, the GNU disassembler. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "sparc-opcode.h" +#include "gdbcore.h" +#include "string.h" +#include "target.h" + +extern void qsort (); + + +extern char *reg_names[]; +#define freg_names (®_names[4 * 8]) + +union sparc_insn + { + unsigned long int code; + struct + { + unsigned int OP:2; +#define op ldst.OP + unsigned int RD:5; +#define rd ldst.RD + unsigned int op3:6; + unsigned int RS1:5; +#define rs1 ldst.RS1 + unsigned int i:1; + unsigned int ASI:8; +#define asi ldst.ASI + unsigned int RS2:5; +#define rs2 ldst.RS2 +#define shcnt rs2 + } ldst; + struct + { + unsigned int OP:2, RD:5, op3:6, RS1:5, i:1; + unsigned int IMM13:13; +#define imm13 IMM13.IMM13 + } IMM13; + struct + { + unsigned int OP:2; + unsigned int a:1; + unsigned int cond:4; + unsigned int op2:3; + unsigned int DISP22:22; +#define disp22 branch.DISP22 + } branch; +#define imm22 disp22 + struct + { + unsigned int OP:2; + unsigned int DISP30:30; +#define disp30 call.DISP30 + } call; + }; + +/* Nonzero if INSN is the opcode for a delayed branch. */ +static int +is_delayed_branch (insn) + union sparc_insn insn; +{ + unsigned int i; + + for (i = 0; i < NUMOPCODES; ++i) + { + const struct sparc_opcode *opcode = &sparc_opcodes[i]; + if ((opcode->match & insn.code) == opcode->match + && (opcode->lose & insn.code) == 0) + return (opcode->flags & F_DELAYED); + } + return 0; +} + +static int opcodes_sorted = 0; + +/* Print one instruction from MEMADDR on STREAM. */ +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + union sparc_insn insn; + + register unsigned int i; + + if (!opcodes_sorted) + { + static int compare_opcodes (); + qsort ((char *) sparc_opcodes, NUMOPCODES, + sizeof (sparc_opcodes[0]), compare_opcodes); + opcodes_sorted = 1; + } + + read_memory (memaddr, &insn, sizeof (insn)); + + for (i = 0; i < NUMOPCODES; ++i) + { + const struct sparc_opcode *opcode = &sparc_opcodes[i]; + if ((opcode->match & insn.code) == opcode->match + && (opcode->lose & insn.code) == 0) + { + /* Nonzero means that we have found an instruction which has + the effect of adding or or'ing the imm13 field to rs1. */ + int imm_added_to_rs1 = 0; + + /* Nonzero means that we have found a plus sign in the args + field of the opcode table. */ + int found_plus = 0; + + /* Do we have an 'or' instruction where rs1 is the same + as rsd, and which has the i bit set? */ + if (opcode->match == 0x80102000 + && insn.rs1 == insn.rd) + imm_added_to_rs1 = 1; + + if (insn.rs1 != insn.rd + && strchr (opcode->args, 'r') != 0) + /* Can't do simple format if source and dest are different. */ + continue; + + fputs_filtered (opcode->name, stream); + + { + register const char *s; + + if (opcode->args[0] != ',') + fputs_filtered (" ", stream); + for (s = opcode->args; *s != '\0'; ++s) + { + if (*s == ',') + { + fputs_filtered (",", stream); + ++s; + if (*s == 'a') + { + fputs_filtered ("a", stream); + ++s; + } + fputs_filtered (" ", stream); + } + + switch (*s) + { + case '+': + found_plus = 1; + + /* note fall-through */ + default: + fprintf_filtered (stream, "%c", *s); + break; + + case '#': + fputs_filtered ("0", stream); + break; + +#define reg(n) fprintf_filtered (stream, "%%%s", reg_names[n]) + case '1': + case 'r': + reg (insn.rs1); + break; + + case '2': + reg (insn.rs2); + break; + + case 'd': + reg (insn.rd); + break; +#undef reg + +#define freg(n) fprintf_filtered (stream, "%%%s", freg_names[n]) + case 'e': + freg (insn.rs1); + break; + + case 'f': + freg (insn.rs2); + break; + + case 'g': + freg (insn.rd); + break; +#undef freg + +#define creg(n) fprintf_filtered (stream, "%%c%u", (unsigned int) (n)) + case 'b': + creg (insn.rs1); + break; + + case 'c': + creg (insn.rs2); + break; + + case 'D': + creg (insn.rd); + break; +#undef creg + + case 'h': + fprintf_filtered (stream, "%%hi(%#x)", + (int) insn.imm22 << 10); + break; + + case 'i': + { + /* We cannot trust the compiler to sign-extend + when extracting the bitfield, hence the shifts. */ + int imm = ((int) insn.imm13 << 19) >> 19; + + /* Check to see whether we have a 1+i, and take + note of that fact. + + Note: because of the way we sort the table, + we will be matching 1+i rather than i+1, + so it is OK to assume that i is after +, + not before it. */ + if (found_plus) + imm_added_to_rs1 = 1; + + if (imm <= 9) + fprintf_filtered (stream, "%d", imm); + else + fprintf_filtered (stream, "%#x", imm); + } + break; + + case 'L': + print_address ((CORE_ADDR) memaddr + insn.disp30 * 4, + stream); + break; + + case 'l': + if ((insn.code >> 22) == 0) + /* Special case for `unimp'. Don't try to turn + it's operand into a function offset. */ + fprintf_filtered (stream, "%#x", + (int) (((int) insn.disp22 << 10) >> 10)); + else + /* We cannot trust the compiler to sign-extend + when extracting the bitfield, hence the shifts. */ + print_address ((CORE_ADDR) + (memaddr + + (((int) insn.disp22 << 10) >> 10) * 4), + stream); + break; + + case 'A': + fprintf_filtered (stream, "(%d)", (int) insn.asi); + break; + + case 'C': + fputs_filtered ("%csr", stream); + break; + + case 'F': + fputs_filtered ("%fsr", stream); + break; + + case 'p': + fputs_filtered ("%psr", stream); + break; + + case 'q': + fputs_filtered ("%fq", stream); + break; + + case 'Q': + fputs_filtered ("%cq", stream); + break; + + case 't': + fputs_filtered ("%tbr", stream); + break; + + case 'w': + fputs_filtered ("%wim", stream); + break; + + case 'y': + fputs_filtered ("%y", stream); + break; + } + } + } + + /* If we are adding or or'ing something to rs1, then + check to see whether the previous instruction was + a sethi to the same register as in the sethi. + If so, attempt to print the result of the add or + or (in this context add and or do the same thing) + and its symbolic value. */ + if (imm_added_to_rs1) + { + union sparc_insn prev_insn; + int errcode; + + errcode = target_read_memory (memaddr - 4, + (char *)&prev_insn, sizeof (prev_insn)); + + if (errcode == 0) + { + /* If it is a delayed branch, we need to look at the + instruction before the delayed branch. This handles + sequences such as + + sethi %o1, %hi(_foo), %o1 + call _printf + or %o1, %lo(_foo), %o1 + */ + + if (is_delayed_branch (prev_insn)) + errcode = target_read_memory + (memaddr - 8, (char *)&prev_insn, sizeof (prev_insn)); + } + + /* If there was a problem reading memory, then assume + the previous instruction was not sethi. */ + if (errcode == 0) + { + /* Is it sethi to the same register? */ + if ((prev_insn.code & 0xc1c00000) == 0x01000000 + && prev_insn.rd == insn.rs1) + { + fprintf_filtered (stream, "\t! "); + /* We cannot trust the compiler to sign-extend + when extracting the bitfield, hence the shifts. */ + print_address (((int) prev_insn.imm22 << 10) + | (insn.imm13 << 19) >> 19, stream); + } + } + } + + return sizeof (insn); + } + } + + printf_filtered ("%#8x", insn.code); + return sizeof (insn); +} + + +/* Compare opcodes A and B. */ + +static int +compare_opcodes (a, b) + char *a, *b; +{ + struct sparc_opcode *op0 = (struct sparc_opcode *) a; + struct sparc_opcode *op1 = (struct sparc_opcode *) b; + unsigned long int match0 = op0->match, match1 = op1->match; + unsigned long int lose0 = op0->lose, lose1 = op1->lose; + register unsigned int i; + + /* If a bit is set in both match and lose, there is something + wrong with the opcode table. */ + if (match0 & lose0) + { + fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n", + op0->name, match0, lose0); + op0->lose &= ~op0->match; + lose0 = op0->lose; + } + + if (match1 & lose1) + { + fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n", + op1->name, match1, lose1); + op1->lose &= ~op1->match; + lose1 = op1->lose; + } + + /* Because the bits that are variable in one opcode are constant in + another, it is important to order the opcodes in the right order. */ + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (match0 & x) != 0; + int x1 = (match1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (lose0 & x) != 0; + int x1 = (lose1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + /* They are functionally equal. So as long as the opcode table is + valid, we can put whichever one first we want, on aesthetic grounds. */ + + /* Our first aesthetic ground is that aliases defer to real insns. */ + { + int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS); + if (alias_diff != 0) + /* Put the one that isn't an alias first. */ + return alias_diff; + } + + /* Except for the above aliases, two "identical" instructions had + better have the same opcode. This is a sanity check on the table. */ + if (0 != strcmp (op0->name, op1->name)) + fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n", + op0->name, op1->name); + + /* Fewer arguments are preferred. */ + { + int length_diff = strlen (op0->args) - strlen (op1->args); + if (length_diff != 0) + /* Put the one with fewer arguments first. */ + return length_diff; + } + + /* Put 1+i before i+1. */ + { + char *p0 = (char *) strchr(op0->args, '+'); + char *p1 = (char *) strchr(op1->args, '+'); + + if (p0 && p1) + { + /* There is a plus in both operands. Note that a plus + sign cannot be the first character in args, + so the following [-1]'s are valid. */ + if (p0[-1] == 'i' && p1[1] == 'i') + /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ + return 1; + if (p0[1] == 'i' && p1[-1] == 'i') + /* op0 is 1+i and op1 is i+1, so op0 goes first. */ + return -1; + } + } + + /* They are, as far as we can tell, identical. + Since qsort may have rearranged the table partially, there is + no way to tell which one was first in the opcode table as + written, so just say there are equal. */ + return 0; +} diff --git a/gdb/sparc-xdep.c b/gdb/sparc-xdep.c new file mode 100644 index 00000000000..89fcb8d0a97 --- /dev/null +++ b/gdb/sparc-xdep.c @@ -0,0 +1,298 @@ +/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger, for SPARC host systems. + + Copyright (C) 1986, 1987, 1989, 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "tm-sparc.h" +#include "param-no-tm.h" +#include "inferior.h" +#include "target.h" + +#include +#include /* For L_SET */ + +#include +#include + +#include "gdbcore.h" +#include + +extern char register_valid[]; + +/* Fetch one or more registers from the inferior. REGNO == -1 to get + them all. We actually fetch more than requested, when convenient, + marking them as valid so we won't fetch them again. */ +void +fetch_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + int i; + + /* We should never be called with deferred stores, because a prerequisite + for writing regs is to have fetched them all (PREPARE_TO_STORE), sigh. */ + if (deferred_stores) abort(); + + DO_DEFERRED_STORES; + + /* Global and Out regs are fetched directly, as well as the control + registers. If we're getting one of the in or local regs, + and the stack pointer has not yet been fetched, + we have to do that first, since they're found in memory relative + to the stack pointer. */ + if (regno < O7_REGNUM /* including -1 */ + || regno >= Y_REGNUM + || (!register_valid[SP_REGNUM] && regno < I7_REGNUM)) + { + if (0 != ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers)) + perror("ptrace_getregs"); + + registers[REGISTER_BYTE (0)] = 0; + bcopy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (1)], 15 * REGISTER_RAW_SIZE (G0_REGNUM)); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y; + + for (i = G0_REGNUM; i <= O7_REGNUM; i++) + register_valid[i] = 1; + register_valid[Y_REGNUM] = 1; + register_valid[PS_REGNUM] = 1; + register_valid[PC_REGNUM] = 1; + register_valid[NPC_REGNUM] = 1; + /* If we don't set these valid, read_register_bytes() rereads + all the regs every time it is called! FIXME. */ + register_valid[WIM_REGNUM] = 1; /* Not true yet, FIXME */ + register_valid[TBR_REGNUM] = 1; /* Not true yet, FIXME */ + register_valid[FPS_REGNUM] = 1; /* Not true yet, FIXME */ + register_valid[CPS_REGNUM] = 1; /* Not true yet, FIXME */ + } + + /* Floating point registers */ + if (regno == -1 || (regno >= FP0_REGNUM && regno <= FP0_REGNUM + 31)) + { + if (0 != ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers)) + perror("ptrace_getfpregs"); + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fpu_fr); + /* bcopy (&inferior_fp_registers.Fpu_fsr, + ®isters[REGISTER_BYTE (FPS_REGNUM)], + sizeof (FPU_FSR_TYPE)); FIXME??? -- gnu@cyg */ + for (i = FP0_REGNUM; i <= FP0_REGNUM+31; i++) + register_valid[i] = 1; + register_valid[FPS_REGNUM] = 1; + } + + /* These regs are saved on the stack by the kernel. Only read them + all (16 ptrace calls!) if we really need them. */ + if (regno == -1) + { + target_xfer_memory (*(CORE_ADDR*)®isters[REGISTER_BYTE (SP_REGNUM)], + ®isters[REGISTER_BYTE (L0_REGNUM)], + 16*REGISTER_RAW_SIZE (L0_REGNUM), 0); + for (i = L0_REGNUM; i <= I7_REGNUM; i++) + register_valid[i] = 1; + } + else if (regno >= L0_REGNUM && regno <= I7_REGNUM) + { + CORE_ADDR sp = *(CORE_ADDR*)®isters[REGISTER_BYTE (SP_REGNUM)]; + i = REGISTER_BYTE (regno); + if (register_valid[regno]) + printf("register %d valid and read\n", regno); + target_xfer_memory (sp + i - REGISTER_BYTE (L0_REGNUM), + ®isters[i], REGISTER_RAW_SIZE (regno), 0); + register_valid[regno] = 1; + } +} + +/* 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). */ + +#define INT_REGS 1 +#define STACK_REGS 2 +#define FP_REGS 4 +int deferred_stores = 0; /* Cumulates stores we want to do eventually. */ + +int +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + int wanna_store = INT_REGS + STACK_REGS + FP_REGS; + + /* First decide which pieces of machine-state we need to modify. + Default for regno == -1 case is all pieces. */ + if (regno >= 0) + if (FP0_REGNUM <= regno && regno < FP0_REGNUM + 32) + { + wanna_store = FP_REGS; + } + else + { + if (regno == SP_REGNUM) + wanna_store = INT_REGS + STACK_REGS; + else if (regno < L0_REGNUM || regno > I7_REGNUM) + wanna_store = INT_REGS; + else + wanna_store = STACK_REGS; + } + + /* See if we're forcing the stores to happen now, or deferring. */ + if (regno == -2) + { + wanna_store = deferred_stores; + deferred_stores = 0; + } + else + { + if (wanna_store == STACK_REGS) + { + /* Fall through and just store one stack reg. If we deferred + it, we'd have to store them all, or remember more info. */ + } + else + { + deferred_stores |= wanna_store; + return 0; + } + } + + if (wanna_store & STACK_REGS) + { + CORE_ADDR sp = *(CORE_ADDR *)®isters[REGISTER_BYTE (SP_REGNUM)]; + + if (regno < 0 || regno == SP_REGNUM) + { + if (!register_valid[L0_REGNUM+5]) abort(); + target_xfer_memory (sp, + ®isters[REGISTER_BYTE (L0_REGNUM)], + 16*REGISTER_RAW_SIZE (L0_REGNUM), 1); + } + else + { + if (!register_valid[regno]) abort(); + target_xfer_memory (sp + REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM), + ®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE (regno), 1); + } + + } + + if (wanna_store & INT_REGS) + { + if (!register_valid[G1_REGNUM]) abort(); + + bcopy (®isters[REGISTER_BYTE (G1_REGNUM)], + &inferior_registers.r_g1, 15 * REGISTER_RAW_SIZE (G1_REGNUM)); + + inferior_registers.r_ps = + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + inferior_registers.r_npc = + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)]; + inferior_registers.r_y = + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)]; + + if (0 != ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers)) + perror("ptrace_setregs"); + } + + if (wanna_store & FP_REGS) + { + if (!register_valid[FP0_REGNUM+9]) abort(); + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], + &inferior_fp_registers, + sizeof inferior_fp_registers.fpu_fr); + +/* bcopy (®isters[REGISTER_BYTE (FPS_REGNUM)], + &inferior_fp_registers.Fpu_fsr, + sizeof (FPU_FSR_TYPE)); +****/ + if (0 != + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers)) + perror("ptrace_setfpregs"); + } + return 0; +} + +void +fetch_core_registers (core_reg_sect, core_reg_size, which) + char *core_reg_sect; + unsigned core_reg_size; + int which; +{ + + if (which == 0) { + + /* Integer registers */ + +#define gregs ((struct regs *)core_reg_sect) + /* G0 *always* holds 0. */ + *(int *)®isters[REGISTER_BYTE (0)] = 0; + + /* The globals and output registers. */ + bcopy (&gregs->r_g1, + ®isters[REGISTER_BYTE (G1_REGNUM)], + 15 * REGISTER_RAW_SIZE (G1_REGNUM)); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = gregs->r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = gregs->r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = gregs->r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = gregs->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 error + from blowing away the stack pointer (as is possible) then this + won't work, but it's worth the try. */ + { + int sp; + + sp = *(int *)®isters[REGISTER_BYTE (SP_REGNUM)]; + if (0 != target_read_memory (sp, ®isters[REGISTER_BYTE (L0_REGNUM)], + 16 * REGISTER_RAW_SIZE (L0_REGNUM))) + { + /* fprintf so user can still use gdb */ + fprintf (stderr, + "Couldn't read input and local registers from core file\n"); + } + } + } else if (which == 2) { + + /* Floating point registers */ + +#define fpuregs ((struct fpu *) core_reg_sect) + if (core_reg_size >= sizeof (struct fpu)) + { + bcopy (fpuregs->fpu_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof (fpuregs->fpu_regs)); + bcopy (&fpuregs->fpu_fsr, + ®isters[REGISTER_BYTE (FPS_REGNUM)], + sizeof (FPU_FSR_TYPE)); + } + else + fprintf (stderr, "Couldn't read float regs from core file\n"); + } +} diff --git a/gdb/stab.def b/gdb/stab.def new file mode 100755 index 00000000000..58364e14229 --- /dev/null +++ b/gdb/stab.def @@ -0,0 +1,182 @@ +/* Table of DBX symbol codes for the GNU system. + Copyright (C) 1988 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Global variable. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_GSYM, 0x20, "GSYM") + +/* Function name for BSD Fortran. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_FNAME, 0x22, "FNAME") + +/* Function name or text-segment variable for C. Value is its address. + Desc is supposedly starting line number, but GCC doesn't set it + and DBX seems not to miss it. */ +__define_stab (N_FUN, 0x24, "FUN") + +/* Data-segment variable with internal linkage. Value is its address. */ +__define_stab (N_STSYM, 0x26, "STSYM") + +/* BSS-segment variable with internal linkage. Value is its address. */ +__define_stab (N_LCSYM, 0x28, "LCSYM") + +/* Name of main routine. Only the name is significant. + This is not used in C. */ +__define_stab (N_MAIN, 0x2a, "MAIN") + +/* Register variable. Value is number of register. */ +__define_stab (N_RSYM, 0x40, "RSYM") + +/* Structure or union element. Value is offset in the structure. */ +__define_stab (N_SSYM, 0x60, "SSYM") + +/* Parameter variable. Value is offset from argument pointer. + (On most machines the argument pointer is the same as the frame pointer. */ +__define_stab (N_PSYM, 0xa0, "PSYM") + +/* Automatic variable in the stack. Value is offset from frame pointer. + Also used for type descriptions. */ +__define_stab (N_LSYM, 0x80, "LSYM") + +/* Alternate entry point. Value is its address. */ +__define_stab (N_ENTRY, 0xa4, "ENTRY") + +/* Name of main source file. + Value is starting text address of the compilation. */ +__define_stab (N_SO, 0x64, "SO") + +/* Name of sub-source file. + Value is starting text address of the compilation. */ +__define_stab (N_SOL, 0x84, "SOL") + +/* Line number in text segment. Desc is the line number; + value is corresponding address. */ +__define_stab (N_SLINE, 0x44, "SLINE") +/* Similar, for data segment. */ +__define_stab (N_DSLINE, 0x66, "DSLINE") +/* Similar, for bss segment. */ +__define_stab (N_BSLINE, 0x68, "BSLINE") + +/* Beginning of an include file. Only Sun uses this. + In an object file, only the name is significant. + The Sun linker puts data into some of the other fields. */ +__define_stab (N_BINCL, 0x82, "BINCL") +/* End of an include file. No name. + These two act as brackets around the file's output. + In an object file, there is no significant data in this entry. + The Sun linker puts data into some of the fields. */ +__define_stab (N_EINCL, 0xa2, "EINCL") +/* Place holder for deleted include file. + This appears only in output from the Sun linker. */ +__define_stab (N_EXCL, 0xc2, "EXCL") + +/* Beginning of lexical block. + The desc is the nesting level in lexical blocks. + The value is the address of the start of the text for the block. + The variables declared inside the block *precede* the N_LBRAC symbol. */ +__define_stab (N_LBRAC, 0xc0, "LBRAC") +/* End of a lexical block. Desc matches the N_LBRAC's desc. + The value is the address of the end of the text for the block. */ +__define_stab (N_RBRAC, 0xe0, "RBRAC") + +/* Begin named common block. Only the name is significant. */ +__define_stab (N_BCOMM, 0xe2, "BCOMM") +/* Begin named common block. Only the name is significant + (and it should match the N_BCOMM). */ +__define_stab (N_ECOMM, 0xe4, "ECOMM") +/* End common (local name): value is address. + I'm not sure how this is used. */ +__define_stab (N_ECOML, 0xe8, "ECOML") +/* Second symbol entry containing a length-value for the preceding entry. + The value is the length. */ +__define_stab (N_LENG, 0xfe, "LENG") + +/* Global symbol in Pascal. + Supposedly the value is its line number; I'm skeptical. */ +__define_stab (N_PC, 0x30, "PC") + +/* Modula-2 compilation unit. Can someone say what info it contains? */ +__define_stab (N_M2C, 0x42, "M2C") +/* Modula-2 scope information. Can someone say what info it contains? */ +__define_stab (N_SCOPE, 0xc4, "SCOPE") + +/* Sun's source-code browser stabs. ?? Don't know what the fields are. + Supposedly the field is "path to associated .cb file". */ +__define_stab (N_BROWS, 0x48, "BROWS") + +/* GNU C++ exception stabs. */ + +/* GNU C++ exception variable. Name is variable name. */ +__define_stab (N_EHDECL, 0x50, "EHDECL") + +/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if + this entry is immediately followed by a CAUGHT stab saying what exception + was caught. Multiple CAUGHT stabs means that multiple exceptions + can be caught here. If Desc is 0, it means all exceptions are caught + here. */ +__define_stab (N_CATCH, 0x54, "CATCH") + +/* These STAB's are used on Gould systems for Non-Base register symbols + or something like that. FIXME. I have assigned the values at random + since I don't have a Gould here. Fixups from Gould folk welcome... */ +__define_stab (N_NBTEXT, 0xF0, "NBTEXT") +__define_stab (N_NBDATA, 0xF2, "NBDATA") +__define_stab (N_NBBSS, 0xF4, "NBBSS") +__define_stab (N_NBSTS, 0xF6, "NBSTS") +__define_stab (N_NBLCS, 0xF8, "NBLCS") +__define_stab (N_NSYMS, 0xFA, "NSYMS") + +/* The above information, in matrix format. + + STAB MATRIX + _________________________________________________ + | 00 - 1F are not dbx stab symbols | + | Entries with bits 01 set are external symbols | + | N_UNDEF | N_ABS | N_TEXT | N_DATA | + | N_BSS | N_COMM | | N_FN | + |_______________________________________________| + | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | + | 28 LCSYM | 2A MAIN | 2C | 2E | + | 30 PC | 32 | 34 | 36 | + | 38 | 3A | 3C | 3E | + | 40 RSYM | 42 M2C | 44 SLINE | 46 | + | 48 BROWS | 4A | 4C | 4E | + | 50 EHDECL | 52 | 54 CATCH | 56 | + | 58 | 5A | 5C | 5E | + | 60 SSYM | 62 | 64 SO | 66 DSLINE | + | 68 BSLINE | 6A | 6C | 6E | + | 70 | 72 | 74 | 76 | + | 78 | 7A | 7C | 7E | + | 80 LSYM | 82 BINCL | 84 SOL | 86 | + | 88 | 8A | 8C | 8E | + | 90 | 92 | 94 | 96 | + | 98 | 9A | 9C | 9E | + | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | + | A8 | AA | AC | AE | + | B0 | B2 | B4 | B6 | + | B8 | BA | BC | BE | + | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | + | C8 | CA | CC | CE | + | D0 | D2 | D4 | D6 | + | D8 | DA | DC | DE | + | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | + | E8 ECOML | EA | EC | EE | + | F0 | F2 | F4 | F6 | + | F8 | FA | FC | FE LENG | + +-----------------------------------------------+ + +*/ diff --git a/gdb/standalone.c b/gdb/standalone.c new file mode 100644 index 00000000000..fcb6e7eb032 --- /dev/null +++ b/gdb/standalone.c @@ -0,0 +1,594 @@ +/* Interface to bare machine for GDB running as kernel debugger. + Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +#if defined (SIGTSTP) && defined (SIGIO) +#include +#include +#endif /* SIGTSTP and SIGIO defined (must be 4.2) */ + +#include "defs.h" +#include "param.h" +#include "signals.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + + +/* Random system calls, mostly no-ops to prevent link problems */ + +ioctl (desc, code, arg) +{} + +int (* signal ()) () +{} + +kill () +{} + +getpid () +{ + return 0; +} + +sigsetmask () +{} + +chdir () +{} + +char * +getwd (buf) + char *buf; +{ + buf[0] = '/'; + buf[1] = 0; + return buf; +} + +/* Used to check for existence of .gdbinit. Say no. */ + +access () +{ + return -1; +} + +exit () +{ + error ("Fatal error; restarting."); +} + +/* Reading "files". The contents of some files are written into kdb's + data area before it is run. These files are used to contain the + symbol table for kdb to load, and the source files (in case the + kdb user wants to print them). The symbols are stored in a file + named "kdb-symbols" in a.out format (except that all the text and + data have been stripped to save room). + + The files are stored in the following format: + int number of bytes of data for this file, including these four. + char[] name of the file, ending with a null. + padding to multiple of 4 boundary. + char[] file contents. The length can be deduced from what was + specified before. There is no terminating null here. + + If the int at the front is zero, it means there are no more files. + + Opening a file in kdb returns a nonzero value to indicate success, + but the value does not matter. Only one file can be open, and only + for reading. All the primitives for input from the file know + which file is open and ignore what is specified for the descriptor + or for the stdio stream. + + Input with fgetc can be done either on the file that is open + or on stdin (which reads from the terminal through tty_input () */ + +/* Address of data for the files stored in format described above. */ +char *files_start; + +/* The file stream currently open: */ + +char *sourcebeg; /* beginning of contents */ +int sourcesize; /* size of contents */ +char *sourceptr; /* current read pointer */ +int sourceleft; /* number of bytes to eof */ + +/* "descriptor" for the file now open. + Incremented at each close. + If specified descriptor does not match this, + it means the program is trying to use a closed descriptor. + We report an error for that. */ + +int sourcedesc; + +open (filename, modes) + char *filename; + int modes; +{ + register char *next; + + if (modes) + { + errno = EROFS; + return -1; + } + + if (sourceptr) + { + errno = EMFILE; + return -1; + } + + for (next - files_start; * (int *) next; + next += * (int *) next) + { + if (!strcmp (next + 4, filename)) + { + sourcebeg = next + 4 + strlen (next + 4) + 1; + sourcebeg = (char *) (((int) sourcebeg + 3) & (-4)); + sourceptr = sourcebeg; + sourcesize = next + * (int *) next - sourceptr; + sourceleft = sourcesize; + return sourcedesc; + } + } + return 0; +} + +close (desc) + int desc; +{ + sourceptr = 0; + sourcedesc++; + /* Don't let sourcedesc get big enough to be confused with stdin. */ + if (sourcedesc == 100) + sourcedesc = 5; +} + +FILE * +fopen (filename, modes) + char *filename; + char *modes; +{ + return (FILE *) open (filename, *modes == 'w'); +} + +FILE * +fdopen (desc) + int desc; +{ + return (FILE *) desc; +} + +fclose (desc) + int desc; +{ + close (desc); +} + +fstat (desc, statbuf) + struct stat *statbuf; +{ + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + statbuf->st_size = sourcesize; +} + +myread (desc, destptr, size, filename) + int desc; + char *destptr; + int size; + char *filename; +{ + int len = min (sourceleft, size); + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + bcopy (sourceptr, destptr, len); + sourceleft -= len; + return len; +} + +int +fread (bufp, numelts, eltsize, stream) +{ + register int elts = min (numelts, sourceleft / eltsize); + register int len = elts * eltsize; + + if (stream != sourcedesc) + { + errno = EBADF; + return -1; + } + + bcopy (sourceptr, bufp, len); + sourceleft -= len; + return elts; +} + +int +fgetc (desc) + int desc; +{ + + if (desc == (int) stdin) + return tty_input (); + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + if (sourceleft-- <= 0) + return EOF; + return *sourceptr++; +} + +lseek (desc, pos) + int desc; + int pos; +{ + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + if (pos < 0 || pos > sourcesize) + { + errno = EINVAL; + return -1; + } + + sourceptr = sourcebeg + pos; + sourceleft = sourcesize - pos; +} + +/* Output in kdb can go only to the terminal, so the stream + specified may be ignored. */ + +printf (a1, a2, a3, a4, a5, a6, a7, a8, a9) +{ + char buffer[1024]; + sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9); + display_string (buffer); +} + +fprintf (ign, a1, a2, a3, a4, a5, a6, a7, a8, a9) +{ + char buffer[1024]; + sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9); + display_string (buffer); +} + +fwrite (buf, numelts, size, stream) + register char *buf; + int numelts, size; +{ + register int i = numelts * size; + while (i-- > 0) + fputc (*buf++, stream); +} + +fputc (c, ign) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + display_string (buf); +} + +/* sprintf refers to this, but loading this from the + library would cause fflush to be loaded from it too. + In fact there should be no need to call this (I hope). */ + +_flsbuf () +{ + error ("_flsbuf was actually called."); +} + +fflush (ign) +{ +} + +/* Entries into core and inflow, needed only to make things link ok. */ + +exec_file_command () +{} + +core_file_command () +{} + +char * +get_exec_file (err) + int err; +{ + /* Makes one printout look reasonable; value does not matter otherwise. */ + return "run"; +} + +have_core_file_p () +{ + return 0; +} + +kill_command () +{ + inferior_pid = 0; +} + +terminal_inferior () +{} + +terminal_ours () +{} + +terminal_init_inferior () +{} + +write_inferior_register () +{} + +read_inferior_register () +{} + +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + bcopy (memaddr, myaddr, len); +} + +/* Always return 0 indicating success. */ + +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + bcopy (myaddr, memaddr, len); + return 0; +} + +static REGISTER_TYPE saved_regs[NUM_REGS]; + +REGISTER_TYPE +read_register (regno) + int regno; +{ + if (regno < 0 || regno >= NUM_REGS) + error ("Register number %d out of range.", regno); + return saved_regs[regno]; +} + +void +write_register (regno, value) + int regno; + REGISTER_TYPE value; +{ + if (regno < 0 || regno >= NUM_REGS) + error ("Register number %d out of range.", regno); + saved_regs[regno] = value; +} + +/* System calls needed in relation to running the "inferior". */ + +vfork () +{ + /* Just appear to "succeed". Say the inferior's pid is 1. */ + return 1; +} + +/* These are called by code that normally runs in the inferior + that has just been forked. That code never runs, when standalone, + and these definitions are so it will link without errors. */ + +ptrace () +{} + +setpgrp () +{} + +execle () +{} + +_exit () +{} + +/* Malloc calls these. */ + +malloc_warning (str) + char *str; +{ + printf ("\n%s.\n\n", str); +} + +char *next_free; +char *memory_limit; + +char * +sbrk (amount) + int amount; +{ + if (next_free + amount > memory_limit) + return (char *) -1; + next_free += amount; + return next_free - amount; +} + +/* Various ways malloc might ask where end of memory is. */ + +char * +ulimit () +{ + return memory_limit; +} + +int +vlimit () +{ + return memory_limit - next_free; +} + +getrlimit (addr) + struct rlimit *addr; +{ + addr->rlim_cur = memory_limit - next_free; +} + +/* Context switching to and from program being debugged. */ + +/* GDB calls here to run the user program. + The frame pointer for this function is saved in + gdb_stack by save_frame_pointer; then we restore + all of the user program's registers, including PC and PS. */ + +static int fault_code; +static REGISTER_TYPE gdb_stack; + +resume () +{ + REGISTER_TYPE restore[NUM_REGS]; + + PUSH_FRAME_PTR; + save_frame_pointer (); + + bcopy (saved_regs, restore, sizeof restore); + POP_REGISTERS; + /* Control does not drop through here! */ +} + +save_frame_pointer (val) + CORE_ADDR val; +{ + gdb_stack = val; +} + +/* Fault handlers call here, running in the user program stack. + They must first push a fault code, + old PC, old PS, and any other info about the fault. + The exact format is machine-dependent and is known only + in the definition of PUSH_REGISTERS. */ + +fault () +{ + /* Transfer all registers and fault code to the stack + in canonical order: registers in order of GDB register number, + followed by fault code. */ + PUSH_REGISTERS; + + /* Transfer them to saved_regs and fault_code. */ + save_registers (); + + restore_gdb (); + /* Control does not reach here */ +} + +restore_gdb () +{ + CORE_ADDR new_fp = gdb_stack; + /* Switch to GDB's stack */ + POP_FRAME_PTR; + /* Return from the function `resume'. */ +} + +/* Assuming register contents and fault code have been pushed on the stack as + arguments to this function, copy them into the standard place + for the program's registers while GDB is running. */ + +save_registers (firstreg) + int firstreg; +{ + bcopy (&firstreg, saved_regs, sizeof saved_regs); + fault_code = (&firstreg)[NUM_REGS]; +} + +/* Store into the structure such as `wait' would return + the information on why the program faulted, + converted into a machine-independent signal number. */ + +static int fault_table[] = FAULT_TABLE; + +int +wait (w) + WAITTYPE *w; +{ + WSETSTOP (*w, fault_table[fault_code / FAULT_CODE_UNITS]); + return inferior_pid; +} + +/* Allocate a big space in which files for kdb to read will be stored. + Whatever is left is where malloc can allocate storage. + + Initialize it, so that there will be space in the executable file + for it. Then the files can be put into kdb by writing them into + kdb's executable file. */ + +/* The default size is as much space as we expect to be available + for kdb to use! */ + +#ifndef HEAP_SIZE +#define HEAP_SIZE 400000 +#endif + +char heap[HEAP_SIZE] = {0}; + +#ifndef STACK_SIZE +#define STACK_SIZE 100000 +#endif + +int kdb_stack_beg[STACK_SIZE / sizeof (int)]; +int kdb_stack_end; + +_initialize_standalone () +{ + register char *next; + + /* Find start of data on files. */ + + files_start = heap; + + /* Find the end of the data on files. */ + + for (next - files_start; * (int *) next; + next += * (int *) next) + {} + + /* That is where free storage starts for sbrk to give out. */ + next_free = next; + + memory_limit = heap + sizeof heap; +} + diff --git a/gdb/stddef.h b/gdb/stddef.h new file mode 100755 index 00000000000..d95a8154d27 --- /dev/null +++ b/gdb/stddef.h @@ -0,0 +1,24 @@ +#ifndef _STDDEF_H +#define _STDDEF_H + +/* Signed type of difference of two pointers. */ + +typedef long ptrdiff_t; + +/* Unsigned type of `sizeof' something. */ + +#ifndef _SIZE_T /* in case has defined it. */ +#define _SIZE_T +typedef unsigned long size_t; +#endif /* _SIZE_T */ + +/* A null pointer constant. */ + +#undef NULL /* in case has defined it. */ +#define NULL 0 + +/* Offset of member MEMBER in a struct of type TYPE. */ + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif /* _STDDEF_H */ diff --git a/gdb/stdlib.h b/gdb/stdlib.h new file mode 100755 index 00000000000..40ce1676a13 --- /dev/null +++ b/gdb/stdlib.h @@ -0,0 +1,10 @@ +/* Fake stdlib.h supplying the stuff needed by malloc. */ + +#ifndef __ONEFILE +#include +#endif + +extern void EXFUN(abort, (void)); +extern void EXFUN(free, (PTR)); +extern PTR EXFUN(malloc, (size_t)); +extern PTR EXFUN(realloc, (PTR, size_t)); diff --git a/gdb/stuff.c b/gdb/stuff.c new file mode 100644 index 00000000000..2ffdc972d1f --- /dev/null +++ b/gdb/stuff.c @@ -0,0 +1,174 @@ +/* Program to stuff files into a specially prepared space in kdb. + Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written 13-Mar-86 by David Bridgham. */ + +#include +#include +#include +#include +#include +#include + +extern char *sys_errlist[]; + +main (argc, argv) + int argc; + char *argv[]; +{ + register char *cp; + char *outfile; + register int i; + int offset; + int out_fd, in_fd; + struct stat stat_buf; + int size, pad; + char buf[1024]; + static char zeros[4] = {0}; + + if (argc < 4) + err("Not enough arguments\nUsage: %s -o kdb file1 file2 ...\n", + argv[0]); + + outfile = 0; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-o") == 0) + outfile = argv[++i]; + } + if (outfile == 0) + err("Output file not specified\n"); + + offset = get_offset (outfile, "_heap"); + + out_fd = open (outfile, O_WRONLY); + if (out_fd < 0) + err ("Error opening %s for write: %s\n", outfile, sys_errlist[errno]); + if (lseek (out_fd, offset, 0) < 0) + err ("Error seeking to heap in %s: %s\n", outfile, sys_errlist[errno]); + + /* For each file listed on the command line, write it into the + * 'heap' of the output file. Make sure to skip the arguments + * that name the output file. */ + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-o") == 0) + continue; + if ((in_fd = open (argv[i], O_RDONLY)) < 0) + err ("Error opening %s for read: %s\n", argv[i], sys_errlist[errno]); + if (fstat (in_fd, &stat_buf) < 0) + err ("Error stat'ing %s: %s\n", argv[i], sys_errlist[errno]); + size = strlen (argv[i]); + pad = 4 - (size & 3); + size += pad + stat_buf.st_size + sizeof (int); + write (out_fd, &size, sizeof (int)); + write (out_fd, argv[i], strlen (argv[i])); + write (out_fd, zeros, pad); + while ((size = read (in_fd, buf, sizeof (buf))) > 0) + write (out_fd, buf, size); + close (in_fd); + } + size = 0; + write (out_fd, &size, sizeof (int)); + close (out_fd); + return (0); +} + +/* Read symbol table from file and returns the offset into the file + * where symbol sym_name is located. If error, print message and + * exit. */ +get_offset (file, sym_name) + char *file; + char *sym_name; +{ + int f; + struct exec file_hdr; + struct nlist *symbol_table; + int size; + char *strings; + + f = open (file, O_RDONLY); + if (f < 0) + err ("Error opening %s: %s\n", file, sys_errlist[errno]); + if (read (f, &file_hdr, sizeof (file_hdr)) < 0) + err ("Error reading exec structure: %s\n", sys_errlist[errno]); + if (N_BADMAG (file_hdr)) + err ("File %s not an a.out file\n", file); + + /* read in symbol table */ + if ((symbol_table = (struct nlist *)malloc (file_hdr.a_syms)) == 0) + err ("Couldn't allocate space for symbol table\n"); + if (lseek (f, N_SYMOFF (file_hdr), 0) == -1) + err ("lseek error: %s\n", sys_errlist[errno]); + if (read (f, symbol_table, file_hdr.a_syms) == -1) + err ("Error reading symbol table from %s: %s\n", file, sys_errlist[errno]); + + /* read in string table */ + if (read (f, &size, 4) == -1) + err ("reading string table size: %s\n", sys_errlist[errno]); + if ((strings = (char *)malloc (size)) == 0) + err ("Couldn't allocate memory for string table\n"); + if (read (f, strings, size - 4) == -1) + err ("reading string table: %s\n", sys_errlist[errno]); + + /* Find the core address at which the first byte of kdb text segment + should be loaded into core when kdb is run. */ + origin = find_symbol ("_etext", symbol_table, file_hdr.a_syms, strings) + - file_hdr.a_text; + /* Find the core address at which the heap will appear. */ + coreaddr = find_symbol (sym_name, symbol_table, file_hdr.a_syms, strings); + /* Return address in file of the heap data space. */ + return (N_TXTOFF (file_hdr) + core_addr - origin); +} + +find_symbol (sym_name, symbol_table, length, strings) + char *sym_name; + struct nlist *symbol_table; + int length; + char *strings; +{ + register struct nlist *sym; + + /* Find symbol in question */ + for (sym = symbol_table; + sym != (struct nlist *)((char *)symbol_table + length); + sym++) + { + if ((sym->n_type & N_TYPE) != N_DATA) continue; + if (sym->n_un.n_strx == 0) continue; + if (strcmp (sym_name, strings + sym->n_un.n_strx - 4) == 0) + return sym->n_value; + } + err ("Data symbol %s not found in %s\n", sym_name, file); +} + +/* VARARGS */ +void +err (va_alist) + va_dcl +{ + va_list args; + char *string; + + va_start (args); + string = va_arg (args, char *); + vfprintf (stderr, string, args); + va_end (args); + exit (-1); +} diff --git a/gdb/sun3-xdep.c b/gdb/sun3-xdep.c new file mode 100644 index 00000000000..6789cd66019 --- /dev/null +++ b/gdb/sun3-xdep.c @@ -0,0 +1,133 @@ +/* Sun-3 Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "inferior.h" + +#include +#define KERNEL /* To get floating point reg definitions */ +#include + +#include "gdbcore.h" + +extern int errno; + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; +#ifdef FP0_REGNUM + struct fp_status inferior_fp_registers; +#endif + extern char registers[]; + + registers_fetched (); + + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); +#ifdef FP0_REGNUM + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); +#endif + + bcopy (&inferior_registers, registers, 16 * 4); +#ifdef FP0_REGNUM + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); +#endif + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; +#ifdef FP0_REGNUM + bcopy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); +#endif +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; +#ifdef FP0_REGNUM + struct fp_status inferior_fp_registers; +#endif + extern char registers[]; + + bcopy (registers, &inferior_registers, 16 * 4); +#ifdef FP0_REGNUM + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); +#endif + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + +#ifdef FP0_REGNUM + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); +#endif + + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); +#if FP0_REGNUM + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); +#endif +} + +/* Machine-dependent code for pulling registers out of a Sun-3 core file. */ + +void +fetch_core_registers (core_reg_sect, core_reg_size, which) + char *core_reg_sect; + unsigned core_reg_size; + int which; +{ + extern char registers[]; + struct regs *regs = (struct regs *) core_reg_sect; + + if (which == 0) { + if (core_reg_size < sizeof (struct regs)) + error ("Can't find registers in core file"); + + bcopy ((char *)regs, registers, 16 * 4); + supply_register (PS_REGNUM, ®s->r_ps); + supply_register (PC_REGNUM, ®s->r_pc); + + } else if (which == 2) { + +#define fpustruct ((struct fpu *) core_reg_sect) + + if (core_reg_size >= sizeof (struct fpu)) + { + bcopy (fpustruct->f_fpstatus.fps_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof fpustruct->f_fpstatus.fps_regs); + bcopy (&fpustruct->f_fpstatus.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof fpustruct->f_fpstatus - + sizeof fpustruct->f_fpstatus.fps_regs); + } + else + fprintf (stderr, "Couldn't read float regs from core file\n"); + } +} diff --git a/gdb/sun386-xdep.c b/gdb/sun386-xdep.c new file mode 100644 index 00000000000..d9f1cb5ebcf --- /dev/null +++ b/gdb/sun386-xdep.c @@ -0,0 +1,252 @@ +/* Machine-dependent code for host Sun 386i's for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + Changes for sun386i by Jean Daniel Fekete (jdf@litp.univ-p6-7.fr), + C2V Paris, April 89. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "signame.h" +#include "gdbcore.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; + struct fp_state inferior_fp_registers; + extern char registers[]; + + registers_fetched (); + + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); + + bcopy (&inferior_registers, registers, sizeof inferior_registers); + + bcopy (inferior_fp_registers.f_st,®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.f_st); + bcopy (&inferior_fp_registers.f_ctrl, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.f_st); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_state inferior_fp_registers; + extern char registers[]; + + bcopy (registers, &inferior_registers, 20 * 4); + + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)],inferior_fp_registers.f_st, + sizeof inferior_fp_registers.f_st); + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.f_ctrl, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.f_st); + +#ifdef PTRACE_FP_BUG + if (regno == FP_REGNUM || regno == -1) + /* Storing the frame pointer requires a gross hack, in which an + instruction that moves eax into ebp gets single-stepped. */ + { + int stack = inferior_registers.r_reg[SP_REGNUM]; + int stuff = ptrace (PTRACE_PEEKDATA, inferior_pid, stack); + int reg = inferior_registers.r_reg[EAX]; + inferior_registers.r_reg[EAX] = + inferior_registers.r_reg[FP_REGNUM]; + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_POKEDATA, inferior_pid, stack, 0xc589); + ptrace (PTRACE_SINGLESTEP, inferior_pid, stack, 0); + wait (0); + ptrace (PTRACE_POKEDATA, inferior_pid, stack, stuff); + inferior_registers.r_reg[EAX] = reg; + } +#endif + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); +} + +/* Machine-dependent code which would otherwise be in core.c */ +/* Work with core files, for GDB. */ + + +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) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + + { + struct core corestr; + + val = myread (corechan, &corestr, sizeof corestr); + if (val < 0) + perror_with_name (filename); + if (corestr.c_magic != CORE_MAGIC) + error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", + filename, corestr.c_magic, (int) CORE_MAGIC); + else if (sizeof (struct core) != corestr.c_len) + error ("\"%s\" has an invalid struct core length (%d, expected %d)", + filename, corestr.c_len, (int) sizeof (struct core)); + + data_start = exec_data_start; + data_end = data_start + corestr.c_dsize; + stack_start = stack_end - corestr.c_ssize; + data_offset = sizeof corestr; + stack_offset = sizeof corestr + corestr.c_dsize; + + bcopy (&corestr.c_regs, registers, sizeof corestr.c_regs); + + bcopy (corestr.c_fpu.f_fpstatus.f_st, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof corestr.c_fpu.f_fpstatus.f_st); + bcopy (&corestr.c_fpu.f_fpstatus.f_ctrl, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof corestr.c_fpu.f_fpstatus - + sizeof corestr.c_fpu.f_fpstatus.f_st); + + /* the struct aouthdr of sun coff is not the struct exec stored + in the core file. */ + bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); +#ifndef COFF_ENCAPSULATE + core_aouthdr.magic = corestr.c_aouthdr.a_info; + core_aouthdr.vstamp = /*SUNVERSION*/ 31252; +#endif + 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"); +} + +i387_to_double (from, to) + char *from; + char *to; +{ + long *lp; + /* push extended mode on 387 stack, then pop in double mode + * + * first, set exception masks so no error is generated - + * number will be rounded to inf or 0, if necessary + */ + asm ("pushl %eax"); /* grab a stack slot */ + asm ("fstcw (%esp)"); /* get 387 control word */ + asm ("movl (%esp),%eax"); /* save old value */ + asm ("orl $0x3f,%eax"); /* mask all exceptions */ + asm ("pushl %eax"); + asm ("fldcw (%esp)"); /* load new value into 387 */ + + asm ("movl 8(%ebp),%eax"); + asm ("fldt (%eax)"); /* push extended number on 387 stack */ + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpl (%eax)"); /* pop double */ + asm ("fwait"); + + asm ("popl %eax"); /* flush modified control word */ + asm ("fnclex"); /* clear exceptions */ + asm ("fldcw (%esp)"); /* restore original control word */ + asm ("popl %eax"); /* flush saved copy */ +} + +double_to_i387 (from, to) + char *from; + char *to; +{ + /* push double mode on 387 stack, then pop in extended mode + * no errors are possible because every 64-bit pattern + * can be converted to an extended + */ + asm ("movl 8(%ebp),%eax"); + asm ("fldl (%eax)"); + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpt (%eax)"); + asm ("fwait"); +} diff --git a/gdb/symmetry-tdep.c b/gdb/symmetry-tdep.c new file mode 100755 index 00000000000..aba21c3c432 --- /dev/null +++ b/gdb/symmetry-tdep.c @@ -0,0 +1,494 @@ +/* Sequent Symmetry target interface, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* many 387-specific items of use taken from i386-dep.c */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" + +#include +#include +#include +#include +#include +#include +#include "gdbcore.h" +#include + +static long i386_get_frame_setup (); +static i386_follow_jump (); + +#include +#define TERMINAL struct sgttyb + +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + data_start = 0; + data_end -= exec_data_start; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close (execchan); + execchan = -1; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + +#ifdef COFF_FORMAT + { + int aout_hdrsize; + int num_sections; + + if (read_file_hdr (execchan, &file_hdr) < 0) + error ("\"%s\": not in executable format.", execfile); + + aout_hdrsize = file_hdr.f_opthdr; + num_sections = file_hdr.f_nscns; + + if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0) + error ("\"%s\": can't read optional aouthdr", execfile); + + if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections, + aout_hdrsize) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections, + aout_hdrsize) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = text_hdr.s_scnptr; + exec_data_start = exec_aouthdr.data_start; + exec_data_end = exec_data_start + exec_aouthdr.dsize; + exec_data_offset = data_hdr.s_scnptr; + data_start = exec_data_start; + data_end += exec_data_start; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + + val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); + + if (val < 0) + perror_with_name (filename); + + text_start = N_ADDRADJ(exec_aouthdr); + exec_data_start = round(exec_aouthdr.a_text, NBPG*CLSIZE); + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + text_end = exec_aouthdr.a_text; + exec_data_end = exec_data_start + exec_aouthdr.a_data; + data_start = exec_data_start; + data_end = data_start + exec_aouthdr.a_data; + exec_data_offset = N_TXTOFF(exec_aouthdr); + 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); +} + +/* rounds 'one' up to divide evenly by 'two' */ + +int +round(one,two) +register int one, two; + +{ + register int temp; + temp = (one/two)*two; + if (one != temp) { + temp += two; + } + return temp; +} + + +static CORE_ADDR codestream_next_addr; +static CORE_ADDR codestream_addr; +static unsigned char codestream_buf[sizeof (int)]; +static int codestream_off; +static int codestream_cnt; + +#define codestream_tell() (codestream_addr + codestream_off) +#define codestream_peek() (codestream_cnt == 0 ? \ + codestream_fill(1): codestream_buf[codestream_off]) +#define codestream_get() (codestream_cnt-- == 0 ? \ + codestream_fill(0) : codestream_buf[codestream_off++]) + + +static unsigned char +codestream_fill (peek_flag) +{ + codestream_addr = codestream_next_addr; + codestream_next_addr += sizeof (int); + codestream_off = 0; + codestream_cnt = sizeof (int); + read_memory (codestream_addr, + (unsigned char *)codestream_buf, + sizeof (int)); + + if (peek_flag) + return (codestream_peek()); + else + return (codestream_get()); +} + +static void +codestream_seek (place) +{ + codestream_next_addr = place & -sizeof (int); + codestream_cnt = 0; + codestream_fill (1); + while (codestream_tell() != place) + codestream_get (); +} + +static void +codestream_read (buf, count) + unsigned char *buf; +{ + unsigned char *p; + int i; + p = buf; + for (i = 0; i < count; i++) + *p++ = codestream_get (); +} + +/* + * Following macro translates i386 opcode register numbers to Symmetry + * register numbers. This is used by FRAME_FIND_SAVED_REGS. + * + * %eax %ecx %edx %ebx %esp %ebp %esi %edi + * i386 0 1 2 3 4 5 6 7 + * Symmetry 0 2 1 5 14 15 6 7 + * + */ +#define I386_REGNO_TO_SYMMETRY(n) \ +((n)==0?0 :(n)==1?2 :(n)==2?1 :(n)==3?5 :(n)==4?14 :(n)==5?15 :(n)) + +/* from i386-dep.c */ +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + unsigned long locals; + unsigned char *p; + unsigned char op; + CORE_ADDR dummy_bottom; + CORE_ADDR adr; + int i; + + bzero (fsrp, sizeof *fsrp); + + /* if frame is the end of a dummy, compute where the + * beginning would be + */ + dummy_bottom = fip->frame - 4 - NUM_REGS*4 - CALL_DUMMY_LENGTH; + + /* check if the PC is in the stack, in a dummy frame */ + if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) + { + /* all regs were saved by push_call_dummy () */ + adr = fip->frame - 4; + for (i = 0; i < NUM_REGS; i++) + { + fsrp->regs[i] = adr; + adr -= 4; + } + return; + } + + locals = i386_get_frame_setup (get_pc_function_start (fip->pc)); + + if (locals >= 0) + { + adr = fip->frame - 4 - locals; + for (i = 0; i < 8; i++) + { + op = codestream_get (); + if (op < 0x50 || op > 0x57) + break; + fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr; + adr -= 4; + } + } + + fsrp->regs[PC_REGNUM] = fip->frame + 4; + fsrp->regs[FP_REGNUM] = fip->frame; +} + +static long +i386_get_frame_setup (pc) +{ + unsigned char op; + + codestream_seek (pc); + + i386_follow_jump (); + + op = codestream_get (); + + if (op == 0x58) /* popl %eax */ + { + /* + * this function must start with + * + * popl %eax 0x58 + * xchgl %eax, (%esp) 0x87 0x04 0x24 + * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 + * + * (the system 5 compiler puts out the second xchg + * inst, and the assembler doesn't try to optimize it, + * so the 'sib' form gets generated) + * + * this sequence is used to get the address of the return + * buffer for a function that returns a structure + */ + int pos; + unsigned char buf[4]; + static unsigned char proto1[3] = { 0x87,0x04,0x24 }; + static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 }; + pos = codestream_tell (); + codestream_read (buf, 4); + if (bcmp (buf, proto1, 3) == 0) + pos += 3; + else if (bcmp (buf, proto2, 4) == 0) + pos += 4; + + codestream_seek (pos); + op = codestream_get (); /* update next opcode */ + } + + if (op == 0x55) /* pushl %esp */ + { + if (codestream_get () != 0x8b) /* movl %esp, %ebp (2bytes) */ + return (-1); + if (codestream_get () != 0xec) + return (-1); + /* + * check for stack adjustment + * + * subl $XXX, %esp + * + * note: you can't subtract a 16 bit immediate + * from a 32 bit reg, so we don't have to worry + * about a data16 prefix + */ + op = codestream_peek (); + if (op == 0x83) /* subl with 8 bit immed */ + { + codestream_get (); + if (codestream_get () != 0xec) + return (-1); + /* subl with signed byte immediate + * (though it wouldn't make sense to be negative) + */ + return (codestream_get()); + } + else if (op == 0x81) /* subl with 32 bit immed */ + { + int locals; + if (codestream_get () != 0xec) + return (-1); + /* subl with 32 bit immediate */ + codestream_read ((unsigned char *)&locals, 4); + return (locals); + } + else + { + return (0); + } + } + else if (op == 0xc8) + { + /* enter instruction: arg is 16 unsigned immed */ + unsigned short slocals; + codestream_read ((unsigned char *)&slocals, 2); + codestream_get (); /* flush final byte of enter instruction */ + return (slocals); + } + return (-1); +} + +/* next instruction is a jump, move to target */ +static +i386_follow_jump () +{ + int long_delta; + short short_delta; + char byte_delta; + int data16; + int pos; + + pos = codestream_tell (); + + data16 = 0; + if (codestream_peek () == 0x66) + { + codestream_get (); + data16 = 1; + } + + switch (codestream_get ()) + { + case 0xe9: + /* relative jump: if data16 == 0, disp32, else disp16 */ + if (data16) + { + codestream_read ((unsigned char *)&short_delta, 2); + pos += short_delta + 3; /* include size of jmp inst */ + } + else + { + codestream_read ((unsigned char *)&long_delta, 4); + pos += long_delta + 5; + } + break; + case 0xeb: + /* relative jump, disp8 (ignore data16) */ + codestream_read ((unsigned char *)&byte_delta, 1); + pos += byte_delta + 2; + break; + } + codestream_seek (pos + data16); +} + +/* return pc of first real instruction */ +/* from i386-dep.c */ + +i386_skip_prologue (pc) +{ + unsigned char op; + int i; + + if (i386_get_frame_setup (pc) < 0) + return (pc); + + /* found valid frame setup - codestream now points to + * start of push instructions for saving registers + */ + + /* skip over register saves */ + for (i = 0; i < 8; i++) + { + op = codestream_peek (); + /* break if not pushl inst */ + if (op < 0x50 || op > 0x57) + break; + codestream_get (); + } + + i386_follow_jump (); + + return (codestream_tell ()); +} + +symmetry_extract_return_value(type, regbuf, valbuf) + struct type *type; + char *regbuf; + char *valbuf; +{ + union { + double d; + int l[2]; + } xd; + int i; + float f; + + if (TYPE_CODE_FLT == TYPE_CODE(type)) { + for (i = 0; i < misc_function_count; i++) { + if (!strcmp(misc_function_vector[i].name, "1167_flt")) + break; + } + if (i < misc_function_count) { + /* found "1167_flt" means 1167, %fp2-%fp3 */ + /* float & double; 19= %fp2, 20= %fp3 */ + /* no single precision on 1167 */ + xd.l[1] = *((int *)®buf[REGISTER_BYTE(19)]); + xd.l[0] = *((int *)®buf[REGISTER_BYTE(20)]); + switch (TYPE_LENGTH(type)) { + case 4: + f = (float) xd.d; + bcopy(&f, valbuf, TYPE_LENGTH(type)); + break; + case 8: + bcopy(&xd.d, valbuf, TYPE_LENGTH(type)); + break; + default: + error("Unknown floating point size"); + break; + } + } else { + /* 387 %st(0), gcc uses this */ + i387_to_double(((int *)®buf[REGISTER_BYTE(3)]), + &xd.d); + switch (TYPE_LENGTH(type)) { + case 4: /* float */ + f = (float) xd.d; + bcopy(&f, valbuf, 4); + break; + case 8: /* double */ + bcopy(&xd.d, valbuf, 8); + break; + default: + error("Unknown floating point size"); + break; + } + } + } else { + bcopy (regbuf, valbuf, TYPE_LENGTH (type)); + } +} diff --git a/gdb/symmetry-xdep.c b/gdb/symmetry-xdep.c new file mode 100755 index 00000000000..34496789aca --- /dev/null +++ b/gdb/symmetry-xdep.c @@ -0,0 +1,557 @@ +/* Sequent Symmetry host interface, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* many 387-specific items of use taken from i386-dep.c */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" + +#include +#include +#include +#include +#include +#include +#include "gdbcore.h" +#include + +static long i386_get_frame_setup (); +static i386_follow_jump (); + +#include +#define TERMINAL struct sgttyb + +store_inferior_registers(regno) +int regno; +{ + struct pt_regset regs; + int reg_tmp, i; + extern char registers[]; + +#if 0 + /* PREPARE_TO_STORE deals with this. */ + if (-1 == regno) + { +#endif + regs.pr_eax = *(int *)®isters[REGISTER_BYTE(0)]; + regs.pr_ebx = *(int *)®isters[REGISTER_BYTE(5)]; + regs.pr_ecx = *(int *)®isters[REGISTER_BYTE(2)]; + regs.pr_edx = *(int *)®isters[REGISTER_BYTE(1)]; + regs.pr_esi = *(int *)®isters[REGISTER_BYTE(6)]; + regs.pr_edi = *(int *)®isters[REGISTER_BYTE(7)]; + regs.pr_esp = *(int *)®isters[REGISTER_BYTE(14)]; + regs.pr_ebp = *(int *)®isters[REGISTER_BYTE(15)]; + regs.pr_eip = *(int *)®isters[REGISTER_BYTE(16)]; + regs.pr_flags = *(int *)®isters[REGISTER_BYTE(17)]; + for (i = 0; i < 31; i++) { + regs.pr_fpa.fpa_regs[i] = + *(int *)®isters[REGISTER_BYTE(FP1_REGNUM+i)]; + } +#if 0 + } + else + { + reg_tmp = *(int *)®isters[REGISTER_BYTE(regno)]; + ptrace(XPT_RREGS, inferior_pid, ®s, 0); + switch (regno) + { + case 0: + regs.pr_eax = *(int *)®isters[REGISTER_BYTE(0)]; + break; + case 5: + regs.pr_ebx = *(int *)®isters[REGISTER_BYTE(5)]; + break; + case 2: + regs.pr_ecx = *(int *)®isters[REGISTER_BYTE(2)]; + break; + case 1: + regs.pr_edx = *(int *)®isters[REGISTER_BYTE(1)]; + break; + case 6: + regs.pr_esi = *(int *)®isters[REGISTER_BYTE(6)]; + break; + case 7: + regs.pr_edi = *(int *)®isters[REGISTER_BYTE(7)]; + break; + case 15: + regs.pr_ebp = *(int *)®isters[REGISTER_BYTE(15)]; + break; + case 14: + regs.pr_esp = *(int *)®isters[REGISTER_BYTE(14)]; + break; + case 16: + regs.pr_eip = *(int *)®isters[REGISTER_BYTE(16)]; + break; + case 17: + regs.pr_flags = *(int *)®isters[REGISTER_BYTE(17)]; + break; + } + } +#endif /* 0 */ + ptrace(XPT_WREGS, inferior_pid, ®s, 0); +} + +void +fetch_inferior_registers() +{ + int i; + struct pt_regset regs; + extern char registers[]; + + registers_fetched (); + + ptrace(XPT_RREGS, inferior_pid, ®s, 0); + *(int *)®isters[REGISTER_BYTE(0)] = regs.pr_eax; + *(int *)®isters[REGISTER_BYTE(5)] = regs.pr_ebx; + *(int *)®isters[REGISTER_BYTE(2)] = regs.pr_ecx; + *(int *)®isters[REGISTER_BYTE(1)] = regs.pr_edx; + *(int *)®isters[REGISTER_BYTE(6)] = regs.pr_esi; + *(int *)®isters[REGISTER_BYTE(7)] = regs.pr_edi; + *(int *)®isters[REGISTER_BYTE(15)] = regs.pr_ebp; + *(int *)®isters[REGISTER_BYTE(14)] = regs.pr_esp; + *(int *)®isters[REGISTER_BYTE(16)] = regs.pr_eip; + *(int *)®isters[REGISTER_BYTE(17)] = regs.pr_flags; + for (i = 0; i < FPA_NREGS; i++) { + *(int *)®isters[REGISTER_BYTE(FP1_REGNUM+i)] = regs.pr_fpa.fpa_regs[i]; + } + bcopy(regs.pr_fpu.fpu_stack[0], ®isters[REGISTER_BYTE(3)], 10); + bcopy(regs.pr_fpu.fpu_stack[1], ®isters[REGISTER_BYTE(4)], 10); + bcopy(regs.pr_fpu.fpu_stack[2], ®isters[REGISTER_BYTE(8)], 10); + bcopy(regs.pr_fpu.fpu_stack[3], ®isters[REGISTER_BYTE(9)], 10); + bcopy(regs.pr_fpu.fpu_stack[4], ®isters[REGISTER_BYTE(10)], 10); + bcopy(regs.pr_fpu.fpu_stack[5], ®isters[REGISTER_BYTE(11)], 10); + bcopy(regs.pr_fpu.fpu_stack[6], ®isters[REGISTER_BYTE(12)], 10); + bcopy(regs.pr_fpu.fpu_stack[7], ®isters[REGISTER_BYTE(13)], 10); +} + + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +#include "gdbcore.h" + +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) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name (filename); + data_start = exec_data_start; + + data_end = data_start + NBPG * (u.u_dsize - u.u_tsize); + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = ctob(UPAGES + u.u_dsize - u.u_tsize); + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; +printf("u.u_tsize= %#x, u.u_dsize= %#x, u.u_ssize= %#x, stack_off= %#x\n", + u.u_tsize, u.u_dsize, u.u_ssize, stack_offset); + + core_aouthdr.a_magic = 0; + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0) + perror_with_name (filename); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame(create_new_frame(read_register(FP_REGNUM), + read_pc())); +/* set_current_frame (read_register (FP_REGNUM));*/ + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} + +/* from i386-dep.c */ +static +print_387_control_word (control) +unsigned short control; +{ + printf ("control 0x%04x: ", control); + printf ("compute to "); + switch ((control >> 8) & 3) + { + case 0: printf ("24 bits; "); break; + case 1: printf ("(bad); "); break; + case 2: printf ("53 bits; "); break; + case 3: printf ("64 bits; "); break; + } + printf ("round "); + switch ((control >> 10) & 3) + { + case 0: printf ("NEAREST; "); break; + case 1: printf ("DOWN; "); break; + case 2: printf ("UP; "); break; + case 3: printf ("CHOP; "); break; + } + if (control & 0x3f) + { + printf ("mask:"); + if (control & 0x0001) printf (" INVALID"); + if (control & 0x0002) printf (" DENORM"); + if (control & 0x0004) printf (" DIVZ"); + if (control & 0x0008) printf (" OVERF"); + if (control & 0x0010) printf (" UNDERF"); + if (control & 0x0020) printf (" LOS"); + printf (";"); + } + printf ("\n"); + if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n", + control & 0xe080); +} + +static +print_387_status_word (status) + unsigned short status; +{ + printf ("status %#04x: ", status); + if (status & 0xff) { + printf ("exceptions:"); /* exception names match */ + if (status & 0x0001) printf (" FLTINV"); + if (status & 0x0002) printf (" FLTDEN"); + if (status & 0x0004) printf (" FLTDIV"); + if (status & 0x0008) printf (" FLTOVF"); + if (status & 0x0010) printf (" FLTUND"); + if (status & 0x0020) printf (" FLTPRE"); + if (status & 0x0040) printf (" FLTSTK"); + printf ("; "); + } + printf ("flags: %d%d%d%d; ", + (status & 0x4000) != 0, + (status & 0x0400) != 0, + (status & 0x0200) != 0, + (status & 0x0100) != 0); + + printf ("top %d\n", (status >> 11) & 7); +} + +static +print_fpu_status(ep) +struct pt_regset ep; + +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + printf("80387:"); + if (ep.pr_fpu.fpu_ip == 0) { + printf(" not in use.\n"); + return; + } else { + printf("\n"); + } + if (ep.pr_fpu.fpu_status != 0) { + print_387_status_word (ep.pr_fpu.fpu_status); + } + print_387_control_word (ep.pr_fpu.fpu_control); + printf ("last exception: "); + printf ("opcode 0x%x; ", ep.pr_fpu.fpu_rsvd4); + printf ("pc 0x%x:0x%x; ", ep.pr_fpu.fpu_cs, ep.pr_fpu.fpu_ip); + printf ("operand 0x%x:0x%x\n", ep.pr_fpu.fpu_data_offset, ep.pr_fpu.fpu_op_sel); + + top = (ep.pr_fpu.fpu_status >> 11) & 7; + + printf ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep.pr_fpu.fpu_tag >> (fpreg * 2)) & 3) + { + case 0: printf ("valid "); break; + case 1: printf ("zero "); break; + case 2: printf ("trap "); break; + case 3: printf ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf ("%02x", ep.pr_fpu.fpu_stack[fpreg][i]); + + i387_to_double (ep.pr_fpu.fpu_stack[fpreg], (char *)&val); + printf (" %g\n", val); + } + if (ep.pr_fpu.fpu_rsvd1) + printf ("warning: rsvd1 is 0x%x\n", ep.pr_fpu.fpu_rsvd1); + if (ep.pr_fpu.fpu_rsvd2) + printf ("warning: rsvd2 is 0x%x\n", ep.pr_fpu.fpu_rsvd2); + if (ep.pr_fpu.fpu_rsvd3) + printf ("warning: rsvd3 is 0x%x\n", ep.pr_fpu.fpu_rsvd3); + if (ep.pr_fpu.fpu_rsvd5) + printf ("warning: rsvd5 is 0x%x\n", ep.pr_fpu.fpu_rsvd5); +} + + +print_1167_control_word(pcr) +unsigned int pcr; + +{ + int pcr_tmp; + + pcr_tmp = pcr & FPA_PCR_MODE; + printf("\tMODE= %#x; RND= %#x ", pcr_tmp, pcr_tmp & 12); + switch (pcr_tmp & 12) { + case 0: + printf("RN (Nearest Value)"); + break; + case 1: + printf("RZ (Zero)"); + break; + case 2: + printf("RP (Positive Infinity)"); + break; + case 3: + printf("RM (Negative Infinity)"); + break; + } + printf("; IRND= %d ", pcr_tmp & 2); + if (0 == pcr_tmp & 2) { + printf("(same as RND)\n"); + } else { + printf("(toward zero)\n"); + } + pcr_tmp = pcr & FPA_PCR_EM; + printf("\tEM= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_EM_DM) printf(" DM"); + if (pcr_tmp & FPA_PCR_EM_UOM) printf(" UOM"); + if (pcr_tmp & FPA_PCR_EM_PM) printf(" PM"); + if (pcr_tmp & FPA_PCR_EM_UM) printf(" UM"); + if (pcr_tmp & FPA_PCR_EM_OM) printf(" OM"); + if (pcr_tmp & FPA_PCR_EM_ZM) printf(" ZM"); + if (pcr_tmp & FPA_PCR_EM_IM) printf(" IM"); + printf("\n"); + pcr_tmp = FPA_PCR_CC; + printf("\tCC= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_20MHZ) printf(" 20MHZ"); + if (pcr_tmp & FPA_PCR_CC_Z) printf(" Z"); + if (pcr_tmp & FPA_PCR_CC_C2) printf(" C2"); + if (pcr_tmp & FPA_PCR_CC_C1) printf(" C1"); + switch (pcr_tmp) { + case FPA_PCR_CC_Z: + printf(" (Equal)"); + break; + case FPA_PCR_CC_C1: + printf(" (Less than)"); + break; + case 0: + printf(" (Greater than)"); + break; + case FPA_PCR_CC_Z | FPA_PCR_CC_C1 | FPA_PCR_CC_C2: + printf(" (Unordered)"); + break; + default: + printf(" (Undefined)"); + break; + } + printf("\n"); + pcr_tmp = pcr & FPA_PCR_AE; + printf("\tAE= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_AE_DE) printf(" DE"); + if (pcr_tmp & FPA_PCR_AE_UOE) printf(" UOE"); + if (pcr_tmp & FPA_PCR_AE_PE) printf(" PE"); + if (pcr_tmp & FPA_PCR_AE_UE) printf(" UE"); + if (pcr_tmp & FPA_PCR_AE_OE) printf(" OE"); + if (pcr_tmp & FPA_PCR_AE_ZE) printf(" ZE"); + if (pcr_tmp & FPA_PCR_AE_EE) printf(" EE"); + if (pcr_tmp & FPA_PCR_AE_IE) printf(" IE"); + printf("\n"); +} + +print_1167_regs(regs) +long regs[FPA_NREGS]; + +{ + int i; + + union { + double d; + long l[2]; + } xd; + union { + float f; + long l; + } xf; + + + for (i = 0; i < FPA_NREGS; i++) { + xf.l = regs[i]; + printf("%%fp%d: raw= %#x, single= %f", i+1, regs[i], xf.f); + if (!(i & 1)) { + printf("\n"); + } else { + xd.l[1] = regs[i]; + xd.l[0] = regs[i+1]; + printf(", double= %f\n", xd.d); + } + } +} + +print_fpa_status(ep) +struct pt_regset ep; + +{ + + printf("WTL 1167:"); + if (ep.pr_fpa.fpa_pcr !=0) { + printf("\n"); + print_1167_control_word(ep.pr_fpa.fpa_pcr); + print_1167_regs(ep.pr_fpa.fpa_regs); + } else { + printf(" not in use.\n"); + } +} + +i386_float_info () + +{ + char ubuf[UPAGES*NBPG]; + struct pt_regset regset; + extern int corechan; + + if (have_inferior_p()) { + call_ptrace(XPT_RREGS, inferior_pid, ®set, 0); + } else { + if (lseek (corechan, 0, 0) < 0) { + perror ("seek on core file"); + } + if (myread (corechan, ubuf, UPAGES*NBPG) < 0) { + perror ("read on core file"); + } + /* only interested in the floating point registers */ + regset.pr_fpu = ((struct user *) ubuf)->u_fpusave; + regset.pr_fpa = ((struct user *) ubuf)->u_fpasave; + } + print_fpu_status(regset); + print_fpa_status(regset); +} + +i387_to_double (from, to) + char *from; + char *to; +{ + long *lp; + /* push extended mode on 387 stack, then pop in double mode + * + * first, set exception masks so no error is generated - + * number will be rounded to inf or 0, if necessary + */ + asm ("pushl %eax"); /* grab a stack slot */ + asm ("fstcw (%esp)"); /* get 387 control word */ + asm ("movl (%esp),%eax"); /* save old value */ + asm ("orl $0x3f,%eax"); /* mask all exceptions */ + asm ("pushl %eax"); + asm ("fldcw (%esp)"); /* load new value into 387 */ + + asm ("movl 8(%ebp),%eax"); + asm ("fldt (%eax)"); /* push extended number on 387 stack */ + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpl (%eax)"); /* pop double */ + asm ("fwait"); + + asm ("popl %eax"); /* flush modified control word */ + asm ("fnclex"); /* clear exceptions */ + asm ("fldcw (%esp)"); /* restore original control word */ + asm ("popl %eax"); /* flush saved copy */ +} + +double_to_i387 (from, to) + char *from; + char *to; +{ + /* push double mode on 387 stack, then pop in extended mode + * no errors are possible because every 64-bit pattern + * can be converted to an extended + */ + asm ("movl 8(%ebp),%eax"); + asm ("fldl (%eax)"); + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpt (%eax)"); + asm ("fwait"); +} diff --git a/gdb/tdesc.c b/gdb/tdesc.c new file mode 100755 index 00000000000..9a632e34eae --- /dev/null +++ b/gdb/tdesc.c @@ -0,0 +1,1650 @@ +/* This file has been modified by Data General Corporation, November 1989. */ + +/* +This file provides an abstract interface to "tdesc" information. + It is designed to be used in a uniform manner by several kinds + of debuggers: + (1) code in live debugged process (e.g., a traceback routine) + (2) a separate-process debugger debugging a live process + (3) a separate-process debugger debugging a memory dump + + Dcontext model notes + * captures machine context + * partial: excludes memory + * frames + * kinds + * make one for starters, chain in reverse order to previous ones + * representation: pointer to opaque + * alloc/free protocol + + Overall model + * access functions + * handle + * error handling +*/ + + + +typedef int dc_boolean_t; /* range 0 .. 1 */ +#define DC_FALSE 0 +#define DC_TRUE 1 + + +typedef int dc_tristate_t; /* range 0 .. 2 */ +#define DC_NO 0 +#define DC_YES 1 +#define DC_MAYBE 2 + + +/* + A word is 32 bits of information. In memory, a word is word-aligned. + + A common and important use of dc_word_t is to represent values in the + target process, including (byte) addresses in the target process. + In this case, C arithmetic can be used to simulate machine address + arithmetic on the target. (Unsigned arithmetic is actually modulus + arithmetic.) +*/ +typedef unsigned int dc_word_t; + + +/* These bit operations number bits from 0 at the least significant end. */ +#define bit_test(word,bit) ((word) & (1 << (bit))) /* returns 0 or other */ +#define bit_value(word,bit) (((word) >> (bit)) & 1) /* returns 0 or 1 */ +#define bit_set(word,bit) ((word) |= (1 << (bit))) +#define bit_clear(word,bit) ((word) &= ~(1 << (bit))) +#define bit_assign(word, bit, bool) \ + if (bool) bit_set(word, bit); else bit_clear(word, bit) + + +/*----------------*/ + + +/* The exactness of locations may not be certainly known. */ +typedef dc_tristate_t dc_exactness_t; + + +/* + The model includes five kinds of contexts. Because each context + has an associated region and frame, these describe region kinds + and frame kinds as well. + [more description needed] + Currently, only call contexts exist. +*/ + +typedef int dc_kind_t; /* range 0 .. 4 */ +#define DC_CALL_KIND 0 +#define DC_SAVE_KIND 1 +#define DC_EXCEPTION_KIND 2 +#define DC_PROTECTION_KIND 3 +#define DC_SPECIAL_KIND 4 +#define DC_NUM_KINDS 5 + +#define DC_MIO_ENTRY_POINT (1<< 0) +#define DC_MIO_PROLOGUE_END (1<< 1) +#define DC_MIO_EPILOGUE_START (1<< 2) +#define DC_MIO_IMPLICIT_PROLOGUE_END (1<<16) +#define DC_MIO_LITERAL_ENTRY_POINT (1<<17) +#define DC_MIO_LITERAL_EPILOGUE_START (1<<18) + +#define DC_MII_PRECEDING_TDESC_END (1<<0) +#define DC_MII_FOLLOWING_TDESC_START (1<<1) + +typedef struct dc_debug_info { + unsigned int protocol; /* 1 for this structure */ + dc_word_t tdesc_ptr; + unsigned int text_words_count; + dc_word_t text_words_ptr; + unsigned int data_words_count; + dc_word_t data_words_ptr; +} dc_debug_info_t; + + +typedef struct tdesc_hdr { + unsigned int map_protocol; /* 1 for this structure */ + unsigned int end; /* address beyond end */ +} tdesc_hdr_t; + + +typedef struct tdesc_chunk_hdr { + int zeroes : 8; + int info_length : 22; + int info_alignment : 2; + unsigned int info_protocol; + dc_word_t start_address; + dc_word_t end_address; +} tdesc_chunk_hdr_t; + + +typedef struct tdesc_chunk_info1 { + int variant : 8; /* 1 for this structure */ + int register_save_mask : 17; + int pad1 : 1; + int return_address_info_discriminant : 1; + int frame_address_register : 5; + unsigned int frame_address_offset; + unsigned int return_address_info; + unsigned int register_save_offset; +} tdesc_chunk_info1_t; + + +typedef struct tdesc_chunk1 { + tdesc_chunk_hdr_t hdr; + tdesc_chunk_info1_t info; +} tdesc_chunk1_t; + + +typedef struct dc_mstate { + dc_word_t reg[32]; /* general registers */ + dc_word_t xip; + dc_word_t nip; + dc_word_t fip; + dc_word_t fpsr; + dc_word_t fpcr; + dc_word_t psr; +} dc_mstate_t; + + +typedef struct dc_map_info_in { + dc_word_t flags; + dc_word_t preceding_tdesc_end; + dc_word_t following_tdesc_start; +} dc_map_info_in_t; + + +typedef struct dc_map_info_out { + dc_word_t flags; + dc_word_t entry_point; + dc_word_t prologue_end; + dc_word_t epilogue_start; +} dc_map_info_out_t; + + +#if 0 + + void error_fcn (env, continuable, message) + dc_word_t env; /* environment (arbitrary datum) */ + dc_boolean_t continuable; /* whether error function may return */ + char *message; /* string (no trailing newline) */ + + /* In the future, we probably want the error_fcn to be: */ + void error_fcn (env, continuable, code, ...) + dc_word_t env; /* environment (arbitrary datum) */ + dc_boolean_t continuable; /* whether error function may return */ + int code; /* error code */ + ... /* parameters to message associated + with the code */ + + void read_fcn (env, memory, length, buffer) + dc_word_t env; /* environment (arbitrary datum) */ + dc_word_t memory; /* start address in image */ + int length; /* in bytes */ + char *buffer; /* start address of buffer */ + /* There are no alignment assumptions for the read function. */ + + void write_fcn (env, memory, length, buffer) + dc_word_t env; /* environment (arbitrary datum) */ + dc_word_t memory; /* start address in image */ + int length; /* in bytes */ + char *buffer; /* start address of buffer */ + /* There are no alignment assumptions for the write function. */ + /* The write function is optional. It must be provided if changes + to writable registers are to be made. */ + + void exec_fcn (env, mstate) + dc_word_t env; /* environment (arbitrary datum) */ + dc_mstate_t *mstate; /* machine state (read-write) */ + /* The execute function is optional. It would be used (in the future) + by the implementation of a procedurally specified tdesc mechanism. */ + +#endif + +/*----------------*/ + + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern char *malloc(); +extern char *calloc(); +extern void qsort(); + + +/* + At initialization, create a tdesc table from the tdesc info. + A tdesc table is simply a sorted array of tdesc elements. + A tdesc element is the last 6 words of the tdesc chunk. + We require that all tdesc chunks have info protocol 1. +*/ + +typedef struct tdesc_elem { + dc_word_t start_address; + dc_word_t end_address; + tdesc_chunk_info1_t info; +} tdesc_elem_t; + +typedef tdesc_elem_t *tdesc_table_t; + +void dc_correct_cr_data(); + +int dc_compare_tdesc_elems (elem1, elem2) + char *elem1, *elem2; +{ + dc_word_t s1, s2, e1, e2; + s1 = ((tdesc_elem_t *) elem1)->start_address; + s2 = ((tdesc_elem_t *) elem2)->start_address; + if (s1 < s2) return -1; + if (s1 > s2) return +1; + e1 = ((tdesc_elem_t *) elem1)->end_address; + e2 = ((tdesc_elem_t *) elem2)->end_address; + if (e1 < e2) return -1; + if (e1 > e2) return +1; + return 0; +} + + +typedef struct handle_info { + dc_word_t debug_info_ptr; + void (*error_fcn)(); + dc_word_t error_env; + void (*read_fcn)(); + dc_word_t read_env; + void (*write_fcn)(); /* NULL => absent */ + dc_word_t write_env; + void (*exec_fcn)(); /* NULL => absent */ + dc_word_t exec_env; + void (*map_fcn)(); /* NULL => absent */ + dc_word_t map_env; + tdesc_table_t tdesc_table; + int tdesc_table_size; +} handle_info_t; + +typedef handle_info_t *dc_handle_t; + + +/* + Errors detected in this module are funnelled through dc_error or dc_warn, + as appropriate. Both routines call dc_exception, which invokes the error + handler supplied by the user. + + Currently, dc_exception substitutes parameters into the message given + it and passes the resulting string to the user error handler. + In the future, dc_exception should simply pass an error code and + the parameters on to the user error handler. +*/ + +#include +extern int vsprintf(); + +/* Exit status for exception-processing machinery failure */ +#define DC_EXCEPTION_FAILURE 250 + +void dc_exception(continuable, args) + dc_boolean_t continuable; + va_list args; +{ + dc_handle_t handle; + char *format; + char buffer[1024]; + + handle = va_arg(args, dc_handle_t); + format = va_arg(args, char *); + (void) vsprintf(buffer, format, args); + (*(handle->error_fcn)) (handle->error_env, continuable, buffer); + if (!continuable) + exit(DC_EXCEPTION_FAILURE); /* User error handler should never return in this case. */ +} + + +void dc_error(va_alist) /* (handle, format, args... ) */ + va_dcl +{ + va_list args; + + va_start(args); + dc_exception(DC_FALSE, args); + va_end(args); +} + + +void dc_warn(va_alist) /* (handle, format, args... ) */ + va_dcl +{ + va_list args; + + va_start(args); + dc_exception(DC_TRUE, args); + va_end(args); +} + + + +#define MALLOC_FAILURE_MESSAGE "Heap space exhausted (malloc failed)." +#define CALLOC_FAILURE_MESSAGE "Heap space exhausted (Calloc failed)." + + +/* Commonize memory allocation call so failure diagnosis is easier */ + +char* dc_malloc( handle, size ) + dc_handle_t handle; + int size; +{ + char* space = malloc( size ); + if (space == (char *)NULL) + dc_error( handle, MALLOC_FAILURE_MESSAGE ); + + return space; +} + + +/* Commonize memory allocation call so failure diagnosis is easier */ + +char* dc_calloc( handle,nelem, size ) + dc_handle_t handle; + int nelem; + int size; +{ + char* space = calloc( nelem, size ); + if (space == (char *)NULL) + dc_error( handle, CALLOC_FAILURE_MESSAGE ); + + return space; +} + + +dc_word_t dc_read_word (handle, address) + dc_handle_t handle; + dc_word_t address; +{ + dc_word_t word; + (*(handle->read_fcn)) (handle->read_env, address, + sizeof(dc_word_t), (char *)(&(word))); + return word; +} + + +void dc_write_word (handle, address, value) + dc_handle_t handle; + dc_word_t address; + dc_word_t value; +{ + dc_word_t word; + word = value; + if (handle->write_fcn) { + (*(handle->write_fcn)) (handle->write_env, address, + sizeof(dc_word_t), (char *)(&(word))); + } else { + dc_error (handle, "Writing is disabled."); + } +} + + +void dc_write_masked_word (handle, address, mask, value) + dc_handle_t handle; + dc_word_t address; + dc_word_t mask; + dc_word_t value; +{ + dc_write_word (handle, address, + (value & mask) | (dc_read_word(handle, address) & ~mask)); +} + + +dc_handle_t dc_initiate (debug_info_ptr, + error_fcn, error_env, + read_fcn, read_env, + write_fcn, write_env, + exec_fcn, exec_env, + map_fcn, map_env) + dc_word_t debug_info_ptr; + void (*error_fcn)(); + dc_word_t error_env; + void (*read_fcn)(); + dc_word_t read_env; + void (*write_fcn)(); /* NULL => absent */ + dc_word_t write_env; + void (*exec_fcn)(); /* NULL => absent */ + dc_word_t exec_env; + void (*map_fcn)(); /* NULL => absent */ + dc_word_t map_env; + /* write_fcn may be given as NULL if no writing is required. */ + /* exec_fcn may be given as NULL if no execution is required. + Currently, no execution is required. It would be if the + implementation needed to invoke procedures in the debugged process. */ +{ + dc_handle_t handle; + unsigned int debug_info_protocol; + dc_debug_info_t debug_info; + unsigned int tdesc_map_protocol; + tdesc_hdr_t tdesc_hdr; + dc_word_t tdesc_info_start; + dc_word_t tdesc_info_end; + dc_word_t tdesc_info_length; + + /* Set up handle enough for dc_error. */ + handle = (dc_handle_t) malloc(sizeof(handle_info_t)); + /* Cant use dc_malloc() as handle is being created ... */ + /* if (handle == NULL) (*error_fcn)( error_env, MALLOC_FAILURE_MESSAGE ) */ + handle->error_fcn = error_fcn; + handle->error_env = error_env; + handle->read_fcn = read_fcn; + handle->read_env = read_env; + handle->write_fcn = write_fcn; + handle->write_env = write_env; + handle->exec_fcn = exec_fcn; + handle->exec_env = exec_env; +/****************************************************************/ +/* BUG 9/19/89 Found by hls. Map functions not initialized. */ +/****************************************************************/ + handle->map_fcn = map_fcn; + handle->map_env = map_env; + handle->debug_info_ptr = debug_info_ptr; + handle->tdesc_table = (tdesc_table_t)NULL; + + /* Find tdesc info. */ + if (debug_info_ptr) { + (*read_fcn) (read_env, debug_info_ptr, sizeof(unsigned int), + (char *)(&debug_info_protocol)); + if (debug_info_protocol != 1) + dc_error (handle, "Unrecognized debug info protocol: %d", + debug_info_protocol); + (*read_fcn) (read_env, debug_info_ptr, sizeof(dc_debug_info_t), + (char *)(&debug_info)); + (*read_fcn) (read_env, debug_info.tdesc_ptr, sizeof(unsigned int), + (char *)(&tdesc_map_protocol)); + if (tdesc_map_protocol != 1) + dc_error (handle, "Unrecognized tdesc map protocol: %d", + tdesc_map_protocol); + (*read_fcn) (read_env, debug_info.tdesc_ptr, sizeof(tdesc_hdr_t), + (char *)(&tdesc_hdr)); + tdesc_info_start = debug_info.tdesc_ptr + sizeof(tdesc_hdr_t); + tdesc_info_end = tdesc_hdr.end; + tdesc_info_length = tdesc_info_end - tdesc_info_start; + + /* Create tdesc table from tdesc info. */ + { + /* Over-allocate in order to avoid second pass over tdesc info. */ + tdesc_table_t tt = (tdesc_table_t) dc_malloc(handle, tdesc_info_length); + dc_word_t p = tdesc_info_start; + dc_word_t q = tdesc_info_end - sizeof(tdesc_chunk1_t); + int n = 0; + tdesc_chunk1_t chunk; + dc_word_t start_address, end_address; + int i; + + for (; p <= q; ) { + (*read_fcn) (read_env, p, sizeof(tdesc_chunk1_t), (char *)(&chunk)); + if (chunk.hdr.zeroes != 0) { + /* Skip padding. */ + p += sizeof(dc_word_t); + continue; + } + if (chunk.hdr.info_protocol != 1) { + dc_warn (handle, "Unrecognized tdesc info protocol: %d", + chunk.hdr.info_protocol); + goto next_chunk; + } + if (chunk.hdr.info_length != 16) { + dc_warn (handle, "Incorrect tdesc info length: %d", + chunk.hdr.info_length); + goto next_chunk; + } + if (chunk.hdr.info_alignment > 2) { + dc_warn (handle, "Incorrect tdesc info alignment: %d", + chunk.hdr.info_alignment); + goto next_chunk; + } + start_address = chunk.hdr.start_address; + end_address = chunk.hdr.end_address; + if ((start_address&3)!=0) { + dc_warn (handle, + "Tdesc start address is not word-aligned: %#.8X", + start_address); + goto next_chunk; + } + if ((end_address&3)!=0) { + dc_warn (handle, + "Tdesc end address is not word-aligned: %#.8X", + end_address); + goto next_chunk; + } + if (start_address > end_address) { + /* Note that the range may be null. */ + dc_warn (handle, + "Tdesc start address (%#.8X) follows end address (%#.8X).", + start_address, end_address); + goto next_chunk; + } + if (chunk.info.variant != 1) { + dc_warn (handle, "Invalid tdesc chunk variant: %d", + chunk.info.variant); + goto next_chunk; + } + if (chunk.info.pad1 != 0) { + dc_warn (handle, "Tdesc chunk padding is not zero."); + goto next_chunk; + } + if (chunk.info.return_address_info_discriminant != 0) { + if ((chunk.info.return_address_info & 3) != 0) { + dc_warn (handle, + "Tdesc return address offset is not word-aligned: %#.8X", + chunk.info.return_address_info); + goto next_chunk; + } + } else { + if ((chunk.info.return_address_info & ~31) != 0) { + dc_warn (handle, + "Invalid tdesc return address register: %d", + chunk.info.return_address_info); + goto next_chunk; + } + } + if ((chunk.info.register_save_offset & 3) != 0) { + dc_warn (handle, + "Tdesc register save offset is not word-aligned: %#.8X", + chunk.info.register_save_offset); + goto next_chunk; + } + + tt[n].start_address = start_address; + tt[n].end_address = end_address; + tt[n].info = chunk.info; + n++; + + next_chunk: + p += sizeof(tdesc_chunk1_t); + } + /* Leftover (less than a tdesc_chunk1_t in size) is padding or + in error. Ignore it in either case. */ + + if (n != 0) { + + /* Sort table by start address. */ + qsort ((char *)tt, n, sizeof(tdesc_elem_t), dc_compare_tdesc_elems); + + /* Check for overlap among tdesc chunks. */ + for (i=0; i<(n-1); i++) { + if (tt[i].end_address > tt[i+1].start_address) + dc_error (handle, "Text chunks overlap."); + } + } + + /* Finish setting up handle. */ + handle->tdesc_table = tt; + handle->tdesc_table_size = n; + } + } else { + handle->tdesc_table_size = 0; + } + + return (dc_handle_t) handle; +} + + +void dc_terminate (handle) + dc_handle_t handle; +{ + if (((dc_handle_t)handle)->tdesc_table) { + free((char *)(((dc_handle_t)handle)->tdesc_table)); + } + free((char *)handle); +} + + + +/* + + Dcontext Model + + For each interesting register (word-sized piece of machine state), + a word of value information is kept. This word may + be either the value of the register, or the address in + subject memory where the value can be found (and changed). In + addition, the register may be invalid (in which case the value + information is undefined). These three cases are encoded for + a given register in the same-numbered bit of two words of flags: + + flags[0] bit flags[1] bit meaning + ------------ ------------ ------- + 0 0 register is invalid; info is undefined + 0 1 register is readable; info is value + 1 0 register is writable; info is address + 1 1 (reserved) + + The general registers (r0-r31) are handled by reg_info and + reg_flags. The bit number for a register is that register's number. + The other registers are grouped together for convenience and are + handled by aux_info and aux_flags. The bit numbers for these + registers are: + + bit number register + ---------- -------- + 0 location + 1 SXIP + 2 SNIP + 3 SFIP + 4 FPSR + 5 FPCR + + The SXIP, SNIP, and SFIP are the exception-time values of the + XIP, NIP, and FIP registers. They are valid only in the topmost frame. + (That is, in any context obtained from dc_previous_context, they + are invalid.) + + "location" is a pseudo-register of this model and represents the + location of the context. It is always valid. It also has an + exactness associated with it. The location and its exactness of a + context obtained from dc_previous_context are taken from the + return address and its exactness of the context given as an argument + to dc_previous_context. + + The following model is recommended for dealing with the partial + redundancy between location and the SXIP, SNIP, and SFIP values + in the topmost frame. The location should be set to either the + SNIP or SXIP value, and its exactness should be set to DC_NO. A + change to the register whose value the location is set to should + be accompanied by an identical change to the location. + + The PSR is handled separately, because it is a diverse collection + of flags. The PSR, as a whole, is always valid. A separate + psr_ind flag tells whether the psr_info data is a value or + an address. Each bit of the PSR has its own pair of flag bits to + mark validity and writability. + +*/ + + +/* The following value means "other", because state is stored in 2 bits. */ +#define DC_RESERVED 3 + + +#define RSTATE(flags, bit) \ + ((bit_value((flags)[0], bit) << 1) + bit_value((flags)[1], bit)) + +#define REG_STATE(dcontext, reg) RSTATE(dcontext->reg_flags, reg) +#define AUX_STATE(dcontext, reg) RSTATE(dcontext->aux_flags, reg) +#define PSR_STATE(dcontext, reg) RSTATE(dcontext->psr_flags, reg) + + +#define SET_INVALID(flags, bit) \ + { bit_clear ((flags)[0], bit); bit_clear ((flags)[1], bit); } + +#define SET_READABLE(flags, bit) \ + { bit_clear ((flags)[0], bit); bit_set ((flags)[1], bit); } + +#define SET_WRITABLE(flags, bit) \ + { bit_set ((flags)[0], bit); bit_clear ((flags)[1], bit); } + +#define ASSIGN_RSTATE(to_flags, to_bit, from_flags, from_bit) \ + { bit_assign ((to_flags)[0], to_bit, bit_value((from_flags)[0], from_bit));\ + bit_assign ((to_flags)[1], to_bit, bit_value((from_flags)[1], from_bit));} + + +#define CHECK_REG_READ(dcontext, reg) \ + if (REG_STATE(dcontext, reg) == DC_INVALID) \ + dc_error (dcontext->handle, \ + "General register %d is not readable.", reg) + +#define CHECK_REG_WRITE(dcontext, reg) \ + if (REG_STATE(dcontext, reg) != DC_WRITABLE) \ + dc_error (dcontext->handle, \ + "General register %d is not writable.", reg) + +#define CHECK_AUX_READ(dcontext, reg) \ + if (AUX_STATE(dcontext, reg) == DC_INVALID) \ + dc_error (dcontext->handle, \ + "Auxiliary register %d is not readable.", reg) + +#define CHECK_AUX_WRITE(dcontext, reg) \ + if (AUX_STATE(dcontext, reg) != DC_WRITABLE) \ + dc_error (dcontext->handle, \ + "Auxiliary register %d is not writable.", reg) + + + +#define DC_REG_RA 1 +#define DC_REG_FP 30 +#define DC_REG_SP 31 +#define DC_NUM_REG 32 + +#define DC_AUX_LOC 0 + /* DC_AUX_LOC must be first, with value 0 */ +#define DC_AUX_SXIP 1 +#define DC_AUX_SNIP 2 +#define DC_AUX_SFIP 3 +#define DC_AUX_FPSR 4 +#define DC_AUX_FPCR 5 +#define DC_NUM_AUX 6 + + + +#define CHECK_REG(dcontext, reg) \ + if ((reg < 0) || (reg >= DC_NUM_REG)) \ + dc_error (dcontext->handle, \ + "Bad general register number: %d", reg) + +#define CHECK_AUX(dcontext, reg) \ + if ((reg < 1) || (reg >= DC_NUM_AUX)) \ + dc_error (dcontext->handle, \ + "Bad auxiliary register number: %d", reg) + /* CHECK_AUX is not used for location pseudo-register. */ + +#define CHECK_BIT(dcontext, bit) \ + if ((bit < 0) || (bit >= 32)) \ + dc_error (dcontext->handle, \ + "Bad bit number: %d", bit) + + + +typedef struct cr_value { + int reg; + unsigned int off; + } dc_cr_value_t; + +#define DC_UNDEF 32 + +/* + A "dc_cr_value" represents an execution-time value symbolically, in + terms of the initial value of a register (the value on entry to + the procedure being analyzed) and a known offset. A value with + a 'reg' field value of 0 through 31 represents the value obtained + by summing (using 32-bit modulus arithmetic) the initial value of + register 'reg' and the value 'off'. Note that the value (0,k) + represents the constant value k, that (31,0) represents the CFA, and + that (1,0) represents the return address. A value with a 'reg' field + of DC_UNDEF represents an indeterminable value; in this case the + 'off' field is undefined. Other values of 'reg' are erroneous. +*/ + +typedef struct cr_data { + dc_cr_value_t reg_val[DC_NUM_REG]; + dc_word_t saved; + dc_word_t how; + unsigned int where[DC_NUM_REG]; +} dc_cr_data_t; + +/* + 'cr_data' collects all the information needed to represent the + symbolic machine state during code reading. + + The 'reg_val' array gives the current dc_cr_value for each register. + + The 'saved', 'how', and 'where' fields combine to describe what + registers have been saved, and where. The 'saved' and 'how' fields + are implicitly bit arrays over 0..31, where the numbering is from + 0 on the right. (Hence, 1<handle, dcontext->reg_info, dcontext->reg_flags, reg) + +#define SET_REG_VALUE(dcontext, reg, value) \ + dc_set_value(dcontext->handle, dcontext->reg_info, dcontext->reg_flags, reg, \ + value) + +#define GET_AUX_VALUE(dcontext, reg) \ + dc_get_value(dcontext->handle, dcontext->aux_info, dcontext->aux_flags, reg) + +#define SET_AUX_VALUE(dcontext, reg, value) \ + dc_set_value(dcontext->handle, dcontext->aux_info, dcontext->aux_flags, reg, \ + value) + + + +void dc_check_dcontext (dc) + dc_dcontext_t dc; + /* Check consistency of information supplied to make a dcontext. */ +{ + int i; + + if ((REG_STATE(dc, 0) != DC_READABLE) || (dc->reg_info[0] != 0)) + dc_error (dc->handle, "Register 0 is misspecified"); + for (i = 1; i < DC_NUM_REG; i++) + if (REG_STATE(dc, i) == DC_RESERVED) + dc_error (dc->handle, + "State for general register %d is incorrect", i); + for (i = 0; i < DC_NUM_AUX; i++) + if (AUX_STATE(dc, i) == DC_RESERVED) + dc_error (dc->handle, + "State for auxiliary register %d is incorrect", i); + if (AUX_STATE(dc, DC_AUX_LOC) == DC_INVALID) + dc_error (dc->handle, "Location is specified as invalid"); + if (GET_AUX_VALUE(dc, DC_AUX_LOC) == 0) + dc_error (dc->handle, "Location is zero."); + if (dc->loc_exact >= 3) + dc_error (dc->handle, "Location exactness is incorrectly specified: %d", + dc->loc_exact); + if (dc->psr_ind >= 2) + dc_error (dc->handle, + "PSR indirection flag is incorrectly specified: %d", + dc->psr_ind); + for (i = 0; i < 32; i++) + if (PSR_STATE(dc, i) == DC_RESERVED) + dc_error (dc->handle, "State for PSR bit %d is incorrect", i); +} + + + +tdesc_elem_t * dc_tdesc_lookup (loc, tt, tt_size, map_info_in_ptr) + dc_word_t loc; + tdesc_table_t tt; + int tt_size; + dc_map_info_in_t *map_info_in_ptr; + /* Return address of tdesc_elem_t for given location, or NULL if + there is no tdesc chunk for the location. + */ +{ + int l = 0; + int h = tt_size; + int m; + + if (tt_size == 0) { + map_info_in_ptr->flags = 0; + return (tdesc_elem_t *)NULL; + } + for (;;) { + m = (l + h) / 2; + if (m == l) break; + if (loc >= tt[m].start_address) + l = m; + else + h = m; + } + if (loc >= tt[m].end_address) { + map_info_in_ptr->preceding_tdesc_end = tt[m].end_address; + if (m+1 < tt_size) { + map_info_in_ptr->following_tdesc_start = tt[m+1].start_address; + map_info_in_ptr->flags = DC_MII_PRECEDING_TDESC_END | + DC_MII_FOLLOWING_TDESC_START; + } else { + map_info_in_ptr->flags = DC_MII_PRECEDING_TDESC_END; + } + return (tdesc_elem_t *)NULL; + } else if (loc < tt[m].start_address) { + map_info_in_ptr->following_tdesc_start = tt[m].start_address; + map_info_in_ptr->flags = DC_MII_FOLLOWING_TDESC_START; + return (tdesc_elem_t *)NULL; + } else { + return (&tt[m]); + } +} + + + +dc_dcontext_t dc_make_dcontext (handle, + reg_info, reg_flags, + aux_info, aux_flags, loc_exact, + psr_info, psr_ind, psr_flags) + dc_handle_t handle; + dc_word_t reg_info[DC_NUM_REG]; + dc_word_t reg_flags[2]; + dc_word_t aux_info[DC_NUM_AUX]; + dc_word_t aux_flags[2]; + dc_exactness_t loc_exact; + dc_word_t psr_info; + dc_boolean_t psr_ind; + dc_word_t psr_flags[2]; +{ + dc_dcontext_t dc = (dc_dcontext_t) dc_malloc (handle, sizeof(dcontext_info_t)); + int i; + dc_map_info_in_t map_info_in; + + /* Fill in supplied content. */ + dc->handle = ((dc_handle_t)handle); + for (i = 0; i < DC_NUM_REG; i++) dc->reg_info[i] = reg_info[i]; + for (i = 0; i < 2; i++) dc->reg_flags[i] = reg_flags[i]; + for (i = 0; i < DC_NUM_AUX; i++) dc->aux_info[i] = aux_info[i]; + for (i = 0; i < 2; i++) dc->aux_flags[i] = aux_flags[i]; + dc->loc_exact = loc_exact; + dc->psr_info = psr_info; + dc->psr_ind = psr_ind; + for (i = 0; i < 2; i++) dc->psr_flags[i] = psr_flags[i]; + + dc_check_dcontext(dc); + + /* Find tdesc information for the text chunk. */ + { +/***************************************************************/ +/* BUG 8/16/89 Found by hls. Not zeroing EV bits of location. */ +/* SHOULD USE dc_location()! */ +/* dc_word_t loc = GET_AUX_VALUE(dc, DC_AUX_LOC); */ +/***************************************************************/ + dc_word_t loc = GET_AUX_VALUE(dc, DC_AUX_LOC) & ~3; + tdesc_elem_t *tep = + dc_tdesc_lookup(loc, ((dc_handle_t)handle)->tdesc_table, + ((dc_handle_t)handle)->tdesc_table_size,&map_info_in); + if (tep) { + dc->code_reading = 0; + dc->info_ptr.tdesc_elem_ptr = tep; + } else { + dc->code_reading = 1; + if (!dc->handle->map_fcn) { + dc_error (dc->handle, "No tdesc information for %#.8X and no map function supplied.",loc); + } +/****************************************************************/ +/* BUG 9/18/89 Found by hls. Not using dc_malloc() */ +/* dc->info_ptr.cr_data_ptr= (dc_cr_data_t *)malloc(sizeof(dc_cr_data_t )); */ +/****************************************************************/ + dc->info_ptr.cr_data_ptr= (dc_cr_data_t *)dc_calloc(dc->handle,1,sizeof(dc_cr_data_t )); + dc_read_code(loc,dc,map_info_in,dc->info_ptr.cr_data_ptr); + } + } + + return (dc_dcontext_t) dc; +} + + + +void dc_free_dcontext (dcontext) + dc_dcontext_t dcontext; +{ +/****************************************************************/ +/* BUG 9/19/89 Found by hls. Freeing non-pointer value. */ +/* free((char *)dcontext->code_reading); */ +/****************************************************************/ + if (dcontext->code_reading) + free((char *)dcontext->info_ptr.cr_data_ptr); + free((char *)dcontext); +} + + + +dc_register_state_t dc_location_state (dcontext) + dc_dcontext_t dcontext; +{ + return AUX_STATE(((dc_dcontext_t)dcontext), DC_AUX_LOC); +} + + +dc_exactness_t dc_location_exactness (dcontext) + dc_dcontext_t dcontext; +{ + return ((dc_dcontext_t)dcontext)->loc_exact; +} + + +dc_word_t dc_location (dcontext) + dc_dcontext_t dcontext; + /* Return high 30 bits only. */ +{ + /* Don't need: CHECK_AUX_READ (((dc_dcontext_t)dcontext), DC_AUX_LOC); */ + return GET_AUX_VALUE (((dc_dcontext_t)dcontext), DC_AUX_LOC) & ~3; +} + + +dc_boolean_t dc_location_in_text_chunk( dcontext, value ) + dc_dcontext_t dcontext; + dc_word_t value; +{ + /* Check that new location is still within same text chunk. */ + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; +/********************************************************************/ +/* Bug in predicate -- LS adjusted according to OCS documentation.. */ +/* if ((value < tep->start_address) || (value >= tep->end_address))*/ +/********************************************************************/ + if ((value >= tep->start_address) && (value < tep->end_address)) + return DC_TRUE; + else + return DC_FALSE; + +} + + +void dc_set_location (dcontext, value) + dc_dcontext_t dcontext; + dc_word_t value; + /* Set high 30 bits only. */ +{ + if (dc_location_in_text_chunk( dcontext, value ) != DC_TRUE) + dc_warn (((dc_dcontext_t)dcontext)->handle, + "New location is not in same text chunk."); + + CHECK_AUX_WRITE (((dc_dcontext_t)dcontext), DC_AUX_LOC); + dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, + ((dc_dcontext_t)dcontext)->aux_info[DC_AUX_LOC], ~3, value); +} + + + +dc_register_state_t dc_general_register_state (dcontext, reg) + dc_dcontext_t dcontext; + int reg; +{ + CHECK_REG (((dc_dcontext_t)dcontext), reg); + return REG_STATE(((dc_dcontext_t)dcontext), reg); +} + + +dc_word_t dc_general_register (dcontext, reg) + dc_dcontext_t dcontext; + int reg; +{ + CHECK_REG (((dc_dcontext_t)dcontext), reg); + CHECK_REG_READ (((dc_dcontext_t)dcontext), reg); + return GET_REG_VALUE(((dc_dcontext_t)dcontext), reg); +} + + +void dc_set_general_register (dcontext, reg, value) + dc_dcontext_t dcontext; + int reg; + dc_word_t value; +{ + CHECK_REG (((dc_dcontext_t)dcontext), reg); + CHECK_REG_WRITE (((dc_dcontext_t)dcontext), reg); + SET_REG_VALUE (((dc_dcontext_t)dcontext), reg, value); +} + + + +dc_register_state_t dc_auxiliary_register_state (dcontext, reg) + dc_dcontext_t dcontext; + int reg; +{ + CHECK_AUX (((dc_dcontext_t)dcontext), reg); + return AUX_STATE(((dc_dcontext_t)dcontext), reg); +} + + +dc_word_t dc_auxiliary_register (dcontext, reg) + dc_dcontext_t dcontext; + int reg; +{ + CHECK_AUX (((dc_dcontext_t)dcontext), reg); + CHECK_AUX_READ (((dc_dcontext_t)dcontext), reg); + return GET_AUX_VALUE(((dc_dcontext_t)dcontext), reg); +} + + +void dc_set_auxiliary_register (dcontext, reg, value) + dc_dcontext_t dcontext; + int reg; + dc_word_t value; +{ + CHECK_AUX (((dc_dcontext_t)dcontext), reg); + CHECK_AUX_WRITE (((dc_dcontext_t)dcontext), reg); + SET_AUX_VALUE (((dc_dcontext_t)dcontext), reg, value); +} + + + +dc_register_state_t dc_psr_register_bit_state (dcontext, bit) + dc_dcontext_t dcontext; + int bit; +{ + CHECK_BIT (((dc_dcontext_t)dcontext), bit); + return PSR_STATE(((dc_dcontext_t)dcontext), bit); +} + + +dc_word_t dc_psr_register (dcontext) + dc_dcontext_t dcontext; +{ + if (((dc_dcontext_t)dcontext)->psr_ind) { + return dc_read_word(((dc_dcontext_t)dcontext)->handle, + ((dc_dcontext_t)dcontext)->psr_info); + } else { + return ((dc_dcontext_t)dcontext)->psr_info; + } +} + + +void dc_set_psr_register (dcontext, mask, value) + dc_dcontext_t dcontext; + dc_word_t mask; + dc_word_t value; + /* Set bits of PSR corresponding to 1 bits in mask. */ +{ + if (((dc_dcontext_t)dcontext)->psr_ind) { + if (((((dc_dcontext_t)dcontext)->psr_flags[0] & mask) != mask) || + ((((dc_dcontext_t)dcontext)->psr_flags[1] & mask) != 0)) + dc_error (((dc_dcontext_t)dcontext)->handle, + "Some PSR bits specified are not writable."); + dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, + ((dc_dcontext_t)dcontext)->psr_info, mask, value); + } else { + dc_error (((dc_dcontext_t)dcontext)->handle, "PSR is not writable."); + } +} + + + +dc_word_t dc_frame_address (dcontext) + dc_dcontext_t dcontext; +{ + if (!dcontext->code_reading) { + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; + return dc_general_register(dcontext, + tep->info.frame_address_register) + tep->info.frame_address_offset; + } else { + if (dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_FP].reg == DC_REG_SP) { + return (dc_general_register(dcontext,DC_REG_FP) + - dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_FP].off); + } + if (dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_SP].reg == DC_REG_SP) { + return (dc_general_register(dcontext,DC_REG_SP) + - dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_SP].off); + } + dc_error (((dc_dcontext_t)dcontext)->handle, "Cannot locate frame pointer."); + } +} + + + +dc_kind_t dc_context_kind (dcontext) + dc_dcontext_t dcontext; +{ + return DC_CALL_KIND; +} + + + + +/* operations valid for call contexts only */ + + +dc_register_state_t dc_return_address_state (dcontext) + dc_dcontext_t dcontext; +{ + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; + int reg; + + if (!dcontext->code_reading) { + if (tep->info.return_address_info_discriminant) { + return DC_WRITABLE; + } else { + return REG_STATE(((dc_dcontext_t)dcontext), tep->info.return_address_info); + } + } else { + reg= DC_REG_RA; + if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,DC_REG_RA)) { + if (bit_test(dcontext->info_ptr.cr_data_ptr->how,DC_REG_RA)) { + return DC_WRITABLE; + } else { + reg= dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]; + } + } + return REG_STATE(((dc_dcontext_t)dcontext),reg); + + + } +} + + +dc_exactness_t dc_return_address_exactness (dcontext) + dc_dcontext_t dcontext; +{ + return DC_MAYBE; +} + + +dc_word_t dc_return_address (dcontext) + dc_dcontext_t dcontext; + /* Return high 30 bits only. */ +{ + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; + dc_word_t rai = tep->info.return_address_info; + dc_word_t val; + int reg; + + if (!dcontext->code_reading) { + if (tep->info.return_address_info_discriminant) { + val = dc_read_word (((dc_dcontext_t)dcontext)->handle, + dc_frame_address(dcontext) + rai); + } else { + val = dc_general_register (dcontext, rai); + } + } else { + reg=DC_REG_RA; + if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,reg)) { + if (bit_test(dcontext->info_ptr.cr_data_ptr->how,reg)) { + val = dc_read_word (((dc_dcontext_t)dcontext)->handle, + dc_frame_address(dcontext) + + (dcontext->info_ptr.cr_data_ptr->where[reg])); + } else { + reg= dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]; + val = dc_general_register (dcontext, reg); + } + } else { + val = dc_general_register (dcontext, reg); + } + } + return val & ~3; +} + + +void dc_set_return_address (dcontext, value) + dc_dcontext_t dcontext; + dc_word_t value; + /* Set high 30 bits only. */ +{ + if (!dcontext->code_reading) { + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; + dc_word_t rai = tep->info.return_address_info; + + if (tep->info.return_address_info_discriminant) { + dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, + dc_frame_address(dcontext) + rai, ~3, value); + } else { + dc_set_general_register (dcontext, rai, + (value & ~3) | (dc_general_register(dcontext, rai) & 3)); + } + } else { + if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,DC_REG_RA)) { + if (bit_test(dcontext->info_ptr.cr_data_ptr->how,DC_REG_RA)) { + dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, + dc_frame_address(dcontext) + + dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA], ~3, value); + } else { + dc_set_general_register( dcontext, + dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]); + } + } else { + dc_set_general_register( dcontext, + dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]); + } + } +} + + + +/* operations valid for save contexts only */ + +/* (none) */ + + + +/* operations valid for exception contexts only */ + + +void dc_get_exception_info (dcontext, handler, datum) + dc_dcontext_t dcontext; + dc_word_t *handler; + dc_word_t *datum; +{ + dc_error (((dc_dcontext_t)dcontext)->handle, + "dc_get_exception_info is not yet implemented."); +} + + + +/* operations valid for protection contexts only */ + + +void dc_get_protection_info (dcontext, handler, datum) + dc_dcontext_t dcontext; + dc_word_t *handler; + dc_word_t *datum; +{ + dc_error (((dc_dcontext_t)dcontext)->handle, + "dc_get_protection_info is not yet implemented."); +} + + + +/* operations valid for special contexts only */ + + +void dc_get_special_info (dcontext, kind, datum) + dc_dcontext_t dcontext; + dc_word_t *kind; + dc_word_t *datum; +{ + dc_error (((dc_dcontext_t)dcontext)->handle, + "dc_get_special_info is not yet implemented."); +} + + + +/* operations valid for all contexts (again) */ + + +dc_dcontext_t dc_previous_dcontext (dcontext) + dc_dcontext_t dcontext; + /* Return NULL if there is no previous context. */ +{ + dc_dcontext_t old = (dc_dcontext_t) dcontext; + dcontext_info_t new; /* to serve as temporary storage only */ + tdesc_elem_t *tep; + dc_cr_data_t *cdp; + dc_word_t cfa; + int rsm; + dc_word_t offset; + dc_word_t rai; + int r; + + if (dc_return_address_state((dc_dcontext_t)old) == DC_INVALID) + dc_error (old->handle, "Return address is invalid."); + + if (dc_return_address((dc_dcontext_t)old) == 0) + return (dc_dcontext_t)NULL; /* end of the chain */ + + /* Copy over old contents. */ + new = *old; + + cfa = dc_frame_address(old); + /* Restore stack pointer. */ + new.reg_info[DC_REG_SP] = cfa; + SET_READABLE (new.reg_flags, DC_REG_SP); + + /* Invalidate temporary registers. */ + for (r = 1; r <= 13; r++) SET_INVALID (new.reg_flags, r); + + if (!old->code_reading) { + tep = old->info_ptr.tdesc_elem_ptr; + /* Restore preserved registers. */ + rsm = tep->info.register_save_mask; + offset = cfa + tep->info.register_save_offset; + for (r = 14; r <= 30; r++) { + if (bit_test(rsm, 30-r)) { + new.reg_info[r] = offset; + SET_WRITABLE (new.reg_flags, r); + offset += sizeof(dc_word_t); + } + } + + /* Set location from old return address. */ + rai = tep->info.return_address_info; + if (tep->info.return_address_info_discriminant) { + new.aux_info[DC_AUX_LOC] = cfa + rai; + SET_WRITABLE (new.aux_flags, DC_AUX_LOC); + } else { + new.aux_info[DC_AUX_LOC] = old->reg_info[rai]; + ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, old->reg_flags, rai); + } + } else { + cdp = old->info_ptr.cr_data_ptr; + + /* Restore preserved registers. */ + for (r = 14; r <= 30; r++) { + if (bit_test(cdp->saved,r)) { + if (bit_test(cdp->how,r)){ /* saved in the frame */ + new.reg_info[r] = cfa+cdp->where[r]; + SET_WRITABLE (new.reg_flags, r); + } else { /* saved in the in a register */ + new.reg_info[r] = dc_general_register(old,cdp->where[r]); + ASSIGN_RSTATE (new.aux_flags, r, old->reg_flags, cdp->where[r]); + } + } /* not saved, therefore, already valid , no else*/ + } + + /* Set location from old return address. */ + if (bit_test(cdp->saved,DC_REG_RA)) { + if (bit_test(cdp->how,DC_REG_RA)){ /* saved in the frame */ + new.aux_info[DC_AUX_LOC] = + new.reg_info[DC_REG_RA] = cfa+cdp->where[DC_REG_RA]; + SET_WRITABLE (new.reg_flags, DC_REG_RA); + SET_WRITABLE (new.aux_flags, DC_AUX_LOC); + } else { /* saved in the in a register */ + new.reg_info[DC_REG_RA] = + new.aux_info[DC_AUX_LOC] = + dc_general_register(old,cdp->where[DC_REG_RA]); + ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, + old->reg_flags, cdp->where[DC_REG_RA]); + } + } else { /* not saved, therefore, already valid , set DC_AUX_LOC only*/ + new.aux_info[DC_AUX_LOC] = + dc_general_register(old,DC_REG_RA); + ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, + old->reg_flags, DC_REG_RA); + } + } + + /* Invalidate instruction pointers. */ + SET_INVALID (new.aux_flags, DC_AUX_SXIP); + SET_INVALID (new.aux_flags, DC_AUX_SNIP); + SET_INVALID (new.aux_flags, DC_AUX_SFIP); + + /* No change to FCR registers. */ + + /* No change to PSR register. */ + + return dc_make_dcontext ((dc_handle_t)new.handle, + new.reg_info, new.reg_flags, + new.aux_info, new.aux_flags, new.loc_exact, + new.psr_info, new.psr_ind, new.psr_flags); +} + + + +/* extensions for nonlocal goto */ + +#if 0 + +typedef + struct label { + ??? + } label_t; + + +label_t dc_make_label (dcontext, location) + dc_dcontext_t dcontext; + dc_word_t location; +{ +} + +#endif + +/* procedure for reading code */ + +dc_read_code(loc,dc,map_info_in,cdp) +dc_word_t loc; +dc_dcontext_t dc; +dc_cr_data_t *cdp; +dc_map_info_in_t map_info_in; +{ +dc_map_info_out_t map_info_out; +dc_word_t pc; +dc_boolean_t found_branch=DC_FALSE; +dc_word_t instr; + + (*dc->handle->map_fcn)(dc->handle->map_env,loc,map_info_in,&map_info_out); + if (map_info_out.flags & DC_MIO_ENTRY_POINT + && (!(map_info_in.flags & DC_MII_PRECEDING_TDESC_END) + || map_info_out.entry_point >= map_info_in.preceding_tdesc_end + || map_info_out.flags & DC_MIO_LITERAL_ENTRY_POINT)) { + dc_init_cr_data(cdp,(tdesc_elem_t *)NULL); + pc= map_info_out.entry_point; + } else if (map_info_in.flags & DC_MII_PRECEDING_TDESC_END) { + /**/ + /* tdesc_lookup gets the tep for the preceeding tdesc information + /* so we call it with one less than the preceding tdesc end since + /* tdesc information is exclusive of the ending address + /**/ + dc_init_cr_data(cdp, + dc_tdesc_lookup(map_info_in.preceding_tdesc_end-1, + ((dc_handle_t)dc->handle)->tdesc_table, + ((dc_handle_t)dc->handle)->tdesc_table_size, + &map_info_in)); + pc= map_info_in.preceding_tdesc_end; + } else { + dc_error (dc->handle, "Insufficient information for code reading."); + } + for (;;pc+=4) { + if (pc==loc) { + return (DC_TRUE); + } + instr= dc_read_word(dc->handle,pc); + found_branch= dc_decode_finds_branch(dc,instr); + if ((map_info_out.flags & DC_MIO_PROLOGUE_END) + && (pc==map_info_out.prologue_end)) { + break; + } + if (found_branch) { + if (DC_MIO_IMPLICIT_PROLOGUE_END & map_info_out.flags) { + break; + } else { + dc_error (dc->handle, "Found branch before end of prologue."); + } + } + } + if (!(map_info_out.flags & DC_MIO_LITERAL_EPILOGUE_START) + && (map_info_out.epilogue_start >= loc + || !(map_info_out.flags & DC_MIO_EPILOGUE_START))) { + return (DC_TRUE); + } + dc_correct_cr_data(cdp,dc->handle); + for (pc=map_info_out.epilogue_start;pchandle,pc); + if (dc_decode_finds_branch(dc,instr)) { + return (DC_FALSE); + } + } + return (DC_TRUE); + +} + + + +dc_init_cr_data(cdp,tep) +dc_cr_data_t *cdp; +tdesc_elem_t *tep; +{ +int reg; +dc_word_t rai; +dc_word_t raid; +dc_word_t rsm; +dc_word_t frpos; + + if (tep){ + + /* Start off with all registers undefined and none saved. */ + for (reg = 0; reg < DC_NUM_REG; reg++) { + cdp->reg_val[reg].reg = DC_UNDEF; + } + cdp->saved = 0; + + /* Overwrite with what tdesc element says. */ + + cdp->reg_val[tep->info.frame_address_register].reg = DC_REG_SP; + cdp->reg_val[tep->info.frame_address_register].off = + - tep->info.frame_address_offset; + + rai = tep->info.return_address_info; + raid = tep->info.return_address_info_discriminant; + if (raid || rai != DC_REG_RA) { + bit_set(cdp->saved,DC_REG_RA); + bit_assign(cdp->how,DC_REG_RA,raid); + cdp->where[DC_REG_RA] = rai; + } + + rsm = tep->info.register_save_mask; + frpos = tep->info.register_save_offset; + for (reg = 14; reg <= 30; reg++) { + if (bit_test(rsm, 30-reg)) { + bit_set(cdp->saved,reg); + bit_set(cdp->how,reg); + cdp->where[reg] = frpos; + frpos += sizeof(dc_word_t); + } else { + cdp->reg_val[reg].reg = reg; + cdp->reg_val[reg].off = 0; + } + } + + cdp->reg_val[0].reg = 0; /* guarantee what hardware does */ + cdp->reg_val[0].off = 0; + + } else { + /* Each register has its own initial value. */ + for (reg = 0; reg < DC_NUM_REG; reg++) { + cdp->reg_val[reg].reg = reg; + cdp->reg_val[reg].off = 0; + } + /* No register is yet saved. */ + cdp->saved = 0; + cdp->how = 0; + } +} +void dc_correct_cr_data(cdp,handle) +dc_cr_data_t *cdp; +dc_handle_t handle; +{ +long sr,r; +dc_word_t save_regs = 0; /* registers used to save others */ + for (r = 1; r < DC_REG_SP; r++) { + if (bit_test(cdp->saved,r) && !bit_test(cdp->how,r)) { + sr = cdp->where[r]; + if (bit_test(save_regs,sr)) { + dc_error(handle, "Same register used to save two others."); + } + bit_set(save_regs,sr); + } + } + for (r = 1; r < DC_REG_FP; r++) { + if ((r < 14 || bit_test(cdp->saved,r)) && !bit_test(save_regs,r)) { + cdp->reg_val[r].reg = DC_UNDEF; + } + } + if (bit_test(cdp->saved,DC_REG_FP) && + cdp->reg_val[DC_REG_FP].reg == DC_REG_SP) { /* is r30 the far? */ + cdp->reg_val[DC_REG_SP].reg = DC_UNDEF; /* trash sp */ + } else if (cdp->reg_val[DC_REG_SP].reg == DC_REG_SP) { /* is r31 the far? */ + if (bit_test(cdp->saved,DC_REG_FP) && !bit_test(save_regs,DC_REG_FP)) { + cdp->reg_val[DC_REG_FP].reg = DC_UNDEF; /* trash r30 */ + } + } +} diff --git a/gdb/tdesc.h b/gdb/tdesc.h new file mode 100755 index 00000000000..39363305280 --- /dev/null +++ b/gdb/tdesc.h @@ -0,0 +1,329 @@ +/* This file has been modified by Data General Corporation, November 1989. */ + +#ifndef _tdesc_h +#define _tdesc_h +#ifdef __STDC__ +#define _ARGS(x) x +#else +#define _ARGS(x) () +#endif + +/* + This file provides an abstract interface to "tdesc" information. + It is designed to be used in a uniform manner by several kinds + of debuggers: + (1) code in live debugged process (e.g., a traceback routine) + (2) a separate-process debugger debugging a live process + (3) a separate-process debugger debugging a memory dump + + Dcontext model notes + * captures machine context + * partial: excludes memory + * frames + * kinds + * make one for starters, chain in reverse order to previous ones + * representation: pointer to opaque + * alloc/free protocol + + Overall model + * access functions + * handle + * error handling +*/ + + + +typedef int dc_boolean_t; /* range 0 .. 1 */ +#define DC_FALSE 0 +#define DC_TRUE 1 + + +typedef int dc_tristate_t; /* range 0 .. 2 */ +#define DC_NO 0 +#define DC_YES 1 +#define DC_MAYBE 2 + + +#define DC_MII_PRECEDING_TDESC_END (1<<0) +#define DC_MII_FOLLOWING_TDESC_START (1<<1) + +#define DC_MIO_ENTRY_POINT (1<< 0) +#define DC_MIO_PROLOGUE_END (1<< 1) +#define DC_MIO_EPILOGUE_START (1<< 2) +#define DC_MIO_IMPLICIT_PROLOGUE_END (1<<16) +#define DC_MIO_LITERAL_ENTRY_POINT (1<<17) +#define DC_MIO_LITERAL_EPILOGUE_START (1<<18) + + +/* + A word is 32 bits of information. In memory, a word is word-aligned. + + A common and important use of word_t is to represent values in the + target process, including (byte) addresses in the target process. + In this case, C arithmetic can be used to simulate machine address + arithmetic on the target. (Unsigned arithmetic is actually modulus + arithmetic.) +*/ +typedef unsigned int dc_word_t; + + +/*----------------*/ + + +/* The exactness of locations may not be certainly known. */ +typedef dc_tristate_t dc_exactness_t; + + +/* + The model includes five kinds of contexts. Because each context + has an associated region and frame, these describe region kinds + and frame kinds as well. + [more description needed] + Currently, only call contexts exist. +*/ + +typedef int dc_kind_t; /* range 0 .. 4 */ +#define DC_CALL_KIND 0 +#define DC_SAVE_KIND 1 +#define DC_EXCEPTION_KIND 2 +#define DC_PROTECTION_KIND 3 +#define DC_SPECIAL_KIND 4 +#define DC_NUM_KINDS 5 + + +typedef struct dc_debug_info { + unsigned int protocol; /* 1 for this structure */ + dc_word_t tdesc_ptr; + unsigned int text_words_count; + dc_word_t text_words_ptr; + unsigned int data_words_count; + dc_word_t data_words_ptr; +} dc_debug_info_t; + + +typedef struct dc_mstate { + dc_word_t reg[32]; /* general registers */ + dc_word_t xip; + dc_word_t nip; + dc_word_t fip; + dc_word_t fpsr; + dc_word_t fpcr; + dc_word_t psr; +} dc_mstate_t; + + + +#if 0 + + void error_fcn (env, continuable, message) + dc_word_t env; /* environment (arbitrary datum) */ + boolean_t continuable; /* whether error function may return */ + char *message; /* string (no trailing newline) */ + + /* In the future, we probably want the error_fcn to be: */ + void error_fcn (env, continuable, code, ...) + dc_word_t env; /* environment (arbitrary datum) */ + boolean_t continuable; /* whether error function may return */ + int code; /* error code */ + ... /* parameters to message associated + with the code */ + + void read_fcn (env, memory, length, buffer) + dc_word_t env; /* environment (arbitrary datum) */ + dc_word_t memory; /* start address in image */ + int length; /* in bytes */ + char *buffer; /* start address of buffer */ + /* There are no alignment assumptions for the read function. */ + + void write_fcn (env, memory, length, buffer) + dc_word_t env; /* environment (arbitrary datum) */ + dc_word_t memory; /* start address in image */ + int length; /* in bytes */ + char *buffer; /* start address of buffer */ + /* There are no alignment assumptions for the write function. */ + /* The write function is optional. It must be provided if changes + to writable registers are to be made. */ + + void exec_fcn (env, mstate) + dc_word_t env; /* environment (arbitrary datum) */ + dc_mstate_t *mstate; /* machine state (read-write) */ + /* The execute function is optional. It would be used (in the future) + by the implementation of a procedurally specified tdesc mechanism. */ + +#endif + +/*----------------*/ + + +typedef struct dc_map_info_in { + dc_word_t flags; + dc_word_t preceding_tdesc_end; + dc_word_t following_tdesc_start; +} dc_map_info_in_t; + + +typedef struct dc_map_info_out { + dc_word_t flags; + dc_word_t entry_point; + dc_word_t prologue_end; + dc_word_t epilogue_start; +} dc_map_info_out_t; + + +typedef void *dc_handle_t; + +typedef void (*tdesc_error_fcn_type) _ARGS(( + dc_word_t env, /* environment (arbitrary datum) */ + dc_boolean_t continuable, /* whether error function may return */ + const char *message /* string (no trailing newline) */ +)); +typedef void (*tdesc_io_fcn_type) _ARGS(( + dc_word_t env, /* environment (arbitrary datum) */ + dc_word_t memory, /* start address in image */ + int length, /* in bytes */ + void *buffer /* start address of buffer */ +)); +typedef void (*tdesc_exec_fcn_type) _ARGS(( + dc_word_t env, /* environment (arbitrary datum) */ + dc_mstate_t *mstate /* machine state (read-write) */ +)); +typedef void (*tdesc_map_fcn_type) _ARGS(( + dc_word_t map_env, + dc_word_t loc, + dc_map_info_in_t map_info_in, + dc_map_info_out_t *map_info_out +)); + + +extern dc_handle_t dc_initiate _ARGS(( + dc_word_t debug_info_ptr, + tdesc_error_fcn_type error_fcn, + dc_word_t error_env, + tdesc_io_fcn_type read_fcn, + dc_word_t read_env, + tdesc_io_fcn_type write_fcn, /* NULL => absent */ + dc_word_t write_env, + tdesc_exec_fcn_type exec_fcn, /* NULL => absent */ + dc_word_t exec_env, + tdesc_map_fcn_type map_fcn, /* NULL => absent */ + dc_word_t map_env +)); +extern void dc_terminate _ARGS(( + dc_handle_t handle +)); + +typedef int dc_register_state_t; /* range 0 to 2 */ + +#define DC_INVALID 0 +#define DC_READABLE 1 +#define DC_WRITABLE 2 + +#define DC_NUM_REG 32 + +#define DC_AUX_LOC 0 +#define DC_AUX_SXIP 1 +#define DC_AUX_SNIP 2 +#define DC_AUX_SFIP 3 +#define DC_AUX_FPSR 4 +#define DC_AUX_FPCR 5 +#define DC_NUM_AUX 6 + + +typedef void *dc_dcontext_t; + +extern dc_dcontext_t dc_make_dcontext _ARGS(( + dc_handle_t handle, + dc_word_t reg_info[DC_NUM_REG], + dc_word_t reg_flags[2], + dc_word_t aux_info[DC_NUM_AUX], + dc_word_t aux_flags[2], + dc_exactness_t loc_exact, + dc_word_t psr_info, + dc_boolean_t psr_ind, + dc_word_t psr_flags[2] +)); +extern void dc_free_dcontext _ARGS(( + dc_dcontext_t dcontext +)); +extern dc_register_state_t dc_location_state _ARGS(( + dc_dcontext_t dcontext +)); +extern dc_exactness_t dc_location_exactness _ARGS(( + dc_dcontext_t dcontext +)); +extern dc_word_t dc_location _ARGS(( + dc_dcontext_t dcontext +)); +extern void dc_set_location _ARGS(( + dc_dcontext_t dcontext, + dc_word_t value +)); +extern dc_register_state_t dc_general_register_state _ARGS(( + dc_dcontext_t dcontext, + int reg +)); +extern dc_word_t dc_general_register _ARGS(( + dc_dcontext_t dcontext, + int reg +)); +extern void dc_set_general_register _ARGS(( + dc_dcontext_t dcontext, + int reg, + dc_word_t value +)); +extern dc_register_state_t dc_auxiliary_register_state _ARGS(( + dc_dcontext_t dcontext, + int reg +)); +extern dc_word_t dc_auxiliary_register _ARGS(( + dc_dcontext_t dcontext, + int reg +)); +extern void dc_set_auxiliary_register _ARGS(( + dc_dcontext_t dcontext, + int reg, + dc_word_t value +)); +extern dc_register_state_t dc_psr_register_bit_state _ARGS(( + dc_dcontext_t dcontext, + int bit +)); +extern dc_word_t dc_psr_register _ARGS(( + dc_dcontext_t dcontext +)); +extern void dc_set_psr_register _ARGS(( + dc_dcontext_t dcontext, + dc_word_t mask, + dc_word_t value +)); +extern dc_word_t dc_frame_address _ARGS(( + dc_dcontext_t dcontext +)); +extern dc_kind_t dc_context_kind _ARGS(( + dc_dcontext_t dcontext +)); +extern dc_register_state_t dc_return_address_state _ARGS(( + dc_dcontext_t dcontext +)); +extern dc_exactness_t dc_return_address_exactness _ARGS(( + dc_dcontext_t dcontext +)); +extern dc_word_t dc_return_address _ARGS(( + dc_dcontext_t dcontext +)); +extern void dc_set_return_address _ARGS(( + dc_dcontext_t dcontext, + dc_word_t value +)); +extern void dc_get_exception_info(); +extern void dc_get_protection_info(); +extern void dc_get_special_info(); +extern dc_dcontext_t dc_previous_dcontext _ARGS(( + dc_dcontext_t dcontext +)); +extern dc_boolean_t dc_location_in_text_chunk _ARGS(( + dc_dcontext_t dcontext, + dc_word_t value +)); + +#endif diff --git a/gdb/tm-29k.h b/gdb/tm-29k.h new file mode 100644 index 00000000000..459462216eb --- /dev/null +++ b/gdb/tm-29k.h @@ -0,0 +1,653 @@ +/* Parameters for target machine of AMD 29000, for GDB, the GNU debugger. + Copyright 1990, 1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Jim Kingdon. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Parameters for an EB29K (a board which plugs into a PC and is + accessed through EBMON software running on the PC, which we + use as we'd use a remote stub (see remote-eb.c). + + If gdb is ported to other 29k machines/systems, the + machine/system-specific parts should be removed from this file (a + la tm-68k.h). */ + +/* Byte order is configurable, but this machine runs big-endian. */ +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* Floating point uses IEEE representations. */ +#define IEEE_FLOAT + +/* We can either use a.out, encapsulated, or can use COFF */ +#ifndef COFF_ENCAPSULATE +#define COFF_FORMAT +/* This just has to do with what coff header files are in use. */ +#define COFF_CHECK_X_ZEROES +#endif + +/* Recognize our magic number. */ +#define BADMAG(x) ((x)->f_magic != 0572) + +/* 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 + +/* 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); } +CORE_ADDR skip_prologue (); + +/* 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_register (LR0_REGNUM)) + +/* I'm not sure about the exact value of this, but based on looking + at the stack pointer when we get to main this seems to be right. + + This is the register stack; We call it "CONTROL" in GDB for consistency + with Pyramid. */ +#define CONTROL_END_ADDR 0x80200000 + +/* Memory stack. This is for the default register stack size, which is + only 0x800 bytes. Perhaps we should let the user specify stack sizes + (and tell EBMON with the "ZS" command). */ +#define STACK_END_ADDR 0x801ff800 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Stack must be aligned on 32-bit word boundaries. */ +#define STACK_ALIGN(ADDR) (((ADDR) + 3) & ~3) + +/* Sequence of bytes for breakpoint instruction. */ +/* ASNEQ 0x50, gr1, gr1 + The trap number 0x50 is chosen arbitrarily. */ +#if TARGET_BYTE_ORDER == BIG_ENDIAN +#define BREAKPOINT {0x72, 0x50, 0x01, 0x01} +#else /* Target is little-endian. */ +#define BREAKPOINT {0x01, 0x01, 0x50, 0x72} +#endif /* Target is little-endian. */ + +/* 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 4 + +/* Nonzero if instruction at PC is a return instruction. + On the 29k, this is a "jmpi l0" instruction. */ + +#define ABOUT_TO_RETURN(pc) \ + ((read_memory_integer (pc, 4) & 0xff0000ff) == 0xc0000080) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 205 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. + + FIXME, add floating point registers and support here. + + Also note that this list does not attempt to deal with kernel + debugging (in which the first 32 registers are gr64-gr95). */ + +#define REGISTER_NAMES \ +{"gr96", "gr97", "gr98", "gr99", "gr100", "gr101", "gr102", "gr103", "gr104", \ + "gr105", "gr106", "gr107", "gr108", "gr109", "gr110", "gr111", "gr112", \ + "gr113", "gr114", "gr115", "gr116", "gr117", "gr118", "gr119", "gr120", \ + "gr121", "gr122", "gr123", "gr124", "gr125", "gr126", "gr127", \ + "lr0", "lr1", "lr2", "lr3", "lr4", "lr5", "lr6", "lr7", "lr8", "lr9", \ + "lr10", "lr11", "lr12", "lr13", "lr14", "lr15", "lr16", "lr17", "lr18", \ + "lr19", "lr20", "lr21", "lr22", "lr23", "lr24", "lr25", "lr26", "lr27", \ + "lr28", "lr29", "lr30", "lr31", "lr32", "lr33", "lr34", "lr35", "lr36", \ + "lr37", "lr38", "lr39", "lr40", "lr41", "lr42", "lr43", "lr44", "lr45", \ + "lr46", "lr47", "lr48", "lr49", "lr50", "lr51", "lr52", "lr53", "lr54", \ + "lr55", "lr56", "lr57", "lr58", "lr59", "lr60", "lr61", "lr62", "lr63", \ + "lr64", "lr65", "lr66", "lr67", "lr68", "lr69", "lr70", "lr71", "lr72", \ + "lr73", "lr74", "lr75", "lr76", "lr77", "lr78", "lr79", "lr80", "lr81", \ + "lr82", "lr83", "lr84", "lr85", "lr86", "lr87", "lr88", "lr89", "lr90", \ + "lr91", "lr92", "lr93", "lr94", "lr95", "lr96", "lr97", "lr98", "lr99", \ + "lr100", "lr101", "lr102", "lr103", "lr104", "lr105", "lr106", "lr107", \ + "lr108", "lr109", "lr110", "lr111", "lr112", "lr113", "lr114", "lr115", \ + "lr116", "lr117", "lr118", "lr119", "lr120", "lr121", "lr122", "lr123", \ + "lr124", "lr125", "lr126", "lr127", \ + "AI0", "AI1", "AI2", "AI3", "AI4", "AI5", "AI6", "AI7", "AI8", "AI9", \ + "AI10", "AI11", "AI12", "AI13", "AI14", "AI15", "FP", \ + "bp", "fc", "cr", "q", \ + "vab", "ops", "cps", "cfg", "cha", "chd", "chc", "rbp", "tmc", "tmr", \ + "pc0", "pc1", "pc2", "mmu", "lru", "fpe", "int", "fps", "exo", "gr1", \ + "alu", "ipc", "ipa", "ipb" } + +/* Special register #x. */ +#define SR_REGNUM(x) \ + ((x) < 15 ? VAB_REGNUM + (x) \ + : (x) >= 128 && (x) < 131 ? IPC_REGNUM + (x) \ + : (x) == 131 ? Q_REGNUM \ + : (x) == 132 ? ALU_REGNUM \ + : (x) >= 133 && (x) < 136 ? BP_REGNUM + (x) \ + : (x) >= 160 && (x) < 163 ? FPE_REGNUM + (x) \ + : (x) == 164 ? EXO_REGNUM \ + : (error ("Internal error in SR_REGNUM"), 0)) +#define GR96_REGNUM 0 +#define GR1_REGNUM 200 +/* This needs to be the memory stack pointer, not the register stack pointer, + to make call_function work right. */ +#define SP_REGNUM MSP_REGNUM +#define FP_REGNUM 33 /* lr1 */ +/* Large Return Pointer (gr123). */ +#define LRP_REGNUM (123 - 96 + GR96_REGNUM) +/* Static link pointer (gr124). */ +#define SLP_REGNUM (124 - 96 + GR96_REGNUM) +/* Memory Stack Pointer (gr125). */ +#define MSP_REGNUM (125 - 96 + GR96_REGNUM) +/* Register allocate bound (gr126). */ +#define RAB_REGNUM (126 - 96 + GR96_REGNUM) +/* Register Free Bound (gr127). */ +#define RFB_REGNUM (127 - 96 + GR96_REGNUM) +/* Register Stack Pointer. */ +#define RSP_REGNUM GR1_REGNUM +#define LR0_REGNUM 32 +#define PC_REGNUM 192 /* pc1 */ +#define NPC_REGNUM 191 /* pc0 */ +#define PC2_REGNUM 193 +#define BP_REGNUM 177 +#define FC_REGNUM 178 +#define CR_REGNUM 179 +#define Q_REGNUM 180 +#define VAB_REGNUM 181 +#define LRU_REGNUM 195 +#define FPE_REGNUM 196 +#define INT_REGNUM 197 +#define FPS_REGNUM 198 +#define EXO_REGNUM 199 +#define PS_REGNUM 201 +#define ALU_REGNUM 201 +#define IPC_REGNUM 202 +#define IPB_REGNUM 204 + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_REGS * 4) + +/* Index within `registers' of the first byte of the space for + register N. */ +#define REGISTER_BYTE(N) ((N)*4) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +/* All regs are 4 bytes. */ + +#define REGISTER_RAW_SIZE(N) (4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +/* All regs are 4 bytes. */ + +#define REGISTER_VIRTUAL_SIZE(N) (4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE (4) + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE (4) + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (0) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ bcopy ((FROM), (TO), 4); } + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +{ bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((N) == PC_REGNUM || (N) == LRP_REGNUM || (N) == SLP_REGNUM \ + || (N) == MSP_REGNUM || (N) == RAB_REGNUM || (N) == RFB_REGNUM \ + || (N) == GR1_REGNUM || (N) == FP_REGNUM || (N) == LR0_REGNUM \ + || (N) == NPC_REGNUM || (N) == PC2_REGNUM) \ + ? lookup_pointer_type (builtin_type_void) : builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ +/* On the 29k the LRP points to the part of the structure beyond the first + 16 words. */ +#define STORE_STRUCT_RETURN(ADDR, SP) \ + write_register (LRP_REGNUM, (ADDR) + 16 * 4); + +/* Should call_function allocate stack space for a struct return? */ +/* On the 29k objects over 16 words require the caller to allocate space. */ +#define USE_STRUCT_CONVENTION(gcc_p, type) (TYPE_LENGTH (type) > 16 * 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) \ + { \ + int reg_length = TYPE_LENGTH (TYPE); \ + if (reg_length > 16 * 4) \ + { \ + reg_length = 16 * 4; \ + read_memory (*((int *)(REGBUF) + LRP_REGNUM), (VALBUF) + 16 * 4, \ + TYPE_LENGTH (TYPE) - 16 * 4); \ + } \ + bcopy (((int *)(REGBUF))+GR96_REGNUM, (VALBUF), reg_length); \ + } + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + { \ + int reg_length = TYPE_LENGTH (TYPE); \ + if (reg_length > 16 * 4) \ + { \ + reg_length = 16 * 4; \ + write_memory (read_register (LRP_REGNUM), \ + (char *)(VALBUF) + 16 * 4, \ + TYPE_LENGTH (TYPE) - 16 * 4); \ + } \ + write_register_bytes (REGISTER_BYTE (GR96_REGNUM), (char *)(VALBUF), \ + TYPE_LENGTH (TYPE)); \ + } + +/* The am29k user's guide documents well what the stacks look like. + But what isn't so clear there is how this interracts with the + symbols, or with GDB. + In the following saved_msp, saved memory stack pointer (which functions + as a memory frame pointer), means either + a register containing the memory frame pointer or, in the case of + functions with fixed size memory frames (i.e. those who don't use + alloca()), the result of the calculation msp + msize. + + LOC_ARG, LOC_LOCAL - For GCC, these are relative to saved_msp. + For high C, these are relative to msp (making alloca impossible). + LOC_REGISTER, LOC_REGPARM - The register number is the number at the + time the function is running (after the prologue), or in the case + of LOC_REGPARM, may be a register number in the range 160-175. + + The compilers do things like store an argument into memory, and then put out + a LOC_ARG for it, or put it into global registers and put out a + LOC_REGPARM. Thus is it important to execute the first line of + code (i.e. the line of the open brace, i.e. the prologue) of a function + before trying to print arguments or anything. + + The following diagram attempts to depict what is going on in memory + (see also the _am29k user's guide_) and also how that interacts with + GDB frames. We arbitrarily pick fci->frame to point the same place + as the register stack pointer; since we set it ourself in + INIT_EXTRA_FRAME_INFO, and access it only through the FRAME_* + macros, it doesn't really matter exactly how we + do it. However, note that FRAME_FP is used in two ways in GDB: + (1) as a "magic cookie" which uniquely identifies frames (even over + calls to the inferior), (2) (in PC_IN_CALL_DUMMY [!CANNOT_EXECUTE_STACK]) + as the value of SP_REGNUM before the dummy frame was pushed. These + two meanings would be incompatible for the 29k if we didn't define + CANNOT_EXECUTE_STACK (but we do, so don't worry about it). + Also note that "lr1" below, while called a frame pointer + in the user's guide, has only one function: To determine whether + registers need to be filled in the function epilogue. + + Consider the code: + < call bar> + loc1: . . . + bar: sub gr1,gr1,rsize_b + . . . + add mfp,msp,0 + sub msp,msp,msize_b + . . . + < call foo > + loc2: . . . + foo: sub gr1,gr1,rsize_f + . . . + add mfp,msp,0 + sub msp,msp,msize_f + . . . + loc3: < suppose the inferior stops here > + + memory stack register stack + | | |____________| + | | |____loc1____| + +------->|___________| | | ^ + | | ^ | | locals_b | | + | | | | |____________| | + | | | | | | | rsize_b + | | | msize_b | | args_to_f | | + | | | | |____________| | + | | | | |____lr1_____| V + | | V | |____loc2____|<----------------+ + | +--->|___________|<---------mfp | ^ | + | | | ^ | | locals_f | | | + | | | | msize_f | |____________| | | + | | | | | | | | rsize_f | + | | | V | | args | | | + | | |___________|pc and ->frame, but all the extra stuff, when called from + get_prev_frame_info, that is. */ +#define INIT_EXTRA_FRAME_INFO(fci) \ + init_extra_frame_info(fci); +void init_extra_frame_info (); +#define INIT_FRAME_PC(fromleaf, fci) \ + init_frame_pc(fromleaf, fci); +void init_frame_pc (); + +/* FRAME_CHAIN takes a FRAME + 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. */ + +/* On the 29k, the nominal address of a frame is the address on the + register stack of the return address (the one next to the incoming + arguments, not down at the bottom so nominal address == stack pointer). + + GDB expects "nominal address" to equal contents of FP_REGNUM, + at least when it comes time to create the innermost frame. + However, that doesn't work for us, so when creating the innermost + frame we set ->frame ourselves in INIT_EXTRA_FRAME_INFO. */ + +/* These are mostly dummies for the 29k because INIT_FRAME_PC + sets prev->frame instead. */ +#define FRAME_CHAIN(thisframe) (0) + +/* Not sure how to figure out where the bottom frame is. There is + no frame for start. In my tests so far the + pc has been outside the text segment, though, so check for that. + However, allow a pc in a call dummy. */ +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (outside_startup_file (FRAME_SAVED_PC (thisframe)) \ + && FRAME_SAVED_PC (thisframe) >= text_start \ + && FRAME_SAVED_PC (thisframe) < text_end + CALL_DUMMY_LENGTH) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (0) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +/* Saved pc (i.e. return address). */ +#define FRAME_SAVED_PC(fraim) \ + (read_register_stack_integer ((fraim)->frame + (fraim)->rsize, 4)) + +/* Local variables (i.e. LOC_LOCAL) are on the memory stack, with their + offsets being relative to the memory stack pointer (high C) or + saved_msp (gcc). */ + +#define FRAME_LOCALS_ADDRESS(fi) frame_locals_address (fi) +extern CORE_ADDR frame_locals_address (); + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ +/* While we could go the effort of finding the tags word and getting + the argcount field from it, + (1) It only counts arguments in registers, i.e. the first 16 words + of arguments + (2) It gives the number of arguments the function was declared with + not how many it was called with (or some variation, like all 16 + words for varadic functions). This makes argcount pretty much + redundant with -g info, even for varadic functions. + So don't bother. */ +#define FRAME_NUM_ARGS(numargs, fi) ((numargs) = -1) + +#define FRAME_ARGS_ADDRESS(fi) FRAME_LOCALS_ADDRESS (fi) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 0 + +/* Provide our own get_saved_register. HAVE_REGISTER_WINDOWS is insufficient + because registers get renumbered on the 29k without getting saved. */ + +#define GET_SAVED_REGISTER + +/* Call function stuff. */ + +/* The dummy frame looks like this (see also the general frame picture + above): + + register stack + + | | frame for function + | locals_sproc | executing at time + |________________| of call_function. + | | We must not disturb + | args_out_sproc | it. + memory stack |________________| + |____lr1_sproc___| + | | |__retaddr_sproc_| <- gr1 (at start) + |____________|<-msp 0 <-----------mfp_dummy_____| + | | (at start) | | + | arg_slop | | saved regs | + | (16 words) | | gr96-gr124 | + |____________|<-msp 1--after | sr128-sr135 | + | | PUSH_DUMMY_FRAME| | + | struct ret | |________________| + | 17+ | | | + |____________|<- lrp | args_out_dummy | + | struct ret | | (16 words) | + | 16 | |________________| + | (16 words) | |____lr1_dummy___| + |____________|<- msp 2--after |_retaddr_dummy__|<- gr1 after + | | struct ret | | PUSH_DUMMY_FRAME + | margs17+ | area allocated | locals_inf | + | | |________________| called + |____________|<- msp 4--when | | function's + | | inf called | args_out_inf | frame (set up + | margs16 | |________________| by called + | (16 words) | |_____lr1_inf____| function). + |____________|<- msp 3--after | . | + | | args pushed | . | + | | | . | + | | + + arg_slop: This area is so that when the call dummy adds 16 words to + the msp, it won't end up larger than mfp_dummy (it is needed in the + case where margs and struct_ret do not add up to at least 16 words). + struct ret: This area is allocated by GDB if the return value is more + than 16 words. struct ret_16 is not used on the 29k. + margs: Pushed by GDB. The call dummy copies the first 16 words to + args_out_dummy. + retaddr_sproc: Contains the PC at the time we call the function. + set by PUSH_DUMMY_FRAME and read by POP_FRAME. + retaddr_dummy: This points to a breakpoint instruction in the dummy. */ + +/* Rsize for dummy frame, in bytes. */ + +/* Bytes for outgoing args, lr1, and retaddr. */ +#define DUMMY_ARG (2 * 4 + 16 * 4) + +/* Number of special registers (sr128-) to save. */ +#define DUMMY_SAVE_SR128 8 +/* Number of general (gr96-) registers to save. */ +#define DUMMY_SAVE_GR96 29 + +#define DUMMY_FRAME_RSIZE \ +(4 /* mfp_dummy */ \ + + DUMMY_SAVE_GR96 * 4 \ + + DUMMY_SAVE_SR128 * 4 \ + + DUMMY_ARG \ + ) + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME push_dummy_frame(); +extern void push_dummy_frame (); + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +#define POP_FRAME pop_frame (); +extern void pop_frame (); + +/* This sequence of words is the instructions + mtsrim cr, 15 + loadm 0, 0, lr2, msp ; load first 16 words of arguments into registers + add msp, msp, 16 * 4 ; point to the remaining arguments + CONST_INSN: + const gr96,inf + consth gr96,inf + calli lr0, gr96 + aseq 0x40,gr1,gr1 ; nop + asneq 0x50,gr1,gr1 ; breakpoint + */ + +/* Position of the "const" instruction within CALL_DUMMY in bytes. */ +#define CONST_INSN (3 * 4) +#if TARGET_BYTE_ORDER == HOST_BYTE_ORDER +#define CALL_DUMMY {0x0400870f, 0x3600827d, 0x157d7d40, 0x03ff60ff, \ + 0x02ff60ff, 0xc8008060, 0x70400101, 0x72500101} +#else /* Byte order differs. */ + you lose +#endif /* Byte order differs. */ +#define CALL_DUMMY_LENGTH (8 * 4) + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +/* Helper macro for FIX_CALL_DUMMY. WORDP is a long * which points to a + word in target byte order; bits 0-7 and 16-23 of *WORDP are replaced with + bits 0-7 and 8-15 of DATA (which is in host byte order). */ + +#if TARGET_BYTE_ORDER == BIG_ENDIAN +#define STUFF_I16(WORDP, DATA) \ + { \ + *((char *)(WORDP) + 3) = ((DATA) & 0xff);\ + *((char *)(WORDP) + 1) = (((DATA) >> 8) & 0xff);\ + } +#else /* Target is little endian. */ +#define STUFF_I16(WORDP, DATA) \ + { + *(char *)(WORDP) = ((DATA) & 0xff); + *((char *)(WORDP) + 2) = (((DATA) >> 8) & 0xff); + } +#endif /* Target is little endian. */ + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +/* Currently this stuffs in the address of the function that we are calling. + If different 29k systems use different breakpoint instructions, it + could also stuff BREAKPOINT in the right place (to avoid having to + duplicate CALL_DUMMY in each tm-*.h file). */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ + {\ + STUFF_I16((char *)dummyname + CONST_INSN, fun);\ + STUFF_I16((char *)dummyname + CONST_INSN + 4, fun >> 16);\ + } + +/* At least our 29k board has separate data & instruction memories and can't + execute the data memory. Also, there should be space after text_end; + we won't get a SIGSEGV or scribble on data space. */ + +#define CALL_DUMMY_LOCATION AFTER_TEXT_END + +/* How to translate register numbers in the .stab's into gdb's internal register + numbers. We don't translate them, but we warn if an invalid register + number is seen. Note that FIXME, we use the value "sym" as an implicit + argument in printing the error message. It happens to be available where + this macro is used. (This macro definition appeared in a late revision + of gdb-3.91.6 and is not well tested. Also, it should be a "complaint".) */ + +#define STAB_REG_TO_REGNUM(num) \ + (((num) > LR0_REGNUM + 127) \ + ? fprintf(stderr, \ + "Invalid register number %d in symbol table entry for %s\n", \ + (num), SYMBOL_NAME (sym)), (num) \ + : (num)) diff --git a/gdb/tm-3b1.h b/gdb/tm-3b1.h new file mode 100644 index 00000000000..65143a9a26d --- /dev/null +++ b/gdb/tm-3b1.h @@ -0,0 +1,108 @@ +/* Parameters for targeting to a 3b1. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define BREAKPOINT { 0x4e, 0x41 } +/* 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 COFF format. */ + +#define COFF_FORMAT +#define COFF_NO_LONG_FILE_NAMES + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x300000 + + +/* 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; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } + +/* This sequence of words is the instructions + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @#32323232 + addl #69696969,sp + bpt + nop +Note this is 24 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 24 + +#define CALL_DUMMY_START_OFFSET 8 + +/* 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 + 16) = nargs * 4; \ + *(int *)((char *) dummyname + 10) = fun; } + +#include "tm-68k.h" diff --git a/gdb/tm-68k.h b/gdb/tm-68k.h new file mode 100644 index 00000000000..120ea0863f7 --- /dev/null +++ b/gdb/tm-68k.h @@ -0,0 +1,473 @@ +/* Parameters for execution on a 68000 series machine. + Copyright (C) 1986, 1987, 1989, 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Generic 68000 stuff, to be included by other m-*.h files. + Define HAVE_68881 if that is the case. */ + +#if defined (HAVE_68881) +#define IEEE_FLOAT 1 +#endif + +/* Define the bit, byte, and word ordering of the machine. */ +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* 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 */ \ + /* Not sure why branches are here. */ \ + /* From m-isi.h, m-altos.h */ \ + else if (op == 0060000) \ + pc += 4; /* Skip bra #word */ \ + else if (op == 00600377) \ + pc += 6; /* skip bra #long */ \ + else if ((op & 0177400) == 0060000) \ + pc += 2; /* skip bra #char */ \ +} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ +read_memory_integer (read_register (SP_REGNUM), 4) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. + This is a TRAP instruction. The last 4 bits (0xf below) is the + vector. Systems which don't use 0xf should define BREAKPOINT + themselves before including this file. */ + +#if !defined (BREAKPOINT) +#define BREAKPOINT {0x4e, 0x4f} +#endif + +/* If your kernel resets the pc after the trap happens you may need to + define this in m-68k.h. */ + +#if !defined (DECR_PC_AFTER_BREAK) +#define DECR_PC_AFTER_BREAK 2 +#endif + +/* Nonzero if instruction at PC is a return instruction. */ +/* Allow any of the return instructions, including a trapv and a return + from interupt. */ + +#define ABOUT_TO_RETURN(pc) ((read_memory_integer (pc, 2) & ~0x3) == 0x4e74) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Say how long registers are. */ + +#define REGISTER_TYPE long + +#if defined (HAVE_68881) +# if defined (sun) + /* Sun3 status includes fpflags, which shows whether the FPU has been used + by the process, and whether the FPU was done with an instruction or + was interrupted in the middle of a long instruction. See + . */ + /* a&d, pc,sr, fp, fpstat, fpflags */ +# define NUM_REGS 31 +# define REGISTER_BYTES (16*4 + 8 + 8*12 + 3*4 + 4) +# else /* Not sun3. */ +# define NUM_REGS 29 +# define REGISTER_BYTES (16*4 + 8 + 8*12 + 3*4) +# endif /* Not sun3. */ +#else /* No 68881. */ +# define NUM_REGS 18 +# define REGISTER_BYTES (16*4 + 8) +#endif /* No 68881. */ + +/* Index within `registers' of the first byte of the space for + register N. */ + +#if defined (HAVE_68881) +#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 + subtraction 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) \ +{ \ + extern struct ext_format ext_format_68881 []; \ + \ + if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + ieee_extended_to_double (ext_format_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) \ +{ \ + extern struct ext_format ext_format_68881 []; \ + \ + if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + double_to_ieee_extended (ext_format_68881, (FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); \ +} + +/* Return the GDB type object for the "standard" data type + of data in register N. */ +/* Note, for registers which contain addresses return + pointer to void, not pointer to char, because we don't + want to attempt to print the string after printing the address. */ +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : \ + (N) == PC_REGNUM || (N) == FP_REGNUM || (N) == SP_REGNUM ? \ + lookup_pointer_type (builtin_type_void) : builtin_type_int) + +#else /* no 68881. */ +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, 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 68000, all regs are 4 bytes. */ + +#define REGISTER_VIRTUAL_SIZE(N) 4 + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) 0 + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) bcopy ((FROM), (TO), 4); + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) bcopy ((FROM), (TO), 4); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) builtin_type_int + +#endif /* No 68881. */ + +/* Initializer for an array of names of registers. + Entries beyond the first NUM_REGS are ignored. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "ps", "pc", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr", "fpcode", "fpflags" } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define A1_REGNUM 9 +#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 */ +#if defined (HAVE_68881) +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ +#define FPS_REGNUM 27 /* 68881 status register */ +#endif /* 68881. */ + +/* 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 (A1_REGNUM, (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. This is assuming that floating point values are returned + as doubles in d0/d1. */ + +#if !defined (EXTRACT_RETURN_VALUE) +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)) +#endif + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. Assumes floats are passed + in d0/d1. */ + +#if !defined (STORE_RETURN_VALUE) +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)) +#endif + +/* 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 68000, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && outside_startup_file (FRAME_SAVED_PC (thisframe))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +#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. */ +#if !defined (FRAME_NUM_ARGS) +#define FRAME_NUM_ARGS(val,fi) (val = -1) +#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. */ + +#if !defined (FRAME_FIND_SAVED_REGS) +#if defined (HAVE_68881) +#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; \ +} +#else /* no 68881. */ +#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; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4; }\ + 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); \ + 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); } \ + /* 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; \ +} +#endif /* no 68881. */ +#endif /* no FIND_FRAME_SAVED_REGS. */ + +/* Note that stuff for calling inferior functions is not in this file + because the call dummy is different for different breakpoint + instructions, which are different on different systems. Perhaps + they could be merged, but I haven't bothered. */ diff --git a/gdb/tm-altos.h b/gdb/tm-altos.h new file mode 100644 index 00000000000..ea92f8b8bb6 --- /dev/null +++ b/gdb/tm-altos.h @@ -0,0 +1,130 @@ +/* Definitions to make GDB run on an Altos 3068 (m68k running SVR2) + Copyright (C) 1987,1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x4e} + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#undef NAMES_HAVE_UNDERSCORE + +/* Exec files and symbol tables are in COFF format */ + +#define COFF_FORMAT +#define COFF_NO_LONG_FILE_NAMES + +/* Address of end of stack space. */ + +/*#define STACK_END_ADDR (0xffffff)*/ +#define STACK_END_ADDR (0x1000000) + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. + On the Altos, the kernel resets the pc to the trap instr */ + +#define DECR_PC_AFTER_BREAK 0 + + +/* 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, 0x4e4e4e71} + +#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, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } + +#include "tm-68k.h" diff --git a/gdb/tm-altosgas.h b/gdb/tm-altosgas.h new file mode 100644 index 00000000000..eb342eac7c6 --- /dev/null +++ b/gdb/tm-altosgas.h @@ -0,0 +1,28 @@ +/* Definitions to make GDB run on an Altos 3068 using COFF encapsulation. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define COFF_ENCAPSULATE + +#include "m-altos.h" + +#undef COFF_FORMAT +#undef COFF_NO_LONG_FILE_NAMES +#define NAMES_HAVE_UNDERSCORE + +#define READ_DBX_FORMAT diff --git a/gdb/tm-arm.h b/gdb/tm-arm.h new file mode 100644 index 00000000000..c06139993ca --- /dev/null +++ b/gdb/tm-arm.h @@ -0,0 +1,415 @@ +/* Definitions to make GDB target for an ARM under RISCiX (4.3bsd). + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* IEEE format floating point */ + +#define IEEE_FLOAT + +/* I provide my own xfer_core_file to cope with shared libraries */ + +#define XFER_CORE_FILE + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) pc = skip_prologue(pc) + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) (read_register (LR_REGNUM) & 0x03fffffc) + +/* I don't know the real values for these. */ +#define TARGET_UPAGES UPAGES +#define TARGET_NBPG NBPG + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0x01000000 - (TARGET_UPAGES * TARGET_NBPG)) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x00,0x00,0x18,0xef} /* BKPT_SWI from */ + +/* 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, 4) & 0x0fffffff == 0x01b0f00e) || \ + (read_memory_integer(pc, 4) & 0x0ffff800 == 0x09eba800)) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes. */ + +#define INVALID_FLOAT(p, len) 0 + +/* code to execute to print interesting information about the + * floating point processor (if any) + * No need to define if there is nothing to do. + */ +#define FLOAT_INFO { arm_float_info (); } + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +/* Note: I make a fake copy of the pc in register 25 (calling it ps) so + that I can clear the status bits from pc (register 15) */ + +#define NUM_REGS 26 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + { "a1", "a2", "a3", "a4", \ + "v1", "v2", "v3", "v4", "v5", "v6", \ + "sl", "fp", "ip", "sp", "lr", "pc", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "fps", "ps" } + +/* 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 AP_REGNUM 11 +#define FP_REGNUM 11 /* Contains address of executing stack frame */ +#define SP_REGNUM 13 /* Contains address of top of stack */ +#define LR_REGNUM 14 /* address to return to from a function call */ +#define PC_REGNUM 15 /* Contains program counter */ +#define F0_REGNUM 16 /* first floating point register */ +#define FPS_REGNUM 24 /* floating point status register */ +#define PS_REGNUM 25 /* Contains processor status */ + + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4 + 12*8 + 4 + 4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) (((N) < F0_REGNUM) ? (N)*4 : \ + (((N) < PS_REGNUM) ? 16*4 + ((N) - 16)*12 : \ + 16*4 + 8*12 + ((N) - FPS_REGNUM) * 4)) + +/* Number of bytes of storage in the actual machine representation + for register N. On the vax, all regs are 4 bytes. */ + +#define REGISTER_RAW_SIZE(N) (((N) < F0_REGNUM || (N) >= FPS_REGNUM) ? 4 : 12) + +/* Number of bytes of storage in the program's representation + for register N. On the vax, all regs are 4 bytes. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((N) < F0_REGNUM || (N) >= FPS_REGNUM) ? 4 : 8) + +/* 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) - F0_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 (REGISTER_CONVERTIBLE(REGNUM)) \ + convert_from_extended((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 (REGISTER_CONVERTIBLE(REGNUM)) \ + convert_to_extended((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) - F0_REGNUM) < 8 ? builtin_type_double : builtin_type_int) + +/* The system C compiler uses a similar structure return convention to gcc */ + +#define USE_STRUCT_CONVENTION(gcc_p, type) (TYPE_LENGTH (type) > 4) + +/* 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 (0, (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) \ + convert_from_extended(REGBUF + REGISTER_BYTE (F0_REGNUM), VALBUF); \ + else \ + bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) { \ + char _buf[MAX_REGISTER_RAW_SIZE]; \ + convert_to_extended(VALBUF, _buf); \ + write_register_bytes (REGISTER_BYTE (F0_REGNUM), _buf, MAX_REGISTER_RAW_SIZE); \ + } else \ + 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)) + +/* Specify that for the native compiler variables for a particular + lexical context are listed after the beginning LBRAC instead of + before in the executables list of symbols. */ +#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) (!(gcc_p)) + + +/* 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 ARM, the frame's nominal address is the FP value, + and 12 bytes before comes the saved previous FP value as a 4-byte word. */ + +#define FRAME_CHAIN(thisframe) \ + ((thisframe)->pc >= first_object_file_end ? \ + read_memory_integer ((thisframe)->frame - 12, 4) :\ + 0) + +#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. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ +{ \ + CORE_ADDR func_start, after_prologue; \ + func_start = (get_pc_function_start ((FI)->pc) + \ + FUNCTION_START_OFFSET); \ + after_prologue = func_start; \ + SKIP_PROLOGUE (after_prologue); \ + (FRAMELESS) = (after_prologue == func_start); \ +} + +/* Saved Pc. */ + +#define FRAME_SAVED_PC(FRAME) \ + (read_memory_integer ((FRAME)->frame - 4, 4) & 0x03fffffc) + +#define FRAME_ARGS_ADDRESS(fi) (fi->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) (numargs = -1) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 0 + +/* 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 frame; \ + register int next_addr; \ + register int return_data_save; \ + register int saved_register_mask; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + frame = (frame_info)->frame; \ + return_data_save = read_memory_integer(frame, 4) & 0x03fffffc - 12; \ + saved_register_mask = \ + read_memory_integer(return_data_save, 4); \ + next_addr = frame - 12; \ + for (regnum = 4; regnum < 10; regnum++) \ + if (saved_register_mask & (1<= 4; regnum --) \ + sp = push_word(sp, read_register (regnum)); \ + write_register (FP_REGNUM, read_register (SP_REGNUM) - 8); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ \ + register CORE_ADDR fp = read_register (FP_REGNUM); \ + register unsigned long return_data_save = \ + read_memory_integer ( (read_memory_integer (fp, 4) & \ + 0x03fffffc) - 12, 4); \ + register int regnum; \ + write_register (PS_REGNUM, read_memory_integer (fp - 4, 4)); \ + write_register (PC_REGNUM, read_register (PS_REGNUM) & 0x03fffffc); \ + write_register (SP_REGNUM, read_memory_integer (fp - 8, 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp - 12, 4)); \ + fp -= 12; \ + for (regnum = 9; regnum >= 4; regnum--) \ + if (return_data_save & (1< 4) { \ + nargs_in_registers = min(nargs + 1, 4); \ + struct_return = 1; \ + } else \ + nargs_in_registers = min(nargs, 4); \ + *(char *) dummyname = (1 << nargs_in_registers) - 1 - struct_return; \ + *(int *)((char *) dummyname + 8) = \ + (((fun - (pc + 16)) / 4) & 0x00ffffff) | 0xeb000000; } diff --git a/gdb/tm-bigmips.h b/gdb/tm-bigmips.h new file mode 100644 index 00000000000..7d6bae5e3ae --- /dev/null +++ b/gdb/tm-bigmips.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TARGET_BYTE_ORDER BIG_ENDIAN + +#include "tm-mips.h" diff --git a/gdb/tm-convex.h b/gdb/tm-convex.h new file mode 100644 index 00000000000..5a001f182be --- /dev/null +++ b/gdb/tm-convex.h @@ -0,0 +1,563 @@ +/* Definitions to make GDB run on Convex Unix (4bsd) + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* I don't know if this will work for cross-debugging, even if you do get + the right files. */ +/* Include certain files for dbxread.c */ +#include +#include +#include +#include + +/* 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 + +/* There is come problem with the debugging symbols generated by the + compiler such that the debugging symbol for the first line of a + function overlap with the function prologue. */ +#define PROLOGUE_FIRSTLINE_OVERLAP + +/* When convex pcc says CHAR or SHORT, it provides the correct address. */ + +#define BELIEVE_PCC_PROMOTION 1 + +/* Symbol types to ignore. */ +/* 0xc4 is N_MONPT. Use the numeric value for the benefit of people + with (rather) old OS's. */ +#define IGNORE_SYMBOL(TYPE) \ + (((TYPE) & ~N_EXT) == N_TBSS \ + || ((TYPE) & ~N_EXT) == N_TDATA \ + || ((TYPE) & ~N_EXT) == 0xc4) + +/* 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. + Convex prolog is: + [sub.w #-,sp] in one of 3 possible sizes + [mov psw,- fc/vc main program prolog + and #-,- (skip it because the "mov psw" saves the + mov -,psw] T bit, so continue gets a surprise trap) + [and #-,sp] fc/vc O2 main program prolog + [ld.- -(ap),-] pcc/gcc register arg loads +*/ + +#define SKIP_PROLOGUE(pc) \ +{ int op, ix; \ + op = read_memory_integer (pc, 2); \ + if ((op & 0xffc7) == 0x5ac0) pc += 2; \ + else if (op == 0x1580) pc += 4; \ + else if (op == 0x15c0) pc += 6; \ + if ((read_memory_integer (pc, 2) & 0xfff8) == 0x7c40 \ + && (read_memory_integer (pc + 2, 2) & 0xfff8) == 0x1240 \ + && (read_memory_integer (pc + 8, 2) & 0xfff8) == 0x7c48) \ + pc += 10; \ + if (read_memory_integer (pc, 2) == 0x1240) pc += 6; \ + for (;;) { \ + op = read_memory_integer (pc, 2); \ + ix = (op >> 3) & 7; \ + if (ix != 6) break; \ + if ((op & 0xfcc0) == 0x3000) pc += 4; \ + else if ((op & 0xfcc0) == 0x3040) pc += 6; \ + else if ((op & 0xfcc0) == 0x2800) pc += 4; \ + else if ((op & 0xfcc0) == 0x2840) pc += 6; \ + else break;}} + +/* Immediately after a function call, return the saved pc. + (ignore frame and return *$sp so we can handle both calls and callq) */ + +#define SAVED_PC_AFTER_CALL(frame) \ + read_memory_integer (read_register (SP_REGNUM), 4) + +/* Address of end of stack space. + This is ((USRSTACK + 0xfff) & -0x1000)) from but + that expression depends on the kernel version; instead, fetch a + page-zero pointer and get it from that. This will be invalid if + they ever change the way bkpt signals are delivered. */ + +#define STACK_END_ADDR (0xfffff000 & *(unsigned *) 0x80000050) + +/* User-mode traps push an extended rtn block, + then fault with one of the following PCs */ + +#define is_trace_pc(pc) ((unsigned) ((pc) - (*(int *) 0x80000040)) <= 4) +#define is_arith_pc(pc) ((unsigned) ((pc) - (*(int *) 0x80000044)) <= 4) +#define is_break_pc(pc) ((unsigned) ((pc) - (*(int *) 0x80000050)) <= 4) + +/* We need to manipulate trap bits in the psw */ + +#define PSW_TRAP_FLAGS 0x69670000 +#define PSW_T_BIT 0x08000000 +#define PSW_S_BIT 0x01000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. (bkpt) */ + +#define BREAKPOINT {0x7d,0x50} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT but not always. + (The break PC needs to be decremented by 2, but we do it when the + break frame is recognized and popped. That way gdb can tell breaks + from trace traps with certainty.) */ + +#define DECR_PC_AFTER_BREAK 0 + +/* Nonzero if instruction at PC is a return instruction. (rtn or rtnq) */ + +#define ABOUT_TO_RETURN(pc) \ + ((read_memory_integer (pc, 2) & 0xffe0) == 0x7c80) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p,len) 0 + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long long + +/* Number of machine registers */ + +#define NUM_REGS 26 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"pc","psw","fp","ap","a5","a4","a3","a2","a1","sp",\ + "s7","s6","s5","s4","s3","s2","s1","s0",\ + "S7","S6","S5","S4","S3","S2","S1","S0"} + +/* 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 S0_REGNUM 25 /* the real S regs */ +#define S7_REGNUM 18 +#define s0_REGNUM 17 /* low-order halves of S regs */ +#define s7_REGNUM 10 +#define SP_REGNUM 9 /* A regs */ +#define A1_REGNUM 8 +#define A5_REGNUM 4 +#define AP_REGNUM 3 +#define FP_REGNUM 2 /* Contains address of executing stack frame */ +#define PS_REGNUM 1 /* Contains processor status */ +#define PC_REGNUM 0 /* Contains program counter */ + +/* convert dbx stab register number (from `r' declaration) to a gdb REGNUM */ + +#define STAB_REG_TO_REGNUM(value) \ + ((value) < 8 ? S0_REGNUM - (value) : SP_REGNUM - ((value) - 8)) + +/* Vector register numbers, not handled as ordinary regs. + They are treated as convenience variables whose values are read + from the inferior when needed. */ + +#define V0_REGNUM 0 +#define V7_REGNUM 7 +#define VM_REGNUM 8 +#define VS_REGNUM 9 +#define VL_REGNUM 10 + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (4*10 + 8*8) + +/* Index within `registers' of the first byte of the space for + register N. + NB: must match structure of struct syscall_context for correct operation */ + +#define REGISTER_BYTE(N) ((N) < s7_REGNUM ? 4*(N) : \ + (N) < S7_REGNUM ? 44 + 8 * ((N)-s7_REGNUM) : \ + 40 + 8 * ((N)-S7_REGNUM)) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#define REGISTER_RAW_SIZE(N) ((N) < S7_REGNUM ? 4 : 8) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) REGISTER_RAW_SIZE(N) + +/* 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), REGISTER_RAW_SIZE (REGNUM)); + +/* 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), REGISTER_RAW_SIZE (REGNUM)); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N) < S7_REGNUM ? builtin_type_int : builtin_type_long_long) + +/* 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 (A1_REGNUM, (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 (&((char *) REGBUF) [REGISTER_BYTE (S0_REGNUM) + \ + 8 - TYPE_LENGTH (TYPE)],\ + 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 (REGISTER_BYTE (S0_REGNUM), VALBUF, 8) + +/* 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 *) & ((char *) REGBUF) [REGISTER_BYTE (s0_REGNUM)]) + +/* Define trapped internal variable hooks to read and write + vector and communication registers. */ + +#define IS_TRAPPED_INTERNALVAR is_trapped_internalvar +#define VALUE_OF_TRAPPED_INTERNALVAR value_of_trapped_internalvar +#define SET_TRAPPED_INTERNALVAR set_trapped_internalvar + +extern struct value *value_of_trapped_internalvar (); + +/* Hooks to read data from soff exec and core files, + and to describe the files. */ + +#define XFER_CORE_FILE +#define FILES_INFO_HOOK print_maps + +/* Hook to call to print a typeless integer value, normally printed in decimal. + For convex, use hex instead if the number looks like an address. */ + +#define PRINT_TYPELESS_INTEGER decout + +/* For the native compiler, variables for a particular lexical context + are listed after the beginning LBRAC instead of before in the + executables list of symbols. Using "gcc_compiled." to distinguish + between GCC and native compiler doesn't work on Convex because the + linker sorts the symbols to put "gcc_compiled." in the wrong place. + desc is nonzero for native, zero for gcc. */ +#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) (desc != 0) + +/* Pcc occaisionally puts an SO where there should be an SOL. */ +#define PCC_SOL_BROKEN + +/* Cannot execute with pc on the stack. */ +#define CANNOT_EXECUTE_STACK + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame_info with a frame's nominal address in fi->frame, + 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. */ + +/* (caller fp is saved at 8(fp)) */ + +#define FRAME_CHAIN(fi) (read_memory_integer ((fi)->frame + 8, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. + On convex, check at the return address for `callq' -- if so, frameless, + otherwise, not. */ + +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ +{ \ + extern CORE_ADDR text_start, text_end; \ + CORE_ADDR call_addr = SAVED_PC_AFTER_CALL (FI); \ + (FRAMELESS) = (call_addr >= text_start && call_addr < text_end \ + && read_memory_integer (call_addr - 6, 1) == 0x22); \ +} + +#define FRAME_SAVED_PC(fi) (read_memory_integer ((fi)->frame, 4)) + +#define FRAME_ARGS_ADDRESS(fi) (read_memory_integer ((fi)->frame + 12, 4)) + +#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) \ +{ numargs = read_memory_integer (FRAME_ARGS_ADDRESS (fi) - 4, 4); \ + if (numargs < 0 || numargs >= 256) numargs = -1;} + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 0 + +/* 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. */ + +/* Normal (short) frames save only PC, FP, (callee's) AP. To reasonably + handle gcc and pcc register variables, scan the code following the + call for the instructions the compiler inserts to reload register + variables from stack slots and record the stack slots as the saved + locations of those registers. This will occasionally identify some + random load as a saved register; this is harmless. vc does not + declare its register allocation actions in the stabs. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ register int regnum; \ + register int frame_length = /* 3 short, 2 long, 1 extended, 0 context */\ + (read_memory_integer ((frame_info)->frame + 4, 4) >> 25) & 3; \ + register CORE_ADDR frame_fp = \ + read_memory_integer ((frame_info)->frame + 8, 4); \ + register CORE_ADDR next_addr; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 0; \ + (frame_saved_regs).regs[PS_REGNUM] = (frame_info)->frame + 4; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[AP_REGNUM] = frame_fp + 12; \ + next_addr = (frame_info)->frame + 12; \ + if (frame_length < 3) \ + for (regnum = A5_REGNUM; regnum < SP_REGNUM; ++regnum) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4); \ + if (frame_length < 2) \ + (frame_saved_regs).regs[SP_REGNUM] = (next_addr += 4); \ + next_addr -= 4; \ + if (frame_length < 3) \ + for (regnum = S7_REGNUM; regnum < S0_REGNUM; ++regnum) \ + (frame_saved_regs).regs[regnum] = (next_addr += 8); \ + if (frame_length < 2) \ + (frame_saved_regs).regs[S0_REGNUM] = (next_addr += 8); \ + else \ + (frame_saved_regs).regs[SP_REGNUM] = next_addr + 8; \ + if (frame_length == 3) { \ + CORE_ADDR pc = read_memory_integer ((frame_info)->frame, 4); \ + int op, ix, disp; \ + op = read_memory_integer (pc, 2); \ + if ((op & 0xffc7) == 0x1480) pc += 4; /* add.w #-,sp */ \ + else if ((op & 0xffc7) == 0x58c0) pc += 2; /* add.w #-,sp */ \ + op = read_memory_integer (pc, 2); \ + if ((op & 0xffc7) == 0x2a06) pc += 4; /* ld.w -,ap */ \ + for (;;) { \ + op = read_memory_integer (pc, 2); \ + ix = (op >> 3) & 7; \ + if ((op & 0xfcc0) == 0x2800) { /* ld.- -,ak */ \ + regnum = SP_REGNUM - (op & 7); \ + disp = read_memory_integer (pc + 2, 2); \ + pc += 4;} \ + else if ((op & 0xfcc0) == 0x2840) { /* ld.- -,ak */ \ + regnum = SP_REGNUM - (op & 7); \ + disp = read_memory_integer (pc + 2, 4); \ + pc += 6;} \ + if ((op & 0xfcc0) == 0x3000) { /* ld.- -,sk */ \ + regnum = S0_REGNUM - (op & 7); \ + disp = read_memory_integer (pc + 2, 2); \ + pc += 4;} \ + else if ((op & 0xfcc0) == 0x3040) { /* ld.- -,sk */ \ + regnum = S0_REGNUM - (op & 7); \ + disp = read_memory_integer (pc + 2, 4); \ + pc += 6;} \ + else if ((op & 0xff00) == 0x7100) { /* br crossjump */ \ + pc += 2 * (char) op; \ + continue;} \ + else if (op == 0x0140) { /* jmp crossjump */ \ + pc = read_memory_integer (pc + 2, 4); \ + continue;} \ + else break; \ + if ((frame_saved_regs).regs[regnum]) \ + break; \ + if (ix == 7) disp += frame_fp; \ + else if (ix == 6) disp += read_memory_integer (frame_fp + 12, 4); \ + else if (ix != 0) break; \ + (frame_saved_regs).regs[regnum] = \ + disp - 8 + (1 << ((op >> 8) & 3)); \ + if (regnum >= S7_REGNUM) \ + (frame_saved_regs).regs[regnum - S0_REGNUM + s0_REGNUM] = \ + disp - 4 + (1 << ((op >> 8) & 3)); \ + } \ + } \ +} + +/* 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 buf[8]; \ + long word; \ + for (regnum = S0_REGNUM; regnum >= S7_REGNUM; --regnum) { \ + read_register_bytes (REGISTER_BYTE (regnum), buf, 8); \ + sp = push_bytes (sp, buf, 8);} \ + for (regnum = SP_REGNUM; regnum >= FP_REGNUM; --regnum) { \ + word = read_register (regnum); \ + sp = push_bytes (sp, &word, 4);} \ + word = (read_register (PS_REGNUM) &~ (3<<25)) | (1<<25); \ + sp = push_bytes (sp, &word, 4); \ + word = read_register (PC_REGNUM); \ + sp = push_bytes (sp, &word, 4); \ + write_register (SP_REGNUM, sp); \ + write_register (FP_REGNUM, sp); \ + write_register (AP_REGNUM, sp);} + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME do {\ + register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + register int frame_length = /* 3 short, 2 long, 1 extended, 0 context */ \ + (read_memory_integer (fp + 4, 4) >> 25) & 3; \ + char buf[8]; \ + write_register (PC_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PS_REGNUM, read_memory_integer (fp += 4, 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp += 4, 4)); \ + write_register (AP_REGNUM, read_memory_integer (fp += 4, 4)); \ + if (frame_length < 3) \ + for (regnum = A5_REGNUM; regnum < SP_REGNUM; ++regnum) \ + write_register (regnum, read_memory_integer (fp += 4, 4)); \ + if (frame_length < 2) \ + write_register (SP_REGNUM, read_memory_integer (fp += 4, 4)); \ + fp -= 4; \ + if (frame_length < 3) \ + for (regnum = S7_REGNUM; regnum < S0_REGNUM; ++regnum) { \ + read_memory (fp += 8, buf, 8); \ + write_register_bytes (REGISTER_BYTE (regnum), buf, 8);} \ + if (frame_length < 2) { \ + read_memory (fp += 8, buf, 8); \ + write_register_bytes (REGISTER_BYTE (regnum), buf, 8);} \ + else write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM), \ + read_pc ())); \ +} while (0) + +/* This sequence of words is the instructions + mov sp,ap + pshea 69696969 + calls 32323232 + bkpt + Note this is 16 bytes. */ + +#define CALL_DUMMY {0x50860d4069696969LL,0x2140323232327d50LL} + +#define CALL_DUMMY_LENGTH 16 + +#define CALL_DUMMY_START_OFFSET 0 + +/* 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, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 4) = nargs; \ + *(int *)((char *) dummyname + 10) = fun; } + +/* Defs to read soff symbol tables, see dbxread.c */ + +#define NUMBER_OF_SYMBOLS ((long) opthdr.o_nsyms) +#define STRING_TABLE_OFFSET ((long) filehdr.h_strptr) +#define SYMBOL_TABLE_OFFSET ((long) opthdr.o_symptr) +#define STRING_TABLE_SIZE ((long) filehdr.h_strsiz) +#define SIZE_OF_TEXT_SEGMENT ((long) txthdr.s_size) +#define ENTRY_POINT ((long) opthdr.o_entry) + +#define READ_STRING_TABLE_SIZE(BUFFER) \ + (BUFFER = STRING_TABLE_SIZE) + +#define DECLARE_FILE_HEADERS \ + FILEHDR filehdr; \ + OPTHDR opthdr; \ + SCNHDR txthdr + +#define READ_FILE_HEADERS(DESC,NAME) \ +{ \ + int n; \ + val = myread (DESC, &filehdr, sizeof filehdr); \ + if (val < 0) \ + perror_with_name (NAME); \ + if (! IS_SOFF_MAGIC (filehdr.h_magic)) \ + error ("%s: not an executable file.", NAME); \ + lseek (DESC, 0L, 0); \ + if (myread (DESC, &filehdr, sizeof filehdr) < 0) \ + perror_with_name (NAME); \ + if (myread (DESC, &opthdr, filehdr.h_opthdr) <= 0) \ + perror_with_name (NAME); \ + for (n = 0; n < filehdr.h_nscns; n++) \ + { \ + if (myread (DESC, &txthdr, sizeof txthdr) < 0) \ + perror_with_name (NAME); \ + if ((txthdr.s_flags & S_TYPMASK) == S_TEXT) \ + break; \ + } \ +} diff --git a/gdb/tm-hp300bsd.h b/gdb/tm-hp300bsd.h new file mode 100644 index 00000000000..d4601bfa846 --- /dev/null +++ b/gdb/tm-hp300bsd.h @@ -0,0 +1,142 @@ +/* Parameters for execution on a Hewlett-Packard 9000/300, running bsd. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Configuration file for HP9000/300 series machine running + * University of Utah's 4.3bsd port. This is NOT for HP-UX. + * Problems to hpbsd-bugs@cs.utah.edu + */ + +/* 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 + +#define TARGET_NBPG 4096 +#define TARGET_UPAGES 3 + +/* On the HP300, sigtramp is in the u area. Gak! User struct is not + mapped to the same virtual address in user/kernel address space + (hence STACK_END_ADDR as opposed to KERNEL_U_ADDR). This tests + for the whole u area, since we don't necessarily have hp300bsd + include files around. */ +#define IN_SIGTRAMP(pc, name) \ + ((pc) >= STACK_END_ADDR \ + && (pc) < STACK_END_ADDR + TARGET_UPAGES * TARGET_NBPG \ + ) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xfff00000 + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x42} + + +/* 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_gen (regnum, raw_buffer); \ + 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 #2 + 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, 0x4e424e71} + +#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, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } + +#define HAVE_68881 + +#include "tm-68k.h" diff --git a/gdb/tm-hp300hpux.h b/gdb/tm-hp300hpux.h new file mode 100644 index 00000000000..67c93233f08 --- /dev/null +++ b/gdb/tm-hp300hpux.h @@ -0,0 +1,122 @@ +/* Parameters for execution on an HP 9000 model 320, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x41} + +/* 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 + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xFFF00000 + +/* 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, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } + +#include HAVE_68881 + +#include "tm-68k.h" diff --git a/gdb/tm-i386v-g.h b/gdb/tm-i386v-g.h new file mode 100644 index 00000000000..e1dc3fd88c8 --- /dev/null +++ b/gdb/tm-i386v-g.h @@ -0,0 +1,38 @@ +/* Macro definitions for i386 using the GNU object file format. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * + * i386gnu: COFF_ENCAPSULATE + */ + + +#define COFF_ENCAPSULATE + +#include "tm-i386v.h" + +/* The version in m-i386.h is for COFF. */ +#undef N_SET_MAGIC + +#define NAMES_HAVE_UNDERSCORE + +#undef COFF_FORMAT +#define READ_DBX_FORMAT diff --git a/gdb/tm-i386v.h b/gdb/tm-i386v.h new file mode 100644 index 00000000000..59f89671fa9 --- /dev/null +++ b/gdb/tm-i386v.h @@ -0,0 +1,307 @@ +/* Macro defintions for i386. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + */ + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* define this if you don't have the extension to coff that allows + * file names to appear in the string table + * (aux.x_file.x_foff) + */ +#define COFF_NO_LONG_FILE_NAMES + +/* turn this on when rest of gdb is ready */ +/* #define IEEE_FLOAT */ + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +/* #define NAMES_HAVE_UNDERSCORE */ + +/* Specify debugger information format. */ + +/* #define READ_DBX_FORMAT */ +#define COFF_FORMAT + +/* number of traps that happen between exec'ing the shell + * to run an inferior, and when we finally get to + * the inferior code. This is 2 on most implementations. + */ +#define START_INFERIOR_TRAPS_EXPECTED 4 + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + (read_memory_integer (read_register (SP_REGNUM), 4)) + +/* This is only supposed to work in execcore.c, where x == 0 and + this is called before any other fields are filled in. */ +#define N_SET_MAGIC(aouthdr, x) \ + bzero ((char *) &aouthdr, sizeof aouthdr) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x80000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xcc} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#define DECR_PC_AFTER_BREAK 1 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc3) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the 386. */ + +#define INVALID_FLOAT(p, len) (0) + +/* code to execute to print interesting information about the + * floating point processor (if any) + * No need to define if there is nothing to do. + */ +#define FLOAT_INFO { i386_float_info (); } + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 16 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* the order of the first 8 registers must match the compiler's + * numbering scheme (which is the same as the 386 scheme) + * also, this table must match regmap in i386-pinsn.c. + */ +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "ps", "cs", "ss", \ + "ds", "es", "fs", "gs", \ + } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define FP_REGNUM 5 /* Contains address of executing stack frame */ +#define SP_REGNUM 4 /* Contains address of top of stack */ + +#define PC_REGNUM 8 +#define PS_REGNUM 9 + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_REGS * 4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N)*4) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#define REGISTER_RAW_SIZE(N) (4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) (4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (0) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);} + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);} + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) (builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { (SP) -= sizeof (ADDR); \ + write_memory ((SP), &(ADDR), sizeof (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)) + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) (numargs) = i386_frame_num_args(fi) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); } + + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME { i386_push_dummy_frame (); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME { i386_pop_frame (); } + +/* this is + * call 11223344 (32 bit relative) + * int3 + */ + +#define CALL_DUMMY { 0x223344e8, 0xcc11 } + +#define CALL_DUMMY_LENGTH 8 + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ \ + int from, to, delta, loc; \ + loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \ + from = loc + 5; \ + to = (int)(fun); \ + delta = to - from; \ + *(int *)((char *)(dummyname) + 1) = delta; \ +} diff --git a/gdb/tm-i960.h b/gdb/tm-i960.h new file mode 100644 index 00000000000..5ddf8c2b9ac --- /dev/null +++ b/gdb/tm-i960.h @@ -0,0 +1,399 @@ +/* Parameters for target machine Intel 960, for GDB, the GNU debugger. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Contributed by Intel Corporation. +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Definitions to target GDB to any i960. */ + +#ifndef I80960 +#define I80960 +#endif + +/* Hook for the SYMBOL_CLASS of a parameter when decoding DBX symbol + information. In the i960, parameters can be stored as locals or as + args, depending on the type of the debug record. + + From empirical observation, gcc960 uses N_LSYM to indicate + arguments passed in registers and then copied immediately + to the frame, and N_PSYM to indicate arguments passed in a + g14-relative argument block. */ + +#define DBX_PARM_SYMBOL_CLASS(type) ((type == N_LSYM)? LOC_LOCAL_ARG: LOC_ARG) + +/* Byte order is configurable, but this machine runs little-endian. */ +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* We have IEEE floating point, if we have any float at all. */ + +#define IEEE_FLOAT + +/* 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 + + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance ip across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(ip) { ip = skip_prologue (ip); } +extern CORE_ADDR skip_prologue (); + +/* Immediately after a function call, return the saved ip. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function + executes some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) (saved_pc_after_call (frame)) +extern CORE_ADDR saved_pc_after_call (); + +/* Stack grows upward */ + +#define INNER_THAN > + +/* Nonzero if instruction at ip is a return instruction. */ + +#define ABOUT_TO_RETURN(ip) (read_memory_integer(ip,4) == 0x0a000000) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes. */ + +#define INVALID_FLOAT(p, len) (0) + +/* How long (ordinary) registers are */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ +#define NUM_REGS 40 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES { \ + /* 0 */ "pfp", "sp", "rip", "r3", "r4", "r5", "r6", "r7", \ + /* 8 */ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",\ + /* 16 */ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", \ + /* 24 */ "g8", "g9", "g10", "g11", "g12", "g13", "g14", "fp", \ + /* 32 */ "pc", "ac", "ip", "tc", "fp0", "fp1", "fp2", "fp3", \ +} + +/* Register numbers of various important registers (used to index + into arrays of register names and register values). */ + +#define R0_REGNUM 0 /* First local register */ +#define SP_REGNUM 1 /* Contains address of top of stack */ +#define RIP_REGNUM 2 /* Return instruction pointer (local r2) */ +#define R15_REGNUM 15 /* Last local register */ +#define G0_REGNUM 16 /* First global register */ +#define G13_REGNUM 29 /* g13 - holds struct return address */ +#define G14_REGNUM 30 /* g14 - ptr to arg block / leafproc return address */ +#define FP_REGNUM 31 /* Contains address of executing stack frame */ +#define PCW_REGNUM 32 /* process control word */ +#define ACW_REGNUM 33 /* arithmetic control word */ +#define IP_REGNUM 34 /* instruction pointer */ +#define TCW_REGNUM 35 /* trace control word */ +#define FP0_REGNUM 36 /* First floating point register */ + +/* Some registers have more than one name */ + +#define PC_REGNUM IP_REGNUM /* GDB refers to ip as the Program Counter */ +#define PFP_REGNUM R0_REGNUM /* Previous frame pointer */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES ((36*4) + (4*10)) + +/* Index within `registers' of the first byte of the space for register N. */ + +#define REGISTER_BYTE(N) ( (N) < FP0_REGNUM ? \ + (4*(N)) : ((10*(N)) - (6*FP0_REGNUM)) ) + +/* The i960 has register windows, sort of. */ + +#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" upon + subroutine calls and thus there is no need to search more than one + stack frame for it. + + On the i960, in fact, the name of this register in another frame is + "mud" -- there is no overlap between the windows. Each window is + simply saved into the stack (true for our purposes, after having been + flushed; normally they reside on-chip and are restored from on-chip + without ever going to memory). */ + +#define REGISTER_IN_WINDOW_P(regnum) ((regnum) <= R15_REGNUM) + +/* Number of bytes of storage in the actual machine representation + for register N. On the i960, all regs are 4 bytes except for floating + point, which are 10. NINDY only sends us 8 byte values for these, + which is a pain, but VxWorks handles this correctly, so we must. */ + +#define REGISTER_RAW_SIZE(N) ( (N) < FP0_REGNUM ? 4 : 10 ) + +/* Number of bytes of storage in the program's representation for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) ( (N) < FP0_REGNUM ? 4 : 8 ) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 10 + +/* 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) ((N) >= FP0_REGNUM) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ \ + extern struct ext_format ext_format_i960[]; \ + \ + if ((REGNUM) >= FP0_REGNUM) \ + ieee_extended_to_double (ext_format_i960, (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) \ +{ \ + extern struct ext_format ext_format_i960[]; \ + \ + if ((REGNUM) >= FP0_REGNUM) \ + double_to_ieee_extended (ext_format_i960, (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) ((N) < FP0_REGNUM ? \ + builtin_type_int : builtin_type_double) + +/* Macros for understanding function return values... */ + +/* Does the specified function use the "struct returning" convention + or the "value returning" convention? The "value returning" convention + almost invariably returns the entire value in registers. The + "struct returning" convention often returns the entire value in + memory, and passes a pointer (out of or into the function) saying + where the value (is or should go). + + Since this sometimes depends on whether it was compiled with GCC, + this is also an argument. This is used in call_function to build a + stack, and in value_being_returned to print return values. + + On i960, a structure is returned in registers g0-g3, if it will fit. + If it's more than 16 bytes long, g13 pointed to it on entry. */ + +#define USE_STRUCT_CONVENTION(gcc_p, type) (TYPE_LENGTH (type) > 16) + +/* 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. This is only called if USE_STRUCT_CONVENTION for this + type is 0. + + On the i960 we just take as many bytes as we need from G0 through G3. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy(REGBUF+REGISTER_BYTE(G0_REGNUM), VALBUF, TYPE_LENGTH (TYPE)) + +/* If USE_STRUCT_CONVENTION produces a 1, + 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). + + Address of where to put structure was passed in in global + register g13 on entry. God knows what's in g13 now. The + (..., 0) below is to make it appear to return a value, though + actually all it does is call error(). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ + (error("Don't know where large structure is returned on i960"), 0) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format, for "value returning" functions. + + For 'return' command: not (yet) implemented for i960. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + error ("Returning values from functions is not implemented in i960 gdb") + +/* 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) \ + error ("Returning values from functions is not implemented in i960 gdb") + +/* 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. */ + +/* We cache information about saved registers in the frame structure, + to save us from having to re-scan function prologues every time + a register in a non-current frame is accessed. */ + +#define EXTRA_FRAME_INFO \ + struct frame_saved_regs *fsr; \ + CORE_ADDR arg_pointer; + +/* Zero the frame_saved_regs pointer when the frame is initialized, + so that FRAME_FIND_SAVED_REGS () will know to allocate and + initialize a frame_saved_regs struct the first time it is called. + Set the arg_pointer to -1, which is not valid; 0 and other values + indicate real, cached values. */ + +#define INIT_EXTRA_FRAME_INFO(fi) ((fi)->fsr = 0, (fi)->arg_pointer = -1) + +/* On the i960, we get the chain pointer by reading the PFP saved + on the stack and clearing the status bits. */ + +#define FRAME_CHAIN(thisframe) \ + (read_memory_integer (FRAME_FP(thisframe), 4) & ~0xf) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* FRAME_CHAIN_VALID returns zero if the given frame is the outermost one + and has no caller. In that case, FRAME_CHAIN_COMBINE is not used. + + On the i960, each various target system type must define FRAME_CHAIN_VALID, + since it differs between NINDY and VxWorks, the two currently supported + targets types. We leave it undefined here. */ + + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ + +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + { (FRAMELESS) = (leafproc_return ((FI)->pc) != 0); } + +/* Note that in the i960 architecture the return pointer is saved in the + *caller's* stack frame. + + Make sure to zero low-order bits because of bug in 960CA A-step part + (instruction addresses should always be word-aligned anyway). */ + +#define FRAME_SAVED_PC(frame) \ + ((read_memory_integer(FRAME_CHAIN(frame)+8,4)) & ~3) + +/* On the i960, FRAME_ARGS_ADDRESS should return the value of + g14 as passed into the frame, if known. We need a function for this. + We cache this value in the frame info if we've already looked it up. */ + +#define FRAME_ARGS_ADDRESS(fi) \ + (((fi)->arg_pointer != -1)? (fi)->arg_pointer: frame_args_address (fi, 0)) +extern CORE_ADDR frame_args_address (); /* i960-tdep.c */ + +/* This is the same except it should return 0 when + it does not really know where the args are, rather than guessing. + This value is not cached since it is only used infrequently. */ + +#define FRAME_ARGS_ADDRESS_CORRECT(fi) (frame_args_address (fi, 1)) + +#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame + +/* Set NUMARGS to the number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) (numargs = -1) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 0 + +/* Produce the positions of the saved registers in a stack frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info_addr, sr) \ + frame_find_saved_regs (frame_info_addr, &sr) +extern void frame_find_saved_regs(); /* See i960-tdep.c */ + + +/* Print status when we get a random unexpected signal. We have more + kinds of signals than Unix does... */ + +#define PRINT_RANDOM_SIGNAL(stop_signal) print_fault (stop_signal) + +/* Things needed for making calls to functions in the inferior process */ + +/* Push an empty stack frame, to record the current ip, etc. + + Not (yet?) implemented for i960. */ + +#define PUSH_DUMMY_FRAME \ +error("Function calls into the inferior process are not supported on the i960") + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ + pop_frame () + + +/* This sequence of words is the instructions + + callx 0x00000000 + fmark + */ + +/* #define CALL_DUMMY { 0x86003000, 0x00000000, 0x66003e00 } */ + +/* #define CALL_DUMMY_START_OFFSET 0 *//* Start execution at beginning of dummy */ + +/* Indicate that we don't support calling inferior child functions. */ + +#undef CALL_DUMMY + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at 'dummyname'. + + Ignore arg count on i960. */ + +/* #define FIX_CALL_DUMMY(dummyname, fun, nargs) *(((int *)dummyname)+1) = fun */ + +#undef FIX_CALL_DUMMY + + +/* Interface definitions for kernel debugger KDB */ +/* (Not relevant to i960.) */ diff --git a/gdb/tm-isi.h b/gdb/tm-isi.h new file mode 100644 index 00000000000..7697a9fb374 --- /dev/null +++ b/gdb/tm-isi.h @@ -0,0 +1,227 @@ +/* Definitions to target GDB on an ISI Optimum V (3.05) under 4.3bsd. + Copyright (C) 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This has not been tested on ISI's running BSD 4.2, but it will probably + work. */ + +/* 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 + +/*#define STACK_END_ADDR 0x10000000*/ +#define STACK_END_ADDR 0xfffe000 + +/* Data segment starts at etext rounded up to DATAROUND in {N,Z}MAGIC files */ + +#define DATAROUND 0x20000 +#define N_DATADDR(hdr) (hdr.a_magic != OMAGIC ? \ + (hdr.a_text + DATAROUND) & ~(DATAROUND-1) : hdr.a_text) + +/* Text segment starts at sizeof (struct exec) in {N,Z}MAGIC files */ + +#define N_TXTADDR(hdr) (hdr.a_magic != OMAGIC ? sizeof (struct exec) : 0) + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. + On the ISI, the kernel resets the pc to the trap instr */ + +#define DECR_PC_AFTER_BREAK 0 + + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + register int insn; \ + register int offset; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info)->pc <= (frame_info)->frame) \ + { next_addr = (frame_info)->frame; \ + pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info)->pc); \ + /* Verify we have a link a6 instruction next, \ + or a branch followed by a link a6 instruction; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ +retry: \ + insn = read_memory_integer (pc, 2); \ + if (insn == 044016) \ + next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 4), pc+=4; \ + else if (insn == 047126) \ + next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 2), pc+=2; \ + else if ((insn & 0177400) == 060000) /* bra insn */ \ + { offset = insn & 0377; \ + pc += 2; /* advance past bra */ \ + if (offset == 0) /* bra #word */ \ + offset = read_memory_integer (pc, 2), pc += 2; \ + else if (offset == 0377) /* bra #long */ \ + offset = read_memory_integer (pc, 4), pc += 4; \ + pc += offset; \ + goto retry; \ + } else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + insn = read_memory_integer (pc, 2), pc += 2; \ + regmask = read_memory_integer (pc, 2); \ + if ((insn & 0177760) == 022700) /* movl rn, (sp) */ \ + (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr; \ + else if ((insn & 0177760) == 024700) /* movl rn, -(sp) */ \ + (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr-=4; \ + else if (insn == 0044327) /* moveml mask, (sp) */ \ + { pc += 2; \ + /* Regmask's low bit is for register 0, the first written */ \ + next_addr -= 4; \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4); \ + } else if (insn == 0044347) /* moveml mask, -(sp) */ \ + { pc += 2; \ + /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (read_memory_integer (pc, 2) == 041147 \ + && read_memory_integer (pc+2, 2) == 042347) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM), \ + read_pc ())); } + +/* This sequence of words is the instructions + fmovem #,-(sp) + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @#32323232 + addl #69696969,sp + bpt + nop +Note this is 24 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } + +#define HAVE_68881 1 + +#include "tm-68k.h" diff --git a/gdb/tm-m88k.h b/gdb/tm-m88k.h new file mode 100644 index 00000000000..1890d6ca672 --- /dev/null +++ b/gdb/tm-m88k.h @@ -0,0 +1,460 @@ +/* Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This is currently for a 88000 running DGUX. If other 88k ports are + done, OS-specific stuff should be moved (see tm-68k.h, for example). */ +/* g++ support is not yet included. */ + +#include "tdesc.h" + +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* This is not a CREATE_INFERIOR_HOOK because it also applies to + remote debugging. */ +#define START_INFERIOR_HOOK () \ + { \ + extern int safe_to_init_tdesc_context; \ + extern int tdesc_handle; \ + \ + safe_to_init_tdesc_context = 0; \ + if (tdesc_handle) \ + { \ + dc_terminate (tdesc_handle); \ + tdesc_handle = 0; \ + } \ + } + +#define EXTRA_FRAME_INFO dc_dcontext_t frame_context; +#define INIT_EXTRA_FRAME_INFO(fci) \ + { \ + if (fci->next_frame != NULL) \ + { \ + /* The call to get_prev_context */ \ + /* will update current_context for us. */ \ + int stack_error = 1; \ + jmp_buf stack_jmp; \ + if (!setjmp (stack_jmp)) \ + { \ + prev->frame_context \ + = get_prev_context (next_frame->frame_context); \ + stack_error = 0; \ + } \ + else \ + { \ + stack_error = 0; \ + next_frame->prev = 0; \ + return 0; \ + } \ + if (!prev->frame_context) \ + { \ + next_frame->prev = 0; \ + return 0; \ + } \ + } \ + else \ + { \ + /* We are creating an arbitrary frame */ \ + /* (i.e. we are in create_new_frame). */ \ + extern dc_dcontext_t current_context; \ + \ + fci->frame_context = current_context; \ + } \ + } + +#define INIT_FRAME_PC(fromleaf, prev) \ + { \ + prev->pc = dc_location (prev->frame_context); \ + prev->frame = get_frame_base (prev->pc); \ + } + +#define IEEE_FLOAT + +/* Text Description (TDESC) is used by m88k to maintain stack & reg info */ + +#define TDESC + +/* 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 + +/* Hook for read_relative_register_raw_bytes */ + +#define READ_RELATIVE_REGISTER_RAW_BYTES + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(frompc) 0 + +/* The m88k kernel aligns all instructions on 4-byte boundaries. The + kernel also uses the least significant two bits for its own hocus + pocus. When gdb receives an address from the kernel, it needs to + preserve those right-most two bits, but gdb also needs to be careful + to realize that those two bits are not really a part of the address + of an instruction. Shrug. */ + +#define ADDR_BITS_REMOVE(addr) ((addr) & ~3) +#define ADDR_BITS_SET(addr) (((addr) | 0x00000002) - 4) + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + (read_register (SRP_REGNUM) & (~3)) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xF0000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +/* instruction 0xF000D1FF is 'tb0 0,r0,511' + If Bit bit 0 of r0 is clear (always true), + initiate exception processing (trap). + */ +#define BREAKPOINT {0xF0, 0x00, 0xD1, 0xFF} + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xF0000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +/* instruction 0xF000D1FF is 'tb0 0,r0,511' + If Bit bit 0 of r0 is clear (always true), + initiate exception processing (trap). + */ +#define BREAKPOINT {0xF0, 0x00, 0xD1, 0xFF} + +/* 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. */ +/* 'jmp r1' or 'jmp.n r1' is used to return from a subroutine. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0xF800) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the 386. */ + +#define INVALID_FLOAT(p, len) IEEE_isNAN(p,len) + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 38 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {\ + "r0",\ + "r1",\ + "r2",\ + "r3",\ + "r4",\ + "r5",\ + "r6",\ + "r7",\ + "r8",\ + "r9",\ + "r10",\ + "r11",\ + "r12",\ + "r13",\ + "r14",\ + "r15",\ + "r16",\ + "r17",\ + "r18",\ + "r19",\ + "r20",\ + "r21",\ + "r22",\ + "r23",\ + "r24",\ + "r25",\ + "r26",\ + "r27",\ + "r28",\ + "r29",\ + "r30",\ + "r31",\ + "psr",\ + "fpsr",\ + "fpcr",\ + "sxip",\ + "snip",\ + "sfip",\ + "vbr",\ + "dmt0",\ + "dmd0",\ + "dma0",\ + "dmt1",\ + "dmd1",\ + "dma1",\ + "dmt2",\ + "dmd2",\ + "dma2",\ + "sr0",\ + "sr1",\ + "sr2",\ + "sr3",\ + "fpecr",\ + "fphs1",\ + "fpls1",\ + "fphs2",\ + "fpls2",\ + "fppt",\ + "fprh",\ + "fprl",\ + "fpit",\ + "fpsr",\ + "fpcr",\ + }; + + +/* 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 SRP_REGNUM 1 /* Contains subroutine return pointer */ +#define RV_REGNUM 2 /* Contains simple return values */ +#define SRA_REGNUM 12 /* Contains address of struct return values */ +#define FP_REGNUM 30 /* Contains address of executing stack frame */ +#define SP_REGNUM 31 /* Contains address of top of stack */ +#define SXIP_REGNUM 35 /* Contains Shadow Execute Instruction Pointer */ +#define SNIP_REGNUM 36 /* Contains Shadow Next Instruction Pointer */ +#define PC_REGNUM SXIP_REGNUM /* Program Counter */ +#define NPC_REGNUM SNIP_REGNUM /* Next Program Counter */ +#define PSR_REGNUM 32 /* Processor Status Register */ +#define FPSR_REGNUM 33 /* Floating Point Status Register */ +#define FPCR_REGNUM 34 /* Floating Point Control Register */ +#define SFIP_REGNUM 37 /* Contains Shadow Fetched Intruction pointer */ +#define NNPC_REGNUM SFIP_REGNUM /* Next Next Program Counter */ + +/* PSR status bit definitions. */ + +#define PSR_MODE 0x80000000 +#define PSR_BYTE_ORDER 0x40000000 +#define PSR_SERIAL_MODE 0x20000000 +#define PSR_CARRY 0x10000000 +#define PSR_SFU_DISABLE 0x000003f0 +#define PSR_SFU1_DISABLE 0x00000008 +#define PSR_MXM 0x00000004 +#define PSR_IND 0x00000002 +#define PSR_SFRZ 0x00000001 + +/* BCS requires that the SXIP_REGNUM (or PC_REGNUM) contain the address + of the next instr to be executed when a breakpoint occurs. Because + the kernel gets the next instr (SNIP_REGNUM), the instr in SNIP needs + to be put back into SFIP, and the instr in SXIP should be shifted + to SNIP */ + +/* Are you sitting down? It turns out that the 88K BCS (binary compatibility + standard) folks originally felt that the debugger should be responsible + for backing up the IPs, not the kernel (as is usually done). Well, they + have reversed their decision, and in future releases our kernel will be + handling the backing up of the IPs. So, eventually, we won't need to + do the SHIFT_INST_REGS stuff. But, for now, since there are 88K systems out + there that do need the debugger to do the IP shifting, and since there + will be systems where the kernel does the shifting, the code is a little + more complex than perhaps it needs to be (we still go inside SHIFT_INST_REGS, + and if the shifting hasn't occurred then gdb goes ahead and shifts). */ + +#define SHIFT_INST_REGS + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ + +#define REGISTER_BYTES (NUM_REGS * sizeof(REGISTER_TYPE)) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N)*sizeof(REGISTER_TYPE)) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#define REGISTER_RAW_SIZE(N) (sizeof(REGISTER_TYPE)) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) (sizeof(REGISTER_TYPE)) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE (sizeof(REGISTER_TYPE)) + +/* Largest value REGISTER_VIRTUAL_SIZE can have. +/* Are FPS1, FPS2, FPR "virtual" regisers? */ + +#define MAX_REGISTER_VIRTUAL_SIZE (sizeof(REGISTER_TYPE)) + +/* 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), (sizeof(REGISTER_TYPE)));} + +/* 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), (sizeof(REGISTER_TYPE)));} + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) (builtin_type_int) + +/* The 88k call/return conventions call for "small" values to be returned + into consecutive registers starting from r2. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (&(((void *)REGBUF)[REGISTER_BYTE(RV_REGNUM)]), (VALBUF), TYPE_LENGTH (TYPE)) + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (2*sizeof(void*), (VALBUF), TYPE_LENGTH (TYPE)) + +/* In COFF, if PCC says a parameter is a short or a char, do not + change it to int (it seems the convention is to change it). */ + +#define BELIEVE_PCC_PROMOTION 1 + +/* 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. */ + +/* These are just dummies for the 88k because INIT_FRAME_PC sets prev->frame + instead. */ + +#define FRAME_CHAIN(thisframe) (0) + +#define FRAME_CHAIN_VALID(chain, thisframe) (1) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (0) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame+4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) ((numargs) = -1) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 0 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +/* On the 88k, parameter registers get stored into the so called "homing" + area. This *always* happens when you compiled with GCC and use -g. + Also, (with GCC and -g) the saving of the parameter register values + always happens right within the function prologue code, so these register + values can generally be relied upon to be already copied into their + respective homing slots by the time you will normally try to look at + them (we hope). + + Note that homing area stack slots are always at *positive* offsets from + the frame pointer. Thus, the homing area stack slots for the parameter + registers (passed values) for a given function are actually part of the + frame area of the caller. This is unusual, but it should not present + any special problems for GDB. + + Note also that on the 88k, we are only interested in finding the + registers that might have been saved in memory. This is a subset of + the whole set of registers because the standard calling sequence allows + the called routine to clobber many registers. + + We could manage to locate values for all of the so called "preserved" + registers (some of which may get saved within any particular frame) but + that would require decoding all of the tdesc information. Tht would be + nice information for GDB to have, but it is not strictly manditory if we + can live without the ability to look at values within (or backup to) + previous frames. +*/ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ + frame_find_saved_regs (frame_info, &frame_saved_regs) + + +/* When popping a frame on the 88k (say when doing a return command), the + calling function only expects to have the "preserved" registers restored. + Thus, those are the only ones that we even try to restore here. */ + +extern void pop_frame (); + +#define POP_FRAME pop_frame () + +/* BCS is a standard for binary compatibility. This machine uses it. */ +#define BCS diff --git a/gdb/tm-merlin.h b/gdb/tm-merlin.h new file mode 100644 index 00000000000..91475c89383 --- /dev/null +++ b/gdb/tm-merlin.h @@ -0,0 +1,364 @@ +/* Definitions to target GDB to a merlin under utek 2.1 + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* I don't know if this will work for cross-debugging, even if you do get + a copy of the right include file. */ +#include + +/* 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, 1); \ + if (op == 0x82) \ + { op = read_memory_integer (pc+2,1); \ + if ((op & 0x80) == 0) pc += 3; \ + else if ((op & 0xc0) == 0x80) pc += 4; \ + else pc += 6; \ + }} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + read_memory_integer (read_register (SP_REGNUM), 4) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0x800000) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xf2} + +/* 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, 1) == 0x12) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 + +/* Define this to say that the "svc" insn is followed by + codes in memory saying which kind of system call it is. */ + +#define NS32K_SVC_IMMED_OPERANDS + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 25 + +#define NUM_GENERAL_REGS 8 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "pc", "sp", "fp", "ps", \ + "fsr", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "l0", "l1", "l2", "l3", "l4", \ + } + +/* 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 AP_REGNUM FP_REGNUM +#define FP_REGNUM 10 /* Contains address of executing stack frame */ +#define SP_REGNUM 9 /* Contains address of top of stack */ +#define PC_REGNUM 8 /* Contains program counter */ +#define PS_REGNUM 11 /* Contains processor status */ +#define FPS_REGNUM 12 /* Floating point status register */ +#define FP0_REGNUM 13 /* Floating point register 0 */ +#define LP0_REGNUM 21 /* Double register 0 (same as FP0) */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES ((NUM_REGS - 4) * sizeof (int) + 4 * sizeof (double)) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N) >= LP0_REGNUM ? \ + LP0_REGNUM * 4 + ((N) - LP0_REGNUM) * 8 : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 32000, all regs are 4 bytes + except for the doubled floating registers. */ + +#define REGISTER_RAW_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 32000, all regs are 4 bytes + except for the doubled floating registers. */ + +#define REGISTER_VIRTUAL_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 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), REGISTER_VIRTUAL_SIZE(REGNUM)); + +/* 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), REGISTER_VIRTUAL_SIZE(REGNUM)); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N) >= FP0_REGNUM ? \ + ((N) >= LP0_REGNUM ? \ + builtin_type_double \ + : builtin_type_float) \ + : builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. + + On this machine this is a no-op, as gcc doesn't run on it yet. + This calling convention is not used. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#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 Merlin, the frame's nominal address is the FP value, + and at that address is saved previous FP value as a 4-byte word. */ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +/* compute base of arguments */ +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) \ +{ CORE_ADDR pc; \ + int insn; \ + int addr_mode; \ + int width; \ + \ + pc = FRAME_SAVED_PC (fi); \ + insn = read_memory_integer (pc,2); \ + addr_mode = (insn >> 11) & 0x1f; \ + insn = insn & 0x7ff; \ + if ((insn & 0x7fc) == 0x57c \ + && addr_mode == 0x14) /* immediate */ \ + { if (insn == 0x57c) /* adjspb */ \ + width = 1; \ + else if (insn == 0x57d) /* adjspw */ \ + width = 2; \ + else if (insn == 0x57f) /* adjspd */ \ + width = 4; \ + numargs = read_memory_integer (pc+2,width); \ + if (width > 1) \ + flip_bytes (&numargs, width); \ + numargs = - sign_extend (numargs, width*8) / 4; } \ + else numargs = -1; \ +} + +/* 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) \ +{ int regmask,regnum; \ + int localcount; \ + CORE_ADDR enter_addr; \ + CORE_ADDR next_addr; \ + \ + enter_addr = get_pc_function_start ((frame_info)->pc); \ + regmask = read_memory_integer (enter_addr+1, 1); \ + localcount = ns32k_localcount (enter_addr); \ + next_addr = (frame_info)->frame + localcount; \ + for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \ + (frame_saved_regs).regs[regnum] \ + = (regmask & 1) ? (next_addr -= 4) : 0; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 4; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ + (frame_saved_regs).regs[FP_REGNUM] \ + = read_memory_integer ((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; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = 0; regnum < 8; regnum++) \ + sp = push_word (sp, read_register (regnum)); \ + write_register (SP_REGNUM, sp); \ +} + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = 0; regnum < 8; regnum++) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); \ +} + +/* This sequence of words is the instructions + enter 0xff,0 82 ff 00 + jsr @0x00010203 7f ae c0 01 02 03 + adjspd 0x69696969 7f a5 01 02 03 04 + bpt f2 + Note this is 16 bytes. */ + +#define CALL_DUMMY { 0x7f00ff82, 0x0201c0ae, 0x01a57f03, 0xf2040302 } + +#define CALL_DUMMY_START_OFFSET 3 +#define CALL_DUMMY_LENGTH 16 +#define CALL_DUMMY_ADDR 5 +#define CALL_DUMMY_NARGS 11 + +/* 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, args, type, gcc_p) \ +{ int flipped = fun | 0xc0000000; \ + flip_bytes (&flipped, 4); \ + *((int *) (((char *) dummyname)+CALL_DUMMY_ADDR)) = flipped; \ + flipped = - nargs * 4; \ + flip_bytes (&flipped, 4); \ + *((int *) (((char *) dummyname)+CALL_DUMMY_NARGS)) = flipped; \ +} diff --git a/gdb/tm-mips.h b/gdb/tm-mips.h new file mode 100644 index 00000000000..6fd681dd426 --- /dev/null +++ b/gdb/tm-mips.h @@ -0,0 +1,363 @@ +/* Definitions to make GDB run on a mips box under 4.3bsd. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + Contributed by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin + and by Alessandro Forin(af@cs.cmu.edu) at CMU + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (TARGET_BYTE_ORDER) +#define TARGET_BYTE_ORDER LITTLE_ENDIAN +#endif + +/* Floating point is IEEE compliant */ +#define IEEE_FLOAT + +/* 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 mips' format */ + +#define READ_MIPS_FORMAT + +/* File format is coff, but with additions */ + +#define COFF_FORMAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) pc = mips_skip_prologue(pc) + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) read_register(RA_REGNUM) + +/* Are we currently handling a signal */ + +#define IN_SIGTRAMP(pc, name) in_sigtramp(pc, name) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0x7ffff000) + +/* Stack grows downward. */ + +#define INNER_THAN < + +#define BIG_ENDIAN 4321 +#if TARGET_BYTE_ORDER == BIG_ENDIAN +#define BREAKPOINT {0, 0x5, 0, 0xd} +#else +#define BREAKPOINT {0xd, 0, 0x5, 0} +#endif + +/* 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. "j ra" on mips. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 4) == 0x3e00008) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p,l) isa_NAN(p,l) + +/* Say how long (all) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 73 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", \ + "sr", "lo", "hi", "bad", "cause","pc", \ + "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",\ + "fsr", "fir", "fp" \ + } + +/* 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 SP_REGNUM 29 /* Contains address of top of stack */ +#define PC_REGNUM 37 /* Contains program counter */ +#define RA_REGNUM 31 /* Contains return address value */ +#define PS_REGNUM 32 /* Contains processor status */ +#define HI_REGNUM 34 /* Multiple/divide temp */ +#define LO_REGNUM 33 /* ... */ +#define FP0_REGNUM 38 /* Floating point register 0 (single float) */ +#define FCRCS_REGNUM 70 /* FP control/status */ +#define FCRIR_REGNUM 71 /* FP implementation/revision */ +#define FP_REGNUM 72 /* Pseudo register that contains true address of executing stack frame */ + +/* Define DO_REGISTERS_INFO() to do machine-specific formatting + of register dumps. */ + +#define DO_REGISTERS_INFO(_regnum) mips_do_registers_info(_regnum) + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + if (blockend == 0) { \ + if (regno < 38) addr = (NBPG*UPAGES) + (regno - 38)*sizeof(int);\ + else addr = 0; /* ..somewhere in the pcb */ \ + } else if (regno < 32) addr = regno; \ + else if (regno == PC_REGNUM) addr = 96; \ + else if (regno == 36) addr = 97; \ + else if (regno == HI_REGNUM) addr = 98; \ + else if (regno == LO_REGNUM) addr = 99; \ + else if (regno == FCRCS_REGNUM) addr = 100; \ + else if (regno == FCRIR_REGNUM) addr = 101; \ + else if (regno >= FP0_REGNUM) addr = regno - (FP0_REGNUM-32);\ + else addr = 0; + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_REGS*4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On mips, 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 mips, all regs are 4 bytes. */ + +#define REGISTER_VIRTUAL_SIZE(N) 4 + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) 0 + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ + bcopy ((FROM), (TO), 4); + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ + bcopy ((FROM), (TO), 4); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) builtin_type_int +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(addr, sp) \ + { sp = push_word(sp, 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. XXX floats */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (REGBUF+REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 2), 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 (REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 2), 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+16)) + +/* Structures are returned by ref in extra arg0 */ +#define USE_STRUCT_CONVENTION(gcc_p, type) 1 + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +#define FRAME_CHAIN(thisframe) (FRAME_ADDR)mips_frame_chain(thisframe) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +/* We handle this differently for mips, and maybe we should not */ + +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) {(FRAMELESS) = 0;} + +/* Saved Pc. */ + +#define FRAME_SAVED_PC(FRAME) (mips_frame_saved_pc(FRAME)) + +#define FRAME_ARGS_ADDRESS(fi) (fi)->frame + +#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(num, fi) (num = mips_frame_num_args(fi)) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 0 + +/* 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) ( \ + (frame_saved_regs) = *(frame_info)->saved_regs, \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame) + + +/* Things needed for making the inferior call functions. */ + +/* Stack has strict alignment. However, use PUSH_ARGUMENTS + to take care of it. */ +/*#define STACK_ALIGN(addr) (((addr)+3)&~3)*/ + +#define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \ + sp = mips_push_arguments(nargs, args, sp, struct_return, struct_addr) + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME mips_push_dummy_frame() + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME mips_pop_frame() + +#define MK_OP(op,rs,rt,offset) (((op)<<26)|((rs)<<21)|((rt)<<16)|(offset)) +#define CALL_DUMMY_SIZE (16*4) +#define Dest_Reg 2 +#define CALL_DUMMY {\ + MK_OP(0,RA_REGNUM,0,8), /* jr $ra # Fake ABOUT_TO_RETURN ...*/\ + 0, /* nop # ... to stop raw backtrace*/\ + 0x27bd0000, /* addu sp,?0 # Pseudo prologue */\ +/* Start here: */\ + MK_OP(061,SP_REGNUM,12,0), /* lwc1 $f12,0(sp) # Reload first 4 args*/\ + MK_OP(061,SP_REGNUM,13,4), /* lwc1 $f13,4(sp) */\ + MK_OP(061,SP_REGNUM,14,8), /* lwc1 $f14,8(sp) */\ + MK_OP(061,SP_REGNUM,15,12), /* lwc1 $f15,12(sp) */\ + MK_OP(043,SP_REGNUM,4,0), /* lw $r4,0(sp) # Re-load FP regs*/\ + MK_OP(043,SP_REGNUM,5,4), /* lw $r5,4(sp) */\ + MK_OP(043,SP_REGNUM,6,8), /* lw $r6,8(sp) */\ + MK_OP(043,SP_REGNUM,7,12), /* lw $r7,12(sp) */\ + (017<<26)| (Dest_Reg << 16), /* lui $r31,*/\ + MK_OP(13,Dest_Reg,Dest_Reg,0), /* ori $r31,$r31,*/ \ + (Dest_Reg<<21) | (31<<11) | 9, /* jalr $r31 */\ + MK_OP(043,SP_REGNUM,7,12), /* lw $r7,12(sp) */\ + 0x5000d, /* bpt */\ +} + +#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, start_sp, fun, nargs, args, rettype, gcc_p)\ + (((int*)dummyname)[11] |= (((unsigned long)(fun)) >> 16), \ + ((int*)dummyname)[12] |= (unsigned short)(fun)) + +/* Specific information about a procedure. + This overlays the MIPS's PDR records, + mipsread.c (ab)uses this to save memory */ + +typedef struct mips_extra_func_info { + unsigned long adr; /* memory address of start of procedure */ + long isym; /* pointer to procedure symbol */ + long pad2; /* iline: start of line number entries*/ + long regmask; /* save register mask */ + long regoffset; /* save register offset */ + long numargs; /* number of args to procedure (was iopt) */ + long fregmask; /* save floating point register mask */ + long fregoffset; /* save floating point register offset */ + long framesize; /* frameoffset: frame size */ + short framereg; /* frame pointer register */ + short pcreg; /* offset or reg of return pc */ + long lnLow; /* lowest line in the procedure */ + long lnHigh; /* highest line in the procedure */ + long pad3; /* cbLineOffset: byte offset for this procedure from the fd base */ +} *mips_extra_func_info_t; + +#define EXTRA_FRAME_INFO \ + char *proc_desc; /* actually, a mips_extra_func_info_t */\ + int num_args;\ + struct frame_saved_regs *saved_regs; + +#define INIT_EXTRA_FRAME_INFO(fci) init_extra_frame_info(fci) diff --git a/gdb/tm-news.h b/gdb/tm-news.h new file mode 100644 index 00000000000..ff50dbf47a9 --- /dev/null +++ b/gdb/tm-news.h @@ -0,0 +1,172 @@ +/* Parameters for execution on a Sony/NEWS, for GDB, the GNU debugger. + Copyright (C) 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* See following cpu type determination macro to get the machine type. + +Here is an m-news.h file for gdb. It supports the 68881 registers. + by hikichi@srava.sra.junet + +* Support Sun assembly format instead of Motorola one. +* Ptrace for handling floating register has a bug(before NEWS OS version 2.2), +* After NEWS OS version 3.2, some of ptrace's bug is fixed. + But we cannot change the floating register(see adb(1) in OS 3.2) yet. */ + +/* 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 + +/* Symbols on this machine are in DBX format. */ +#define READ_DBX_FORMAT + +/* Use to compute STACK_END_ADDR. */ +#define TARGET_UPAGES 2 +#define TARGET_NBPG 4096 + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0x80000000 - TARGET_UPAGES * TARGET_NBPG) + +/* 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. */ + +/* when it return the floating value, use the FP0 in NEWS. */ +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + { if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) \ + { \ + REGISTER_CONVERT_TO_VIRTUAL (FP0_REGNUM, \ + ®BUF[REGISTER_BYTE (FP0_REGNUM)], VALBUF); \ + } \ + else \ + bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)); } + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +/* when it return the floating value, use the FP0 in NEWS. */ +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + { if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) \ + { \ + char raw_buf[REGISTER_RAW_SIZE (FP0_REGNUM)]; \ + REGISTER_CONVERT_TO_RAW (FP0_REGNUM, VALBUF, raw_buf); \ + write_register_bytes (FP0_REGNUM, \ + raw_buf, REGISTER_RAW_SIZE (FP0_REGNUM)); \ + } \ + else \ + write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)); } + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } + +/* Things needed for making the inferior call functions. */ +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM), \ + read_pc ())); } + +/* This sequence of words is the instructions + fmove.m #,-(sp) + movem.l 0xfffc,-(sp) ;; no save a6(fp) and a7(sp) + clr.w -(sp) + move.w 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. *../ + jbsr (#32323232) + add.l #69696969,sp + bpt + nop +Note this is 24 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } + +#define HAVE_68881 + +#include "tm-68k.h" diff --git a/gdb/tm-nindy960.h b/gdb/tm-nindy960.h new file mode 100644 index 00000000000..e7ed59bfaba --- /dev/null +++ b/gdb/tm-nindy960.h @@ -0,0 +1,105 @@ +/* Parameters for Intel 960 running NINDY monitor, for GDB, the GNU debugger. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Contributed by Intel Corporation and Cygnus Support. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/***************************************************************************** + * Definitions to target GDB to an i960 debugged over a serial line. + ******************************************************************************/ + +#include "tm-i960.h" + +/* Override the standard gdb prompt when compiled for this target. */ + +#define DEFAULT_PROMPT "(gdb960) " + +/* Additional command line options accepted by nindy gdb's, for handling + the remote-nindy.c interface. These should really be target-specific + rather than architecture-specific. */ + +extern int nindy_old_protocol; /* nonzero if old NINDY serial protocol */ +extern int nindy_initial_brk; /* Send a BREAK to reset board first */ +extern char *nindy_ttyname; /* Name of serial port to talk to nindy */ + +#define ADDITIONAL_OPTIONS \ + {"O", 0, &nindy_old_protocol, 1}, \ + {"brk", 0, &nindy_initial_brk, 1}, \ + {"r", 1, 0, 1004}, /* 1004 is magic cookie for ADDL_CASES */ + +#define ADDITIONAL_OPTION_CASES \ + case 1004: /* -r option: remote nindy auto-start */ \ + nindy_ttyname = optarg; \ + break; + +#define ADDITIONAL_OPTION_HELP \ + "\ + -O Use old protocol to talk to a Nindy target\n\ + -brk Send a break to a Nindy target to reset it.\n\ + -r SERIAL Open remote Nindy session to SERIAL port.\n\ +" + +/* If specified on the command line, open tty for talking to nindy, + and download the executable file if one was specified. */ + +#define ADDITIONAL_OPTION_HANDLER \ + if (!setjmp (to_top_level) && nindy_ttyname) { \ + nindy_open (nindy_ttyname, !batch); \ + if ( !setjmp(to_top_level) && execarg ) { \ + target_load (execarg, !batch); \ + } \ + } + +/* If configured for i960 target, we take control before main loop + and demand that we configure for a nindy target. */ + +#define BEFORE_MAIN_LOOP_HOOK \ + nindy_before_main_loop(); + +/* Address of end of stack space. + * This probably doesn't matter for nindy, because it's only used + * in manipulation of core files, which we don't support. + */ + +#define STACK_END_ADDR (0xfe000000) + +/* FRAME_CHAIN_VALID returns zero if the given frame is the outermost one + and has no caller. In that case, FRAME_CHAIN_COMBINE is not used. + + On the i960, each various target system type defines FRAME_CHAIN_VALID, + since it differs between NINDY and VxWorks, the two currently supported + targets types. */ + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + nindy_frame_chain_valid (chain, thisframe) + +extern int nindy_frame_chain_valid(); /* See nindy-tdep.c */ + +/* Sequence of bytes for breakpoint instruction */ + +#define BREAKPOINT {0x00, 0x3e, 0x00, 0x66} + +/* Amount ip 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 + +/* Not needed, because we don't support core files: + * #define KERNEL_U_ADDR + * #define REGISTER_U_ADDR(addr, blockend, regno) + */ diff --git a/gdb/tm-np1.h b/gdb/tm-np1.h new file mode 100644 index 00000000000..0bb1dccf3f7 --- /dev/null +++ b/gdb/tm-np1.h @@ -0,0 +1,515 @@ +/* Parameters for targeting on a Gould NP1, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define GOULD_NPL + +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* N_ENTRY appears in libraries on Gould machines. + Don't know what 0xa4 is; it's mentioned in stab.h + but only in the sdb symbol list. */ +#define IGNORE_SYMBOL(type) (type == N_ENTRY || type == 0xa4) + +/* We don't want the extra gnu symbols on the machine; + they will interfere with the shared segment symbols. */ +#define NO_GNU_STABS + +/* Macro for text-offset and data info (in NPL a.out format). */ +#define TEXTINFO \ + text_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr); \ + exec_data_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr)\ + + exec_aouthdr.a_text + +/* Macro for number of symbol table entries */ +#define NUMBER_OF_SYMBOLS \ + (coffhdr.f_nsyms) + +/* Macro for file-offset of symbol table (in NPL a.out format). */ +#define SYMBOL_TABLE_OFFSET \ + N_SYMOFF (coffhdr) + +/* Macro for file-offset of string table (in NPL a.out format). */ +#define STRING_TABLE_OFFSET \ + (N_STROFF (coffhdr)) + +/* Macro to store the length of the string table data in INTO. */ +#define READ_STRING_TABLE_SIZE(INTO) \ + { INTO = hdr.a_stsize; } + +/* Macro to declare variables to hold the file's header data. */ +#define DECLARE_FILE_HEADERS struct exec hdr; \ + FILHDR coffhdr + +/* Macro to read the header data from descriptor DESC and validate it. + NAME is the file name, for error messages. */ +#define READ_FILE_HEADERS(DESC, NAME) \ +{ val = myread (DESC, &coffhdr, sizeof coffhdr); \ + if (val < 0) \ + perror_with_name (NAME); \ + val = myread (DESC, &hdr, sizeof hdr); \ + if (val < 0) \ + perror_with_name (NAME); \ + if (coffhdr.f_magic != GNP1MAGIC) \ + error ("File \"%s\" not in coff executable format.", NAME); \ + if (N_BADMAG (hdr)) \ + error ("File \"%s\" not in executable format.", NAME); } + +/* Define COFF and other symbolic names needed on NP1 */ +#define NS32GMAGIC GNP1MAGIC +#define NS32SMAGIC GPNMAGIC + +/* 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 + +/* Address of blocks in N_LBRAC and N_RBRAC symbols are absolute addresses, + not relative to start of source address. */ +#define BLOCK_ADDRESS_ABSOLUTE + +/* Offset from address of function to start of its code. + Zero on most machines. */ +#define FUNCTION_START_OFFSET 8 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. One NPL we can have one two startup + sequences depending on the size of the local stack: + + Either: + "suabr b2, #" + of + "lil r4, #", "suabr b2, #(r4)" + + "lwbr b6, #", "stw r1, 8(b2)" + Optional "stwbr b3, c(b2)" + Optional "trr r2,r7" (Gould first argument register passing) + or + Optional "stw r2,8(b3)" (Gould first argument register passing) + */ +#define SKIP_PROLOGUE(pc) { \ + register int op = read_memory_integer ((pc), 4); \ + if ((op & 0xffff0000) == 0xFA0B0000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if ((op & 0xffff0000) == 0x59400000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if ((op & 0xffff0000) == 0x5F000000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if (op == 0xD4820008) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if (op == 0x5582000C) { \ + pc += 4; \ + op = read_memory_integer ((pc), 2); \ + if (op == 0x2fa0) { \ + pc += 2; \ + } else { \ + op = read_memory_integer ((pc), 4); \ + if (op == 0xd5030008) { \ + pc += 4; \ + } \ + } \ + } else { \ + op = read_memory_integer ((pc), 2); \ + if (op == 0x2fa0) { \ + pc += 2; \ + } \ + } \ + } \ + } \ + } \ + } \ + if ((op & 0xffff0000) == 0x59000000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if ((op & 0xffff0000) == 0x5F000000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if (op == 0xD4820008) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if (op == 0x5582000C) { \ + pc += 4; \ + op = read_memory_integer ((pc), 2); \ + if (op == 0x2fa0) { \ + pc += 2; \ + } else { \ + op = read_memory_integer ((pc), 4); \ + if (op == 0xd5030008) { \ + pc += 4; \ + } \ + } \ + } else { \ + op = read_memory_integer ((pc), 2); \ + if (op == 0x2fa0) { \ + pc += 2; \ + } \ + } \ + } \ + } \ + } \ +} + +/* 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. True on NPL! Return address is in R1. + The true return address is REALLY 4 past that location! */ +#define SAVED_PC_AFTER_CALL(frame) \ + (read_register(R1_REGNUM) + 4) + +/* Address of end of stack space. */ +#define STACK_END_ADDR 0x7fffc000 + +/* Stack grows downward. */ +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. + This is padded out to the size of a machine word. When it was just + {0x28, 0x09} it gave problems if hit breakpoint on returning from a + function call. */ +#define BREAKPOINT {0x28, 0x09, 0x0, 0x0} + +/* 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. "bu 4(r1)" */ +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 4) == 0x40100004) + +/* Return 1 if P points to an invalid floating point value. */ +#define INVALID_FLOAT(p, len) ((*(short *)p & 0xff80) == 0x8000) + +/* Say how long (ordinary) registers are. */ +#define REGISTER_TYPE long + +/* Size of bytes of vector register (NP1 only), 32 elements * sizeof(int) */ +#define VR_SIZE 128 + +/* Number of machine registers */ +#define NUM_REGS 27 +#define NUM_GEN_REGS 16 +#define NUM_CPU_REGS 4 +#define NUM_VECTOR_REGS 7 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ +#define REGISTER_NAMES { \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", \ + "sp", "ps", "pc", "ve", \ + "v1", "v2", "v3", "v4", "v5", "v6", "v7", \ +} + +/* 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 R1_REGNUM 1 /* Gr1 => return address of caller */ +#define R2_REGNUM 2 /* Gr2 => return value from function */ +#define R4_REGNUM 4 /* Gr4 => register save area */ +#define R5_REGNUM 5 /* Gr5 => register save area */ +#define R6_REGNUM 6 /* Gr6 => register save area */ +#define R7_REGNUM 7 /* Gr7 => register save area */ +#define B1_REGNUM 9 /* Br1 => start of this code routine */ +#define SP_REGNUM 10 /* Br2 == (sp) */ +#define AP_REGNUM 11 /* Br3 == (ap) */ +#define FP_REGNUM 16 /* A copy of Br2 saved in trap */ +#define PS_REGNUM 17 /* Contains processor status */ +#define PC_REGNUM 18 /* Contains program counter */ +#define VE_REGNUM 19 /* Vector end (user setup) register */ +#define V1_REGNUM 20 /* First vector register */ +#define V7_REGNUM 26 /* First vector register */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES \ + (NUM_GEN_REGS*4 + NUM_VECTOR_REGS*VR_SIZE + NUM_CPU_REGS*4) + +/* Index within `registers' of the first byte of the space for + register N. */ +#define REGISTER_BYTE(N) \ + (((N) < V1_REGNUM) ? ((N) * 4) : (((N) - V1_REGNUM) * VR_SIZE) + 80) + +/* Number of bytes of storage in the actual machine representation + for register N. On the NP1, all normal regs are 4 bytes, but + the vector registers are VR_SIZE*4 bytes long. */ +#define REGISTER_RAW_SIZE(N) \ + (((N) < V1_REGNUM) ? 4 : VR_SIZE) + +/* Number of bytes of storage in the program's representation + for register N. On the NP1, all regs are 4 bytes. */ +#define REGISTER_VIRTUAL_SIZE(N) \ + (((N) < V1_REGNUM) ? 4 : VR_SIZE) + +/* Largest value REGISTER_RAW_SIZE can have. */ +#define MAX_REGISTER_RAW_SIZE VR_SIZE + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ +#define MAX_REGISTER_VIRTUAL_SIZE VR_SIZE + +/* 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), REGISTER_RAW_SIZE(REGNUM)); + +/* 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), REGISTER_VIRTUAL_SIZE(REGNUM)); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N) > VE_REGNUM ? builtin_type_np1_vector : builtin_type_int) +extern struct type *builtin_type_np1_vector; + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. + + On this machine this is a no-op, because gcc isn't used on it + yet. So this calling convention is not used. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) push_word(SP + 8, ADDR) + +/* Extract from an arrary REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (((int *)(REGBUF)) + 2, 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 (REGISTER_BYTE (R2_REGNUM), 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) + 2)) + +/* Both gcc and cc return small structs in registers (i.e. in GDB + terminology, small structs don't use the struct return convention). */ +#define USE_STRUCT_CONVENTION(gcc_p, type) (TYPE_LENGTH(type) > 8) + +/* 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 NPL, the frame's norminal address is Br2 and the + previous routines frame is up the stack X bytes, where X is the + value stored in the code function header xA(Br1). */ +#define FRAME_CHAIN(thisframe) (findframe(thisframe)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && chain != (thisframe)->frame) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) \ + (chain) + +/* Define other aspects of the stack frame on NPL. */ +#define FRAME_SAVED_PC(FRAME) \ + (read_memory_integer ((FRAME)->frame + 8, 4)) + +#define FRAME_ARGS_ADDRESS(fi) \ + ((fi)->next_frame ? \ + read_memory_integer ((fi)->frame + 12, 4) : \ + read_register (AP_REGNUM)) + +#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 check the stab info to see how + many arg we have. No info in stack will tell us */ +#define FRAME_NUM_ARGS(val,fi) (val = findarg(fi)) + +/* Return number of bytes at start of arglist that are not really args. */ +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + (frame_saved_regs).regs[SP_REGNUM] = framechain (frame_info); \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[R4_REGNUM] = (frame_info)->frame + 0x30; \ + (frame_saved_regs).regs[R5_REGNUM] = (frame_info)->frame + 0x34; \ + (frame_saved_regs).regs[R6_REGNUM] = (frame_info)->frame + 0x38; \ + (frame_saved_regs).regs[R7_REGNUM] = (frame_info)->frame + 0x3C; \ +} + +/* Things needed for making the inferior call functions. */ + +#define CANNOT_EXECUTE_STACK + +/* 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; \ + for (regnum = 0; regnum < FP_REGNUM; regnum++) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + write_register (SP_REGNUM, sp);} + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +#define POP_FRAME \ +{ CORE_ADDR sp = read_register(SP_REGNUM); \ + REGISTER_TYPE reg; \ + int regnum; \ + for(regnum = 0;regnum < FP_REGNUM;regnum++){ \ + sp-=sizeof(REGISTER_TYPE); \ + read_memory(sp,®,sizeof(REGISTER_TYPE)); \ + write_register(regnum,reg);} \ + sp-=sizeof(REGISTER_TYPE); \ + read_memory(sp,®,sizeof(REGISTER_TYPE)); \ + write_register(PS_REGNUM,reg); \ + sp-=sizeof(REGISTER_TYPE); \ + read_memory(sp,®,sizeof(REGISTER_TYPE)); \ + write_register(PC_REGNUM,reg);} + +/* MJD - Size of dummy frame pushed onto stack by PUSH_DUMMY_FRAME */ + +#define DUMMY_FRAME_SIZE (0x48) + +/* MJD - The sequence of words in the instructions is + halt + halt + halt + halt + subr b2,stack size,0 grab stack space for dummy call + labr b3,x0(b2),0 set AP_REGNUM to point at arguments + lw r2,x8(b3),0 load r2 with first argument + lwbr b1,arguments size(b2),0 load address of function to be called + brlnk r1,x8(b1),0 call function + halt + halt + labr b2,stack size(b2),0 give back stack + break break + */ + +#define CALL_DUMMY {0x00000000, \ + 0x00000000, \ + 0x59000000, \ + 0x598a0000, \ + 0xb5030008, \ + 0x5c820000, \ + 0x44810008, \ + 0x00000000, \ + 0x590a0000, \ + 0x28090000 } + +#define CALL_DUMMY_LENGTH 40 + +#define CALL_DUMMY_START_OFFSET 8 + +#define CALL_DUMMY_STACK_ADJUST 8 + +/* MJD - Fixup CALL_DUMMY for the specific function call. + OK heres the problems + 1) On a trap there are two copies of the stack pointer, one in SP_REGNUM + which is read/write and one in FP_REGNUM which is only read. It seems + that when restarting the GOULD NP1 uses FP_REGNUM's value. + 2) Loading function address into b1 looks a bit difficult if bigger than + 0x0000fffc, infact from what I can tell the compiler sets up table of + function address in base3 through which function calls are referenced. + + OK my solutions + Calculate the size of the dummy stack frame and do adjustments of + SP_REGNUM in the dummy call. + Push function address onto the stack and load it in the dummy call + */ + +#define FIX_CALL_DUMMY(dummyname, sp, fun, nargs, args, type, gcc_p) \ + { int i;\ + int arg_len = 0, total_len;\ + old_sp = push_word(old_sp,fun);\ + for(i = nargs - 1;i >= 0;i--)\ + arg_len += TYPE_LENGTH (VALUE_TYPE (value_arg_coerce (args[i])));\ + if(struct_return)\ + arg_len += TYPE_LENGTH(value_type);\ + total_len = DUMMY_FRAME_SIZE+CALL_DUMMY_STACK_ADJUST+4+arg_len;\ + dummyname[0] += total_len;\ + dummyname[2] += total_len;\ + dummyname[5] += arg_len+CALL_DUMMY_STACK_ADJUST;\ + dummyname[8] += total_len;} + +/* MJD - So the stack should end up looking like this + + | Normal stack frame | + | from normal program | + | flow | + +---------------------+ <- Final sp - 0x08 - argument size + | | - 0x4 - dummy_frame_size + | Pushed dummy frame | + | b0-b7, r0-r7 | + | pc and ps | + | | + +---------------------+ + | Function address | + +---------------------+ <- Final sp - 0x8 - arguments size + | | + | | + | | + | Arguments to | + | Function | + | | + | | + | | + +---------------------+ <- Final sp - 0x8 + | Dummy_stack_adjust | + +---------------------+ <- Final sp + | | + | where call will | + | build frame | +*/ diff --git a/gdb/tm-pn.h b/gdb/tm-pn.h new file mode 100644 index 00000000000..82bf9192968 --- /dev/null +++ b/gdb/tm-pn.h @@ -0,0 +1,444 @@ +/* Parameters for targe of a Gould Powernode, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define GOULD_PN + +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* This code appears in libraries on Gould machines. Ignore it. */ +#define IGNORE_SYMBOL(type) (type == N_ENTRY) + +/* We don't want the extra gnu symbols on the machine; + they will interfere with the shared segment symbols. */ +#define NO_GNU_STABS + +/* Macro for text-offset and data info (in PN a.out format). */ +#define TEXTINFO \ + text_offset = N_TXTOFF (exec_coffhdr); \ + exec_data_offset = N_TXTOFF (exec_coffhdr) \ + + exec_aouthdr.a_text + +/* Macro for number of symbol table entries */ +#define END_OF_TEXT_DEFAULT \ + (0xffffff) + +/* Macro for number of symbol table entries */ +#define NUMBER_OF_SYMBOLS \ + (coffhdr.f_nsyms) + +/* Macro for file-offset of symbol table (in usual a.out format). */ +#define SYMBOL_TABLE_OFFSET \ + N_SYMOFF (coffhdr) + +/* Macro for file-offset of string table (in usual a.out format). */ +#define STRING_TABLE_OFFSET \ + (N_STROFF (coffhdr) + sizeof(int)) + +/* Macro to store the length of the string table data in INTO. */ +#define READ_STRING_TABLE_SIZE(INTO) \ + { INTO = hdr.a_stsize; } + +/* Macro to declare variables to hold the file's header data. */ +#define DECLARE_FILE_HEADERS struct old_exec hdr; \ + FILHDR coffhdr + +/* Macro to read the header data from descriptor DESC and validate it. + NAME is the file name, for error messages. */ +#define READ_FILE_HEADERS(DESC, NAME) \ +{ val = myread (DESC, &coffhdr, sizeof coffhdr); \ + if (val < 0) \ + perror_with_name (NAME); \ + val = myread (DESC, &hdr, sizeof hdr); \ + if (val < 0) \ + perror_with_name (NAME); \ + if (coffhdr.f_magic != GNP1MAGIC) \ + error ("File \"%s\" not in coff executable format.", NAME); \ + if (N_BADMAG (hdr)) \ + error ("File \"%s\" not in executable format.", NAME); } + +/* Define COFF and other symbolic names needed on NP1 */ +#define NS32GMAGIC GDPMAGIC +#define NS32SMAGIC PN_MAGIC +/* 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 4 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. One PN we can have one or two startup + sequences depending on the size of the local stack: + + Either: + "suabr b2, #" + of + "lil r4, #", "suabr b2, #(r4)" + + "lwbr b6, #", "stw r1, 8(b2)" + Optional "stwbr b3, c(b2)" + Optional "trr r2,r7" (Gould first argument register passing) + or + Optional "stw r2,8(b3)" (Gould first argument register passing) + */ +#define SKIP_PROLOGUE(pc) { \ + register int op = read_memory_integer ((pc), 4); \ + if ((op & 0xffff0000) == 0x580B0000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if ((op & 0xffff0000) == 0x59400000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if ((op & 0xffff0000) == 0x5F000000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if (op == 0xD4820008) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if (op == 0x5582000C) { \ + pc += 4; \ + op = read_memory_integer ((pc), 2); \ + if (op == 0x2fa0) { \ + pc += 2; \ + } else { \ + op = read_memory_integer ((pc), 4); \ + if (op == 0xd5030008) { \ + pc += 4; \ + } \ + } \ + } else { \ + op = read_memory_integer ((pc), 2); \ + if (op == 0x2fa0) { \ + pc += 2; \ + } \ + } \ + } \ + } \ + } \ + } \ + if ((op & 0xffff0000) == 0x59000000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if ((op & 0xffff0000) == 0x5F000000) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if (op == 0xD4820008) { \ + pc += 4; \ + op = read_memory_integer ((pc), 4); \ + if (op == 0x5582000C) { \ + pc += 4; \ + op = read_memory_integer ((pc), 2); \ + if (op == 0x2fa0) { \ + pc += 2; \ + } else { \ + op = read_memory_integer ((pc), 4); \ + if (op == 0xd5030008) { \ + pc += 4; \ + } \ + } \ + } else { \ + op = read_memory_integer ((pc), 2); \ + if (op == 0x2fa0) { \ + pc += 2; \ + } \ + } \ + } \ + } \ + } \ +} + +/* 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. True on PN! Return address is in R1. + Note: true return location is 4 bytes past R1! */ +#define SAVED_PC_AFTER_CALL(frame) \ + (read_register(R1_REGNUM) + 4) + +/* Address of end of stack space. */ +#define STACK_END_ADDR 0x480000 + +/* Stack grows downward. */ +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ +#define BREAKPOINT {0x28, 0x09} + +/* 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. "bu 4(r1)" */ +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 4) == 0xEC100004) + +/* Return 1 if P points to an invalid floating point value. */ +#define INVALID_FLOAT(p, len) ((*(short *)p & 0xff80) == 0x8000) + +/* Say how long (ordinary) registers are. */ +#define REGISTER_TYPE long + +/* Number of machine registers */ +#define NUM_REGS 19 +#define NUM_GEN_REGS 16 +#define NUM_CPU_REGS 3 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ +#define REGISTER_NAMES { \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", \ + "sp", "ps", "pc", \ +} + +/* 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 R1_REGNUM 1 /* Gr1 => return address of caller */ +#define R4_REGNUM 4 /* Gr4 => register save area */ +#define R5_REGNUM 5 /* Gr5 => register save area */ +#define R6_REGNUM 6 /* Gr6 => register save area */ +#define R7_REGNUM 7 /* Gr7 => register save area */ +#define B1_REGNUM 9 /* Br1 => start of this code routine */ +#define FP_REGNUM 10 /* Br2 == (sp) */ +#define AP_REGNUM 11 /* Br3 == (ap) */ +#define SP_REGNUM 16 /* A copy of Br2 saved in trap */ +#define PS_REGNUM 17 /* Contains processor status */ +#define PC_REGNUM 18 /* Contains program counter */ + +/* 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) { \ + addr = blockend + regno * 4; \ + if (regno == PC_REGNUM) addr = blockend - 8 * 4; \ + if (regno == PS_REGNUM) addr = blockend - 7 * 4; \ + if (regno == SP_REGNUM) addr = blockend - 6 * 4; \ +} + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_GEN_REGS*4 + NUM_CPU_REGS*4) + +/* Index within `registers' of the first byte of the space for + register N. */ +#define REGISTER_BYTE(N) ((N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the PN, all normal 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 PN, all regs are 4 bytes. */ +#define REGISTER_VIRTUAL_SIZE(N) (4) + +/* Largest value REGISTER_RAW_SIZE can have. */ +#define MAX_REGISTER_RAW_SIZE (4) + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ +#define MAX_REGISTER_VIRTUAL_SIZE (4) + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ +#define REGISTER_CONVERTIBLE(N) (0) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ + bcopy ((FROM), (TO), REGISTER_RAW_SIZE(REGNUM)); + +/* 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), REGISTER_VIRTUAL_SIZE(REGNUM)); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ +#define REGISTER_VIRTUAL_TYPE(N) (builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. + + On this machine this is a no-op, because gcc isn't used on it + yet. So this calling convention is not used. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) + +/* Extract from an arrary REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#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 NPL, the frame's norminal address is Br2 and the + previous routines frame is up the stack X bytes, where X is the + value stored in the code function header xA(Br1). */ +#define FRAME_CHAIN(thisframe) (findframe(thisframe)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && chain != (thisframe)->frame) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) \ + (chain) + +/* Define other aspects of the stack frame on NPL. */ +#define FRAME_SAVED_PC(frame) \ + (read_memory_integer ((frame)->frame + 8, 4)) + +#define FRAME_ARGS_ADDRESS(fi) \ + ((fi)->next_frame ? \ + read_memory_integer ((fi)->frame + 12, 4) : \ + read_register (AP_REGNUM)) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame + 80) + +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can check the stab info to see how + many arg we have. No info in stack will tell us */ +#define FRAME_NUM_ARGS(val,fi) (val = findarg(fi)) + +/* Return number of bytes at start of arglist that are not really args. */ +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[R4_REGNUM] = (frame_info)->frame + 0x30; \ + (frame_saved_regs).regs[R5_REGNUM] = (frame_info)->frame + 0x34; \ + (frame_saved_regs).regs[R6_REGNUM] = (frame_info)->frame + 0x38; \ + (frame_saved_regs).regs[R7_REGNUM] = (frame_info)->frame + 0x3C; \ +} + +/* 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; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, + restoring all 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; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } + +/* This sequence of words is the instructions: + halt + halt + halt + halt + suabr b2, # + lwbr b6, #con + stw r1, 8(b2) - save caller address, do we care? + lw r2, 60(b2) - arg1 + labr b3, 50(b2) + std r4, 30(b2) - save r4-r7 + std r6, 38(b2) + lwbr b1, # - load function call address + brlnk r1, 8(b1) - call function + halt + halt + ld r4, 30(b2) - restore r4-r7 + ld r6, 38(b2) + + Setup our stack frame, load argumemts, call and then restore registers. +*/ + +#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, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } diff --git a/gdb/tm-pyr.h b/gdb/tm-pyr.h new file mode 100644 index 00000000000..e37f8f5182f --- /dev/null +++ b/gdb/tm-pyr.h @@ -0,0 +1,530 @@ +/* Definitions to make GDB run on a Pyramidax under OSx 4.0 (4.2bsd). + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* Traditional Unix virtual address spaces have thre regions: text, + data and stack. The text, initialised data, and uninitialised data + are represented in separate segments of the a.out file. + When a process dumps core, the data and stack regions are written + to a core file. This gives a debugger enough information to + reconstruct (and debug) the virtual address space at the time of + the coredump. + Pyramids have an distinct fourth region of the virtual address + space, in which the contents of the windowed registers are stacked + in fixed-size frames. Pyramid refer to this region as the control + stack. Each call (or trap) automatically allocates a new register + frame; each return deallocates the current frame and restores the + windowed registers to their values before the call. + + When dumping core, the control stack is written to a core files as + a third segment. The core-handling functions need to know to deal + with it. */ +/* Tell core.c there is an extra segment. */ +#define REG_STACK_SEGMENT + +/* Floating point is IEEE compatible on most Pyramid hardware + (Older processors do not have IEEE NaNs). */ +#define IEEE_FLOAT + +/* 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. */ + +/* FIXME -- do we want to skip insns to allocate the local frame? + If so, what do they look like? + This is becoming harder, since tege@sics.SE wants to change + gcc to not output a prologue when no frame is needed. */ +#define SKIP_PROLOGUE(pc) do {} while (0) + + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) FRAME_SAVED_PC(frame) + +/* Address of end of stack space. */ +/* This seems to be right for the 90x comp.vuw.ac.nz. + The correct value at any site may be a function of the configured + maximum control stack depth. If so, I don't know where the + control-stack depth is configured, so I can't #include it here. */ +#define STACK_END_ADDR (0xc00cc000) + +/* Register window stack (Control stack) stack definitions + - Address of beginning of control stack. + - size of control stack frame + (Note that since crts0 is usually the first function called, + main()'s control stack is one frame (0x80 bytes) beyond this value. */ + +#define CONTROL_STACK_ADDR (0xc00cd000) + +/* Bytes in a register window -- 16 parameter regs, 16 local regs + for each call, is 32 regs * 4 bytes */ + +#define CONTROL_STACK_FRAME_SIZE (32*4) + +/* FIXME. On a pyr, Data Stack grows downward; control stack goes upwards. + Which direction should we use for INNER_THAN, PC_INNER_THAN ?? */ + +#define INNER_THAN < +#define PC_INNER_THAN > + +/* Stack has strict alignment. */ + +#define STACK_ALIGN(ADDR) (((ADDR)+3)&-4) + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xf0, 00, 00, 00} + +/* 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. + On a pyr, this is either "ret" or "retd". + It would be friendly to check that any "retd" always had an + argument of 0, since anything else is invalid. */ + +#define ABOUT_TO_RETURN(pc) \ +(((read_memory_integer (pc, 2) & 0x3ff0) == 0x3090) || \ + ((read_memory_integer (pc, 2) & 0x0ff0) == 0x00a0)) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the Vax. */ +/* FIXME -- this is ok for a vax, bad for big-endian ieee format. + I would use the definition for a Sun; but it is no better! */ + +#define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000) + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ +/* pyramids have 64, plus one for the PSW; plus perhaps one more for the + kernel stack pointer (ksp) and control-stack pointer (CSP) */ + +#define NUM_REGS 67 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ +{"gr0", "gr1", "gr2", "gr3", "gr4", "gr5", "gr6", "gr7", \ + "gr8", "gr9", "gr10", "gr11", "logpsw", "cfp", "sp", "pc", \ + "pr0", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", \ + "pr8", "pr9", "pr10", "pr11", "pr12", "pr13", "pr14", "pr15", \ + "lr0", "lr1", "lr2", "lr3", "lr4", "lr5", "lr6", "lr7", \ + "lr8", "lr9", "lr10", "lr11", "lr12", "lr13", "lr14", "lr15", \ + "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7", \ + "tr8", "tr9", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15", \ + "psw", "ksp", "csp"} + +/* 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. */ + +/* pseudo-registers: */ +#define PS_REGNUM 64 /* Contains processor status */ +#define PSW_REGNUM 64 /* Contains current psw, whatever it is.*/ +#define CSP_REGNUM 65 /* address of this control stack frame*/ +#define KSP_REGNUM 66 /* Contains process's Kernel Stack Pointer */ + +#define CFP_REGNUM 13 /* Current data-stack frame ptr */ +#define TR0_REGNUM 48 /* After function call, contains + function result */ + +/* Registers interesting to the machine-independent part of gdb*/ + +#define FP_REGNUM CSP_REGNUM /* Contains address of executing (control) + stack frame */ +#define SP_REGNUM 14 /* Contains address of top of stack -??*/ +#define PC_REGNUM 15 /* Contains program counter */ + +/* Define DO_REGISTERS_INFO() to do machine-specific formatting + of register dumps. */ + +#define DO_REGISTERS_INFO(_regnum) pyr_do_registers_info(_regnum) + +/* need this so we can find the global registers: they never get saved. */ +extern unsigned int global_reg_offset; +extern unsigned int last_frame_offset; + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_REGS*4) + +/* the Pyramid 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) >= 16 && (regnum) < 64) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the Pyramid, 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 Pyramid, all regs are 4 bytes. */ + +#define REGISTER_VIRTUAL_SIZE(N) 4 + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) 0 + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ + bcopy ((FROM), (TO), 4); + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ + bcopy ((FROM), (TO), 4); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) builtin_type_int + +/* FIXME: It seems impossible for both EXTRACT_RETURN_VALUE and + STORE_RETURN_VALUE to be correct. */ + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +/****FIXME****/ +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { write_register (TR0_REGNUM, (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. */ + +/* Note that on a register-windowing machine (eg, Pyr, SPARC), this is + where the value is found after the function call -- ie, it should + correspond to GNU CC's FUNCTION_VALUE rather than FUNCTION_OUTGOING_VALUE.*/ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (((int *)(REGBUF))+TR0_REGNUM, VALBUF, TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ +/* on pyrs, values are returned in */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (REGISTER_BYTE(TR0_REGNUM), 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). */ +/* FIXME */ +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ + ( ((int *)(REGBUF)) [TR0_REGNUM]) + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +#define EXTRA_FRAME_INFO \ + FRAME_ADDR bottom; \ + CORE_ADDR frame_cfp; \ + CORE_ADDR frame_window_addr; + +#define INIT_EXTRA_FRAME_INFO(fci) \ +do { \ + (fci)->frame_window_addr = (fci)->frame; \ + (fci)->bottom = \ + ((fci)->next ? \ + ((fci)->frame == (fci)->next_frame ? \ + (fci)->next->bottom : (fci)->next->frame) : \ + read_register (SP_REGNUM)); \ + (fci)->frame_cfp = \ + read_register (CFP_REGNUM); \ + /***fprintf (stderr, \ + "[[creating new frame for %0x,pc=%0x,csp=%0x]]\n", \ + (fci)->frame, (fci)->pc,(fci)->frame_cfp);*/ \ +} while (0); + +/* 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 pyr, the frame's nominal address is the address + of parameter register 0. The previous frame is found 32 words up. */ + +#define FRAME_CHAIN(thisframe) \ + ( (thisframe) -> frame - CONTROL_STACK_FRAME_SIZE) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + + /*((thisframe) >= CONTROL_STACK_ADDR))*/ + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. + + I do not understand what this means on a Pyramid, where functions + *always* have a control-stack frame, but may or may not have a + frame on the data stack. Since GBD uses the value of the + control stack pointer as its "address" of a frame, FRAMELESS + is always 1, so does not need to be defined. */ + + +/* Where is the PC for a specific frame */ + +#define FRAME_SAVED_PC(fi) \ + ((CORE_ADDR) (read_memory_integer ( (fi) -> frame + 60, 4))) + +/* There may be bugs in FRAME_ARGS_ADDRESS and FRAME_LOCALS_ADDRESS; + or there may be bugs in accessing the registers that break + their definitions. + Having the macros expand into functions makes them easier to debug. + When the bug is finally located, the inline macro defintions can + be un-#if 0ed, and frame_args_addr and frame_locals_address can + be deleted from pyr-dep.c */ + +/* If the argument is on the stack, it will be here. */ +#define FRAME_ARGS_ADDRESS(fi) \ + frame_args_addr(fi) + +#define FRAME_LOCALS_ADDRESS(fi) \ + frame_locals_address(fi) + +/* The following definitions doesn't seem to work. + I don't understand why. */ +#if 0 +#define FRAME_ARGS_ADDRESS(fi) \ + /*(FRAME_FP(fi) + (13*4))*/ (read_register (CFP_REGNUM)) + +#define FRAME_LOCALS_ADDRESS(fi) \ + ((fi)->frame +(16*4)) + +#endif /* 0 */ + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#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 0 + +/* 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 pyrs, frames of window registers are stored contiguously on a + separate stack. All window registers are always stored. + The pc and psw (gr15 and gr14) are also always saved: the call + insn saves them in pr15 and pr14 of the new frame (tr15,tr14 of the + old frame). + The data-stack frame pointer (CFP) is only saved in functions which + allocate a (data)stack frame (with "adsf"). We detect them by + looking at the first insn of the procedure. + + Other non-window registers (gr0-gr11) are never saved. Pyramid's C + compiler and gcc currently ignore them, so it's not an issue. */ + +#define FRAME_FIND_SAVED_REGS(fi_p, frame_saved_regs) \ +{ register int regnum; \ + register CORE_ADDR pc; \ + register CORE_ADDR fn_start_pc; \ + register int first_insn; \ + register CORE_ADDR prev_cf_addr; \ + register int window_ptr; \ + FRAME fid = FRAME_INFO_ID (fi_p); \ + if (!fid) fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS"); \ + bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \ + \ + window_ptr = prev_cf_addr = FRAME_FP(fi_p); \ + \ + for (regnum = 16 ; regnum < 64; regnum++,window_ptr+=4) \ + { \ + (frame_saved_regs).regs[regnum] = window_ptr; \ + } \ + \ + /* In each window, psw, and pc are "saved" in tr14,tr15. */ \ + /*** psw is sometimes saved in gr12 (so sez ) */ \ + (frame_saved_regs).regs[PS_REGNUM] = FRAME_FP(fi_p) + (14*4); \ + \ +/*(frame_saved_regs).regs[PC_REGNUM] = (frame_saved_regs).regs[31];*/ \ + (frame_saved_regs).regs[PC_REGNUM] = FRAME_FP(fi_p) + ((15+32)*4); \ + \ + /* Functions that allocate a frame save sp *where*? */ \ +/*first_insn = read_memory_integer (get_pc_function_start ((fi_p)->pc),4); */ \ + \ + fn_start_pc = (get_pc_function_start ((fi_p)->pc)); \ + first_insn = read_memory_integer(fn_start_pc, 4); \ + \ + if (0x08 == ((first_insn >> 20) &0x0ff)) { \ + /* NB: because WINDOW_REGISTER_P(cfp) is false, a saved cfp \ + in this frame is only visible in this frame's callers. \ + That means the cfp we mark saved is my caller's cfp, ie pr13. \ + I don't understand why we don't have to do that for pc, too. */ \ + \ + (frame_saved_regs).regs[CFP_REGNUM] = FRAME_FP(fi_p)+(13*4); \ + \ + (frame_saved_regs).regs[SP_REGNUM] = \ + read_memory_integer (FRAME_FP(fi_p)+((13+32)*4),4); \ + } \ + \ +/* \ + *(frame_saved_regs).regs[CFP_REGNUM] = (frame_saved_regs).regs[61]; \ + * (frame_saved_regs).regs[SP_REGNUM] = \ + * read_memory_integer (FRAME_FP(fi_p)+((13+32)*4),4); \ + */ \ + \ + (frame_saved_regs).regs[CSP_REGNUM] = prev_cf_addr; \ +} + +/* Things needed for making the inferior call functions. */ +#if 0 +/* These are all lies. These macro definitions are appropriate for a + SPARC. On a pyramid, pushing a dummy frame will + surely involve writing the control stack pointer, + then saving the pc. This requires a privileged instruction. + Maybe one day Pyramid can be persuaded to add a syscall to do this. + Until then, we are out of luck. */ + +/* 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; \ + sp = push_word (sp, 0); /* arglist */ \ + for (regnum = 11; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ +/* sp = push_word (sp, read_register (AP_REGNUM));*/ \ + sp = push_word (sp, (read_register (PS_REGNUM) & 0xffef) \ + + 0x2fff0000); \ + sp = push_word (sp, 0); \ + write_register (SP_REGNUM, sp); \ + write_register (FP_REGNUM, sp); \ +/* write_register (AP_REGNUM, sp + 17 * sizeof (int));*/ } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + register int regmask = read_memory_integer (fp + 4, 4); \ + write_register (PS_REGNUM, \ + (regmask & 0xffff) \ + | (read_register (PS_REGNUM) & 0xffff0000)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 16, 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp + 12, 4)); \ +/* write_register (AP_REGNUM, read_memory_integer (fp + 8, 4));*/ \ + fp += 16; \ + for (regnum = 0; regnum < 12; regnum++) \ + if (regmask & (0x10000 << regnum)) \ + write_register (regnum, read_memory_integer (fp += 4, 4)); \ + fp = fp + 4 + ((regmask >> 30) & 3); \ + if (regmask & 0x20000000) \ + { regnum = read_memory_integer (fp, 4); \ + fp += (regnum + 1) * 4; } \ + write_register (SP_REGNUM, fp); \ + set_current_frame (read_register (FP_REGNUM)); } + +/* This sequence of words is the instructions + calls #69, @#32323232 + bpt + Note this is 8 bytes. */ + +#define CALL_DUMMY {0x329f69fb, 0x03323232} + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ *((char *) dummyname + 1) = nargs; \ + *(int *)((char *) dummyname + 3) = fun; } +#endif /* 0 */ + +#define POP_FRAME \ + { error ("The return command is not supported on this machine."); } diff --git a/gdb/tm-sparc.h b/gdb/tm-sparc.h new file mode 100644 index 00000000000..b3316da1bfd --- /dev/null +++ b/gdb/tm-sparc.h @@ -0,0 +1,586 @@ +/* Parameters for target machine of Sun 4, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* Floating point is IEEE compatible. */ +#define IEEE_FLOAT + +/* 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 + +/* When passing a structure to a function, Sun cc passes the address + in a register, not the structure itself. It (under SunOS4) creates + two symbols, so we get a LOC_ARG saying the address is on the stack + (a lie, and a serious one since we don't know which register to + use), and a LOC_REGISTER saying that the struct is in a register + (sort of a lie, but fixable with REG_STRUCT_HAS_ADDR). + + This still doesn't work if the argument is not one passed in a + register (i.e. it's the 7th or later argument). */ +#define REG_STRUCT_HAS_ADDR(gcc_p) (!(gcc_p)) +#define STRUCT_ARG_SYM_GARBAGE(gcc_p) (!(gcc_p)) + +/* If Pcc says that a parameter is a short, it's a short. This is + because the parameter does get passed in in a register as an int, + but pcc puts it onto the stack frame as a short (not nailing + whatever else might be there. I'm not sure that I consider this + swift. Sigh.) + + No, don't do this. The problem here is that pcc says that the + argument is in the upper half of the word reserved on the stack, + but puts it in the lower half. */ +/* #define BELIEVE_PCC_PROMOTION 1 */ +/* OK, I've added code to dbxread.c to deal with this case. */ +#define BELIEVE_PCC_PROMOTION_TYPE + +/* 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); } +extern CORE_ADDR skip_prologue (); + +/* 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 the end of stack space. We get this from the system + include files. */ +#include +#include +#define STACK_END_ADDR USRSTACK + +#define INNER_THAN < + +/* Stack has strict alignment. */ + +#define STACK_ALIGN(ADDR) (((ADDR)+7)&-8) + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x91, 0xd0, 0x20, 0x01} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#define DECR_PC_AFTER_BREAK 0 + +/* Nonzero if instruction at PC is a return instruction. */ +/* For SPARC, this is either a "jmpl %o7+8,%g0" or "jmpl %i7+8,%g0". + + Note: this does not work for functions returning structures under SunOS. */ +#define ABOUT_TO_RETURN(pc) \ + ((read_memory_integer (pc, 4)|0x00040000) == 0x81c7e008) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 72 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ +{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", \ + "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", \ + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", \ + "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", \ + \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \ + \ + "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" }; + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define G0_REGNUM 0 /* %g0 */ +#define G1_REGNUM 1 /* %g1 */ +#define O0_REGNUM 8 /* %o0 */ +#define SP_REGNUM 14 /* Contains address of top of stack, \ + which is also the bottom of the frame. */ +#define RP_REGNUM 15 /* Contains return address value, *before* \ + any windows get switched. */ +#define O7_REGNUM 15 /* Last local reg not saved on stack frame */ +#define L0_REGNUM 16 /* First local reg that's saved on stack frame + rather than in machine registers */ +#define I0_REGNUM 24 /* %i0 */ +#define FP_REGNUM 30 /* Contains address of executing stack frame */ +#define I7_REGNUM 31 /* Last local reg saved on stack frame */ +#define FP0_REGNUM 32 /* Floating point register 0 */ +#define Y_REGNUM 64 /* Temp register for multiplication, etc. */ +#define PS_REGNUM 65 /* Contains processor status */ +#define WIM_REGNUM 66 /* Window Invalid Mask (not really supported) */ +#define TBR_REGNUM 67 /* Trap Base Register (not really supported) */ +#define PC_REGNUM 68 /* Contains program counter */ +#define NPC_REGNUM 69 /* Contains next PC */ +#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) + +/* Writing to %g0 is a noop (not an error or exception or anything like + that, however). */ + +#define CANNOT_STORE_REGISTER(regno) ((regno) == G0_REGNUM) + +/* 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) \ + { target_write_memory ((SP)+(16*4), (char *)&(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) \ + { \ + if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) \ + { \ + bcopy (((int *)(REGBUF))+FP0_REGNUM, \ + (VALBUF), TYPE_LENGTH(TYPE)); \ + } \ + else \ + 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) \ + { \ + if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) \ + /* Floating-point values are returned in the register pair */ \ + /* formed by %f0 and %f1 (doubles are, anyway). */ \ + write_register_bytes (REGISTER_BYTE (FP0_REGNUM), (VALBUF), \ + TYPE_LENGTH (TYPE)); \ + else \ + /* Other values are returned in register %o0. */ \ + write_register_bytes (REGISTER_BYTE (O0_REGNUM), (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)) + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* I don't know whether this will work for cross-debugging, even if you + do get the right reg.h. */ +#include + +#define GET_RWINDOW_REG(FRAME, REG) \ + (read_memory_integer ((CORE_ADDR)&((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]) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +/* Where is the PC for a specific frame */ + +#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME) +CORE_ADDR frame_saved_pc (); + +/* 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. + The actual code is in sparc-tdep.c so we can debug it sanely. */ + +#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \ + sparc_frame_find_saved_regs ((fi), &(frame_saved_regs)) +extern void sparc_frame_find_saved_regs (); + +/* 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. */ + +#define PUSH_DUMMY_FRAME sparc_push_dummy_frame () +#define POP_FRAME sparc_pop_frame () + +void sparc_push_dummy_frame (), sparc_pop_frame (); +/* 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. + + For structs and unions, if the function was compiled with Sun cc, + it expects 'unimp' after the call. But gcc doesn't use that + (twisted) convention. So leave a nop there for gcc (FIX_CALL_DUMMY + can assume it is operating on a pristine CALL_DUMMY, not one that + has already been customized for a different function). */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ \ + *(int *)((char *) dummyname+168) = (0x40000000|((fun-(pc+168))>>2)); \ + if (!gcc_p \ + && (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 +extern void single_step (); + +/* 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 + +/* To print every pair of float registers as a double, we use this hook. */ + +#define PRINT_REGISTER_HOOK(regno) \ + if (((regno) >= FP0_REGNUM) \ + && ((regno) < FP0_REGNUM + 32) \ + && (0 == (regno & 1))) { \ + char doublereg[8]; /* two float regs */ \ + if (!read_relative_register_raw_bytes (i , doublereg ) \ + && !read_relative_register_raw_bytes (i+1, doublereg+4)) { \ + printf("\t"); \ + print_floating (doublereg, builtin_type_double, stdout); \ + } \ + } + diff --git a/gdb/tm-sun2.h b/gdb/tm-sun2.h new file mode 100644 index 00000000000..6d294623ce9 --- /dev/null +++ b/gdb/tm-sun2.h @@ -0,0 +1,107 @@ +/* Parameters for execution on a Sun, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "m-68k.h" + +/* 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 + +/* Address of the end of stack space. We get this from the system + include files. */ +#include +#include +#define STACK_END_ADDR USRSTACK + +/* 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; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } + +/* This sequence of words is the instructions + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @#32323232 + addl #69696969,sp + bpt + nop +Note this is 24 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 24 + +#define CALL_DUMMY_START_OFFSET 8 + +/* 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, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 16) = nargs * 4; \ + *(int *)((char *) dummyname + 10) = fun; } diff --git a/gdb/tm-sun2os4.h b/gdb/tm-sun2os4.h new file mode 100644 index 00000000000..bb1a0611969 --- /dev/null +++ b/gdb/tm-sun2os4.h @@ -0,0 +1,20 @@ +/* Copyright (C) 1990, Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-sun2.h" +#include "tm-sunos.h" diff --git a/gdb/tm-sun3.h b/gdb/tm-sun3.h new file mode 100644 index 00000000000..4519d6ac774 --- /dev/null +++ b/gdb/tm-sun3.h @@ -0,0 +1,120 @@ +/* Parameters for execution on a Sun, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HAVE_68881 + +#include "tm-68k.h" + +/* 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 + +/* Address of the end of stack space. We get this from the system + include files. */ +#include +#include +#define STACK_END_ADDR USRSTACK + +/* 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, args, type, gcc_p) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = fun; } diff --git a/gdb/tm-sun386.h b/gdb/tm-sun386.h new file mode 100644 index 00000000000..60c8986bb3b --- /dev/null +++ b/gdb/tm-sun386.h @@ -0,0 +1,305 @@ +/* Parameters for execution on a Sun 386i, for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +#ifndef sun386 +#define sun386 +#endif +#define SUNOS4 +#define USE_MACHINE_REG_H + +/* Perhaps some day this will work even without the following #define */ +#define COFF_ENCAPSULATE + +#ifdef COFF_ENCAPSULATE +#define NAMES_HAVE_UNDERSCORE +/* Avoid conflicts between "a.out.gnu.h" and */ +#define _EXEC_ +#endif + +#define BROKEN_LARGE_ALLOCA + +/* sun386 ptrace seems unable to change the frame pointer */ +#define PTRACE_FP_BUG + +/* 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(frompc) {(frompc) = i386_skip_prologue((frompc));} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + (read_memory_integer (read_register (SP_REGNUM), 4)) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xfc000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xcc} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#define DECR_PC_AFTER_BREAK 1 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc3) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the 386. */ + +#define INVALID_FLOAT(p, len) (0) + +/* 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 35 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* the order of the first 8 registers must match the compiler's + * numbering scheme (which is the same as the 386 scheme) + * also, this table must match regmap in i386-pinsn.c. + */ +#define REGISTER_NAMES { "gs", "fs", "es", "ds", \ + "edi", "esi", "ebp", "esp", \ + "ebx", "edx", "ecx", "eax", \ + "retaddr", "trapnum", "errcode", "ip", \ + "cs", "ps", "sp", "ss", \ + "fst0", "fst1", "fst2", "fst3", \ + "fst4", "fst5", "fst6", "fst7", \ + "fctrl", "fstat", "ftag", "fip", \ + "fcs", "fopoff", "fopsel" \ + } + +/* 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 6 /* Contains address of executing stack frame */ +#define SP_REGNUM 18 /* Contains address of top of stack */ +#define PS_REGNUM 17 /* Contains processor status */ +#define PC_REGNUM 15 /* Contains program counter */ +#define FP0_REGNUM 20 /* Floating point register 0 */ +#define FPC_REGNUM 28 /* 80387 control register */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (20*4+8*10+7*4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 160 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 10) + 80 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)((N) - FP0_REGNUM)) < 8 ? 10 : 4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)((N) - FP0_REGNUM)) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 10 + +/* 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) \ + i387_to_double ((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) \ + double_to_i387 ((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) \ + { (SP) -= sizeof (ADDR); \ + write_memory ((SP), &(ADDR), sizeof (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (REGBUF + REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 11), 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 (REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 11), VALBUF, TYPE_LENGTH (TYPE)) + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ +{ (FRAMELESS) = frameless_look_for_prologue (FI); } + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) (numargs) = i386_frame_num_args(fi) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); } + + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME { i386_push_dummy_frame (); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME { i386_pop_frame (); } + +/* this is + * call 11223344 (32 bit relative) + * int3 + */ + +#define CALL_DUMMY { 0x223344e8, 0xcc11 } + +#define CALL_DUMMY_LENGTH 8 + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ \ + *(int *)((char *)(dummyname) + 1) = (int)(fun) - (pc) - 5; \ +} diff --git a/gdb/tm-sun3os4.h b/gdb/tm-sun3os4.h new file mode 100644 index 00000000000..5d89d1523c1 --- /dev/null +++ b/gdb/tm-sun3os4.h @@ -0,0 +1,20 @@ +/* Copyright (C) 1990, Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-sun3.h" +#include "tm-sunos.h" diff --git a/gdb/tm-sun4os4.h b/gdb/tm-sun4os4.h new file mode 100644 index 00000000000..971bb4fbd7a --- /dev/null +++ b/gdb/tm-sun4os4.h @@ -0,0 +1,24 @@ +/* Macro definitions for GDB for a Sun 4 running sunos 4. + Copyright (C) 1989, Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-sparc.h" +#include "tm-sunos.h" + +#undef STACK_END_ADDRESS +#define STACK_END_ADDRESS 0xf8000000 diff --git a/gdb/tm-sunos.h b/gdb/tm-sunos.h new file mode 100644 index 00000000000..f33e3520686 --- /dev/null +++ b/gdb/tm-sunos.h @@ -0,0 +1,26 @@ +/* Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This is for SunOS version 4, not for earlier versions. */ + +#define CLEAR_SOLIB clear_solib + +/* If we can't set a breakpoint, and it's in a shared library, just + disable it. */ +#define DISABLE_UNSETTABLE_BREAK(addr) solib_address(addr) +extern int solib_address (); /* solib.c */ diff --git a/gdb/tm-symmetry.h b/gdb/tm-symmetry.h new file mode 100644 index 00000000000..0030b61abb5 --- /dev/null +++ b/gdb/tm-symmetry.h @@ -0,0 +1,488 @@ +/* Definitions to make GDB run on a Sequent Symmetry under dynix 3.0, + with Weitek 1167 and i387 support. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Symmetry version by Jay Vosburgh (uunet!sequent!fubar) */ + +/* I don't know if this will work for cross-debugging, even if you do get + a copy of the right include file. */ +#include + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* 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. From m-i386.h */ + +#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + read_memory_integer(read_register(SP_REGNUM), 4) + +/* I don't know the real values for these. */ +#define TARGET_UPAGES UPAGES +#define TARGET_NBPG NBPG + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0x40000000 - (TARGET_UPAGES * TARGET_NBPG)) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xcc} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#define DECR_PC_AFTER_BREAK 0 + +/* Nonzero if instruction at PC is a return instruction. */ +/* For Symmetry, this is really the 'leave' instruction, which */ +/* is right before the ret */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc9) + +/* Return 1 if P points to an invalid floating point value. +*/ + +#define INVALID_FLOAT(p, len) (0) + +/* code for 80387 fpu. Functions are from i386-dep.c, copied into + * symm-dep.c. + */ +#define FLOAT_INFO { i386_float_info(); } + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ +#define NUM_REGS 49 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* Symmetry registers are in this weird order to match the register + numbers in the symbol table entries. If you change the order, + things will probably break mysteriously for no apparent reason. + Also note that the st(0)...st(7) 387 registers are represented as + st0...st7. */ + +#define REGISTER_NAMES { "eax", "edx", "ecx", "st0", "st1", \ + "ebx", "esi", "edi", "st2", "st3", \ + "st4", "st5", "st6", "st7", "esp", \ + "ebp", "eip", "eflags", "fp1", "fp2", \ + "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fp8", "fp9", "fp10", "fp11", "fp12", \ + "fp13", "fp14", "fp15", "fp16", "fp17", \ + "fp18", "fp19", "fp20", "fp21", "fp22", \ + "fp23", "fp24", "fp25", "fp26", "fp27", \ + "fp28", "fp29", "fp30", "fp31" } + +/* 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 FP1_REGNUM 18 /* first 1167 register */ +#define SP_REGNUM 14 /* Contains address of top of stack */ +#define FP_REGNUM 15 /* Contains address of executing stack frame */ +#define PC_REGNUM 16 /* Contains program counter */ +#define PS_REGNUM 17 /* Contains processor status */ + +/* The magic numbers below are offsets into u_ar0 in the user struct. + * They live in . Gdb calls this macro with blockend + * holding u.u_ar0 - KERNEL_U_ADDR. Only the registers listed are + * saved in the u area (along with a few others that aren't useful + * here. See ). + */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ struct user foo; /* needed for finding fpu regs */ \ +switch (regno) { \ + case 0: \ + addr = blockend + EAX * sizeof(int); break; \ + case 1: \ + addr = blockend + EDX * sizeof(int); break; \ + case 2: \ + addr = blockend + ECX * sizeof(int); break; \ + case 3: /* st(0) */ \ + addr = blockend - \ + ((int)&foo.u_fpusave.fpu_stack[0][0] - (int)&foo); \ + break; \ + case 4: /* st(1) */ \ + addr = blockend - \ + ((int) &foo.u_fpusave.fpu_stack[1][0] - (int)&foo); \ + break; \ + case 5: \ + addr = blockend + EBX * sizeof(int); break; \ + case 6: \ + addr = blockend + ESI * sizeof(int); break; \ + case 7: \ + addr = blockend + EDI * sizeof(int); break; \ + case 8: /* st(2) */ \ + addr = blockend - \ + ((int) &foo.u_fpusave.fpu_stack[2][0] - (int)&foo); \ + break; \ + case 9: /* st(3) */ \ + addr = blockend - \ + ((int) &foo.u_fpusave.fpu_stack[3][0] - (int)&foo); \ + break; \ + case 10: /* st(4) */ \ + addr = blockend - \ + ((int) &foo.u_fpusave.fpu_stack[4][0] - (int)&foo); \ + break; \ + case 11: /* st(5) */ \ + addr = blockend - \ + ((int) &foo.u_fpusave.fpu_stack[5][0] - (int)&foo); \ + break; \ + case 12: /* st(6) */ \ + addr = blockend - \ + ((int) &foo.u_fpusave.fpu_stack[6][0] - (int)&foo); \ + break; \ + case 13: /* st(7) */ \ + addr = blockend - \ + ((int) &foo.u_fpusave.fpu_stack[7][0] - (int)&foo); \ + break; \ + case 14: \ + addr = blockend + ESP * sizeof(int); break; \ + case 15: \ + addr = blockend + EBP * sizeof(int); break; \ + case 16: \ + addr = blockend + EIP * sizeof(int); break; \ + case 17: \ + addr = blockend + FLAGS * sizeof(int); break; \ + case 18: /* fp1 */ \ + case 19: /* fp2 */ \ + case 20: /* fp3 */ \ + case 21: /* fp4 */ \ + case 22: /* fp5 */ \ + case 23: /* fp6 */ \ + case 24: /* fp7 */ \ + case 25: /* fp8 */ \ + case 26: /* fp9 */ \ + case 27: /* fp10 */ \ + case 28: /* fp11 */ \ + case 29: /* fp12 */ \ + case 30: /* fp13 */ \ + case 31: /* fp14 */ \ + case 32: /* fp15 */ \ + case 33: /* fp16 */ \ + case 34: /* fp17 */ \ + case 35: /* fp18 */ \ + case 36: /* fp19 */ \ + case 37: /* fp20 */ \ + case 38: /* fp21 */ \ + case 39: /* fp22 */ \ + case 40: /* fp23 */ \ + case 41: /* fp24 */ \ + case 42: /* fp25 */ \ + case 43: /* fp26 */ \ + case 44: /* fp27 */ \ + case 45: /* fp28 */ \ + case 46: /* fp29 */ \ + case 47: /* fp30 */ \ + case 48: /* fp31 */ \ + addr = blockend - \ + ((int) &foo.u_fpasave.fpa_regs[(regno)-18] - (int)&foo); \ + } \ +} + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +/* 10 i386 registers, 8 i387 registers, and 31 Weitek 1167 registers */ +#define REGISTER_BYTES ((10 * 4) + (8 * 10) + (31 * 4)) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ +((N < 3) ? (N * 4) : \ +(N < 5) ? (((N - 2) * 10) + 2) : \ +(N < 8) ? (((N - 5) * 4) + 32) : \ +(N < 14) ? (((N - 8) * 10) + 44) : \ + (((N - 14) * 4) + 104)) + +/* Number of bytes of storage in the actual machine representation + * for register N. All registers are 4 bytes, except 387 st(0) - st(7), + * which are 80 bits each. + */ + +#define REGISTER_RAW_SIZE(N) \ +((N < 3) ? 4 : \ +(N < 5) ? 10 : \ +(N < 8) ? 4 : \ +(N < 14) ? 10 : \ + 4) + +/* Number of bytes of storage in the program's representation + for register N. On the vax, all regs are 4 bytes. */ + +#define REGISTER_VIRTUAL_SIZE(N) 4 + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 10 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) \ +((N < 3) ? 0 : \ +(N < 5) ? 1 : \ +(N < 8) ? 0 : \ +(N < 14) ? 1 : \ + 0) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +((REGNUM < 3) ? bcopy ((FROM), (TO), 4) : \ +(REGNUM < 5) ? i387_to_double((FROM), (TO)) : \ +(REGNUM < 8) ? bcopy ((FROM), (TO), 4) : \ +(REGNUM < 14) ? i387_to_double((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) \ +((REGNUM < 3) ? bcopy ((FROM), (TO), 4) : \ +(REGNUM < 5) ? double_to_i387((FROM), (TO)) : \ +(REGNUM < 8) ? bcopy ((FROM), (TO), 4) : \ +(REGNUM < 14) ? double_to_i387((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 < 3) ? builtin_type_int : \ +(N < 5) ? builtin_type_double : \ +(N < 8) ? builtin_type_int : \ +(N < 14) ? builtin_type_double : \ + builtin_type_int) + +/* from m-i386.h */ +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { (SP) -= sizeof (ADDR); \ + write_memory ((SP), &(ADDR), sizeof (ADDR)); \ + write_register(0, (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) \ + symmetry_extract_return_value(TYPE, REGBUF, VALBUF) + +/* 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. */ + +/* On Symmetry, %ebp points to caller's %ebp, and the return address + is right on top of that. +*/ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +#define FRAME_SAVED_PC(fi) (read_memory_integer((fi)->frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. + + The weirdness in the "addl $imm8" case is due to gcc sometimes + issuing "addl $-int" after function call returns; this would + produce ridiculously huge arg counts. */ + +#define FRAME_NUM_ARGS(numargs, fi) \ +{ \ + int op = read_memory_integer(FRAME_SAVED_PC((fi)), 4); \ + int narg; \ + if ((op & 0xff) == 0x59) /* 0x59 'popl %ecx' */ \ + { \ + numargs = 1; \ + } \ + else if ((op & 0xffff) == 0xc483) /* 0xc483 'addl $imm8' */ \ + { \ + narg = ((op >> 16) & 0xff); \ + numargs = (narg >= 128) ? -1 : narg / 4; \ + } \ + else if ((op & 0xffff) == 0xc481) /* 0xc481 'addl $imm32' */ \ + { \ + narg = read_memory_integer(FRAME_SAVED_PC((fi))+2,4); \ + numargs = (narg < 0) ? -1 : narg / 4; \ + } \ + else \ + { \ + numargs = -1; \ + } \ +} + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); } + + +/* Things needed for making the inferior call functions. */ + +#define PUSH_DUMMY_FRAME \ +{ CORE_ADDR sp = read_register (SP_REGNUM); \ + int regnum; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = 0; regnum < NUM_REGS; regnum++) \ + sp = push_word (sp, read_register (regnum)); \ + write_register (SP_REGNUM, sp); \ +} + +#define POP_FRAME \ +{ \ + FRAME frame = get_current_frame (); \ + CORE_ADDR fp; \ + int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = 0; regnum < NUM_REGS; regnum++) { \ + CORE_ADDR adr; \ + adr = fsr.regs[regnum]; \ + if (adr) \ + write_register (regnum, read_memory_integer (adr, 4)); \ + } \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame ( create_new_frame (read_register (FP_REGNUM), \ + read_pc ())); \ +} + +/* from i386-dep.c, worked better than my original... */ +/* This sequence of words is the instructions + * call (32-bit offset) + * int 3 + * This is 6 bytes. + */ + +#define CALL_DUMMY { 0x223344e8, 0xcc11 } + +#define CALL_DUMMY_LENGTH 8 + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ \ + int from, to, delta, loc; \ + loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \ + from = loc + 5; \ + to = (int)(fun); \ + delta = to - from; \ + *(int *)((char *)(dummyname) + 1) = delta; \ +} diff --git a/gdb/tm-umax.h b/gdb/tm-umax.h new file mode 100644 index 00000000000..492906589a0 --- /dev/null +++ b/gdb/tm-umax.h @@ -0,0 +1,405 @@ +/* Definitions to make GDB run on an encore under umax 4.2 + Copyright (C) 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* 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 + +/* Exec files and symbol tables are in COFF format */ + +#define COFF_FORMAT + +/* Need to get function ends by adding this to epilogue address from .bf + record, not using x_fsize field. */ +#define FUNCTION_EPILOGUE_SIZE 4 + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) \ +{ register unsigned char op = read_memory_integer (pc, 1); \ + if (op == 0x82) { op = read_memory_integer (pc+2,1); \ + if ((op & 0x80) == 0) pc += 3; \ + else if ((op & 0xc0) == 0x80) pc += 4; \ + else pc += 6; \ + } \ +} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + read_memory_integer (read_register (SP_REGNUM), 4) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0xfffff000) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xf2} + +/* 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, 1) == 0x12) + +#ifndef NaN +#include +#endif NaN + +/* Return 1 if P points to an invalid floating point value. */ +/* Surely wrong for cross-debugging. */ +#define INVALID_FLOAT(p, s) \ + ((s == sizeof (float))? \ + NaF (*(float *) p) : \ + NaD (*(double *) p)) + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 25 + +#define NUM_GENERAL_REGS 8 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "sp", "fp", "pc", "ps", \ + "fsr", \ + "l0", "l1", "l2", "l3", "xx", \ + } + +/* 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 FP0_REGNUM 8 /* Floating point register 0 */ +#define SP_REGNUM 16 /* Contains address of top of stack */ +#define AP_REGNUM FP_REGNUM +#define FP_REGNUM 17 /* Contains address of executing stack frame */ +#define PC_REGNUM 18 /* Contains program counter */ +#define PS_REGNUM 19 /* Contains processor status */ +#define FPS_REGNUM 20 /* Floating point status register */ +#define LP0_REGNUM 21 /* Double register 0 (same as FP0) */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES ((NUM_REGS - 4) * sizeof (int) + 4 * sizeof (double)) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N) >= LP0_REGNUM ? \ + LP0_REGNUM * 4 + ((N) - LP0_REGNUM) * 8 : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 32000, all regs are 4 bytes + except for the doubled floating registers. */ + +#define REGISTER_RAW_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 32000, all regs are 4 bytes + except for the doubled floating registers. */ + +#define REGISTER_VIRTUAL_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 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), REGISTER_VIRTUAL_SIZE(REGNUM)); + +/* 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), REGISTER_VIRTUAL_SIZE(REGNUM)); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((N) < FP0_REGNUM) ? \ + builtin_type_int : \ + ((N) < FP0_REGNUM + 8) ? \ + builtin_type_float : \ + ((N) < LP0_REGNUM) ? \ + builtin_type_int : \ + builtin_type_double) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. + + On this machine this is a no-op, because gcc isn't used on it + yet. So this calling convention is not used. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (REGBUF+REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 0), 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 (REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 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 ns32000 series, the frame's nominal address is the FP + value, and at that address is saved previous FP value as a 4-byte word. */ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +/* Compute base of arguments. */ + +#define FRAME_ARGS_ADDRESS(fi) \ + ((ns32k_get_enter_addr ((fi)->pc) > 1) ? \ + ((fi)->frame) : (read_register (SP_REGNUM) - 4)) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Get the address of the enter opcode for this function, if it is active. + Returns positive address > 1 if pc is between enter/exit, + 1 if pc before enter or after exit, 0 otherwise. */ + +#ifndef CORE_ADDR +#include "defs.h" /* Make sure CORE_ADDR is defined. */ +#endif + +extern CORE_ADDR ns32k_get_enter_addr (); + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. + Encore's C compiler often reuses same area on stack for args, + so this will often not work properly. If the arg names + are known, it's likely most of them will be printed. */ + +#define FRAME_NUM_ARGS(numargs, fi) \ +{ CORE_ADDR pc; \ + CORE_ADDR enter_addr; \ + unsigned int insn; \ + unsigned int addr_mode; \ + int width; \ + \ + numargs = -1; \ + enter_addr = ns32k_get_enter_addr ((fi)->pc); \ + if (enter_addr > 0) \ + { \ + pc = (enter_addr == 1) ? \ + SAVED_PC_AFTER_CALL (fi) : \ + FRAME_SAVED_PC (fi); \ + insn = read_memory_integer (pc,2); \ + addr_mode = (insn >> 11) & 0x1f; \ + insn = insn & 0x7ff; \ + if ((insn & 0x7fc) == 0x57c && \ + addr_mode == 0x14) /* immediate */ \ + { \ + if (insn == 0x57c) /* adjspb */ \ + width = 1; \ + else if (insn == 0x57d) /* adjspw */ \ + width = 2; \ + else if (insn == 0x57f) /* adjspd */ \ + width = 4; \ + numargs = read_memory_integer (pc+2,width); \ + if (width > 1) \ + flip_bytes (&numargs, width); \ + numargs = - sign_extend (numargs, width*8) / 4;\ + } \ + } \ +} + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ \ + register int regmask, regnum; \ + int localcount; \ + register CORE_ADDR enter_addr; \ + register CORE_ADDR next_addr; \ + \ + bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \ + enter_addr = ns32k_get_enter_addr ((frame_info)->pc); \ + if (enter_addr > 1) \ + { \ + regmask = read_memory_integer (enter_addr+1, 1) & 0xff; \ + localcount = ns32k_localcount (enter_addr); \ + next_addr = (frame_info)->frame + localcount; \ + for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \ + (frame_saved_regs).regs[regnum] = (regmask & 1) ? \ + (next_addr -= 4) : 0; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 4;\ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4;\ + (frame_saved_regs).regs[FP_REGNUM] = \ + (read_memory_integer ((frame_info)->frame, 4));\ + } \ + else if (enter_addr == 1) \ + { \ + CORE_ADDR sp = read_register (SP_REGNUM); \ + (frame_saved_regs).regs[PC_REGNUM] = sp; \ + (frame_saved_regs).regs[SP_REGNUM] = sp + 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; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = 0; regnum < 8; regnum++) \ + sp = push_word (sp, read_register (regnum)); \ + write_register (SP_REGNUM, sp); \ +} + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = 0; regnum < 8; regnum++) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } + +/* This sequence of words is the instructions + enter 0xff,0 82 ff 00 + jsr @0x00010203 7f ae c0 01 02 03 + adjspd 0x69696969 7f a5 01 02 03 04 + bpt f2 + Note this is 16 bytes. */ + +#define CALL_DUMMY { 0x7f00ff82, 0x0201c0ae, 0x01a57f03, 0xf2040302 } + +#define CALL_DUMMY_START_OFFSET 3 +#define CALL_DUMMY_LENGTH 16 +#define CALL_DUMMY_ADDR 5 +#define CALL_DUMMY_NARGS 11 + +/* 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, args, type, gcc_p) \ +{ \ + int flipped; \ + flipped = fun | 0xc0000000; \ + flip_bytes (&flipped, 4); \ + *((int *) (((char *) dummyname)+CALL_DUMMY_ADDR)) = flipped; \ + flipped = - nargs * 4; \ + flip_bytes (&flipped, 4); \ + *((int *) (((char *) dummyname)+CALL_DUMMY_NARGS)) = flipped; \ +} diff --git a/gdb/tm-vax.h b/gdb/tm-vax.h new file mode 100644 index 00000000000..c7a91b49835 --- /dev/null +++ b/gdb/tm-vax.h @@ -0,0 +1,377 @@ +/* Definitions to make GDB run on a vax under 4.2bsd. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* There is one known bug with VAX support that I don't know how to + fix: if you do a backtrace from a signal handler, you get something + like: +#0 0xbc in kill (592, 3) +#1 0x7f in hand (...) (...) +#2 0x7fffec7e in ?? (2, 0, 2147478112, 94) + ^^ GDB doesn't know about sigtramp +#3 0x7fffec70 in ?? (592, 2) + ^^^^^^^^^^ wrong address +#4 0xae in main (...) (...) + +when the correct backtrace (as given by adb) is: +_kill(250,3) from _hand+21 +_hand(2,0,7fffea60,5e) from 7fffec7e +sigtramp(2,0,7fffea60,5e) from _kill+4 +_kill(250,2) from _main+2e +_main(1,7fffeac4,7fffeacc) from start+3d + +If anyone knows enough about VAX BSD to fix this, please send the +fix to bug-gdb@prep.ai.mit.edu. */ + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* 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 2 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) \ +{ register int op = (unsigned char) read_memory_integer (pc, 1); \ + if (op == 0x11) pc += 2; /* skip brb */ \ + if (op == 0x31) pc += 3; /* skip brw */ \ + if (op == 0xC2 && \ + ((unsigned char) read_memory_integer (pc+2, 1)) == 0x5E) \ + pc += 3; /* skip subl2 */ \ + if (op == 0x9E && \ + ((unsigned char) read_memory_integer (pc+1, 1)) == 0xAE && \ + ((unsigned char) read_memory_integer(pc+3, 1)) == 0x5E) \ + pc += 4; /* skip movab */ \ + if (op == 0x9E && \ + ((unsigned char) read_memory_integer (pc+1, 1)) == 0xCE && \ + ((unsigned char) read_memory_integer(pc+4, 1)) == 0x5E) \ + pc += 5; /* skip movab */ \ + if (op == 0x9E && \ + ((unsigned char) read_memory_integer (pc+1, 1)) == 0xEE && \ + ((unsigned char) read_memory_integer(pc+6, 1)) == 0x5E) \ + pc += 7; /* skip movab */ \ +} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) FRAME_SAVED_PC(frame) + +#define TARGET_UPAGES 10 +#define TARGET_NBPG 512 +#define STACK_END_ADDR (0x80000000 - (TARGET_UPAGES * TARGET_NBPG)) + +/* On the VAX, sigtramp is in the u area. Can't check the exact + addresses because for cross-debugging we don't have VAX include + files around. This should be close enough. */ +#define IN_SIGTRAMP(pc, name) ((pc) >= STACK_END_ADDR && (pc < 0x80000000)) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {3} + +/* 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, 1) == 04) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the Vax. */ + +#define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000) + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 17 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc", "ps"} + +/* 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 AP_REGNUM 12 +#define FP_REGNUM 13 /* Contains address of executing stack frame */ +#define SP_REGNUM 14 /* Contains address of top of stack */ +#define PC_REGNUM 15 /* Contains program counter */ +#define PS_REGNUM 16 /* Contains processor status */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (17*4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the vax, 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 vax, all regs are 4 bytes. */ + +#define REGISTER_VIRTUAL_SIZE(N) 4 + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) 0 + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ + bcopy ((FROM), (TO), 4); + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ + bcopy ((FROM), (TO), 4); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) builtin_type_int + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { write_register (1, (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#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 Vax, the frame's nominal address is the FP value, + and 12 bytes later comes the saved previous FP value as a 4-byte word. */ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame + 12, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +/* On the vax, all functions have frames. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) {(FRAMELESS) = 0;} + +/* Saved Pc. */ + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 16, 4)) + +/* Cannot find the AP register value directly from the FP value. Must + find it saved in the frame called by this one, or in the AP + register for the innermost frame. However, there is no way to tell + the difference between the innermost frame and a frame for which we + just don't know the frame that it called (e.g. "info frame + 0x7ffec789"). For the sake of argument suppose that the stack is + somewhat trashed (which is one reason that "info frame" exists). + So return 0 (indicating we don't know the address of + the arglist) if we don't know what frame this frame calls. */ +#define FRAME_ARGS_ADDRESS_CORRECT(fi) \ + (((fi)->next_frame \ + ? read_memory_integer ((fi)->next_frame + 8, 4) \ + : /* read_register (AP_REGNUM) */ 0)) + +/* In most of GDB, getting the args address is too important to + just say "I don't know". This is sometimes wrong for functions + that aren't on top of the stack, but c'est la vie. */ +#define FRAME_ARGS_ADDRESS(fi) \ + (((fi)->next_frame \ + ? read_memory_integer ((fi)->next_frame + 8, 4) \ + : read_register (AP_REGNUM) /* 0 */)) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) \ +{ numargs = (0xff & read_memory_integer (FRAME_ARGS_ADDRESS (fi), 1)); } + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 4 + +/* 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 = read_memory_integer ((frame_info)->frame+4, 4) >> 16; \ + register CORE_ADDR next_addr; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + next_addr = (frame_info)->frame + 16; \ + /* Regmask's low bit is for register 0, \ + which is the first one that would be pushed. */ \ + for (regnum = 0; regnum < 12; regnum++, regmask >>= 1) \ + (frame_saved_regs).regs[regnum] = (regmask & 1) ? (next_addr += 4) : 0; \ + (frame_saved_regs).regs[SP_REGNUM] = next_addr + 4; \ + if (read_memory_integer ((frame_info)->frame + 4, 4) & 0x20000000) \ + (frame_saved_regs).regs[SP_REGNUM] += 4 + 4 * read_memory_integer (next_addr + 4, 4); \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 16; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame + 12; \ + (frame_saved_regs).regs[AP_REGNUM] = (frame_info)->frame + 8; \ + (frame_saved_regs).regs[PS_REGNUM] = (frame_info)->frame + 4; \ +} + +/* 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; \ + sp = push_word (sp, 0); /* arglist */ \ + for (regnum = 11; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + sp = push_word (sp, read_register (AP_REGNUM)); \ + sp = push_word (sp, (read_register (PS_REGNUM) & 0xffef) \ + + 0x2fff0000); \ + sp = push_word (sp, 0); \ + write_register (SP_REGNUM, sp); \ + write_register (FP_REGNUM, sp); \ + write_register (AP_REGNUM, sp + 17 * sizeof (int)); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + register int regmask = read_memory_integer (fp + 4, 4); \ + write_register (PS_REGNUM, \ + (regmask & 0xffff) \ + | (read_register (PS_REGNUM) & 0xffff0000)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 16, 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp + 12, 4)); \ + write_register (AP_REGNUM, read_memory_integer (fp + 8, 4)); \ + fp += 16; \ + for (regnum = 0; regnum < 12; regnum++) \ + if (regmask & (0x10000 << regnum)) \ + write_register (regnum, read_memory_integer (fp += 4, 4)); \ + fp = fp + 4 + ((regmask >> 30) & 3); \ + if (regmask & 0x20000000) \ + { regnum = read_memory_integer (fp, 4); \ + fp += (regnum + 1) * 4; } \ + write_register (SP_REGNUM, fp); \ + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } + +/* This sequence of words is the instructions + calls #69, @#32323232 + bpt + Note this is 8 bytes. */ + +#define CALL_DUMMY {0x329f69fb, 0x03323232} + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ *((char *) dummyname + 1) = nargs; \ + *(int *)((char *) dummyname + 3) = fun; } diff --git a/gdb/tm-vxworks68.h b/gdb/tm-vxworks68.h new file mode 100755 index 00000000000..a3cd7c22f62 --- /dev/null +++ b/gdb/tm-vxworks68.h @@ -0,0 +1,48 @@ +/* Parameters for execution on VxWorks 68k's, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define GDBINIT_FILENAME ".vxgdbinit" + +#define DEFAULT_PROMPT "(vxgdb) " + +/* Kludge... */ +#include "tm-sun3.h" + +/* We have more complex, useful breakpoints on the target. */ +#undef DECR_PC_AFTER_BREAK +#define DECR_PC_AFTER_BREAK 0 + +/* We are guaranteed to have a zero frame pointer at bottom of stack, too. */ +#undef FRAME_CHAIN +#undef FRAME_CHAIN_VALID + +/* Takes the current frame-struct pointer and returns the chain-pointer + to get to the calling frame. + + If our current frame pointer is zero, we're at the top; else read out + the saved FP from memory pointed to by the current FP. */ + +#define FRAME_CHAIN(thisframe) ((thisframe)->frame? read_memory_integer ((thisframe)->frame, 4): 0) + +/* If the chain pointer is zero (either because the saved value fetched + by FRAME_CHAIN was zero, or because the current FP was zero so FRAME_CHAIN + never fetched anything), we are at the top of the stack. */ + +#define FRAME_CHAIN_VALID(chain, thisframe) (chain != 0) diff --git a/gdb/tm-vxworks960.h b/gdb/tm-vxworks960.h new file mode 100755 index 00000000000..fc5c21454f3 --- /dev/null +++ b/gdb/tm-vxworks960.h @@ -0,0 +1,48 @@ +/* Parameters for VxWorks Intel 960's, for GDB, the GNU debugger. + Copyright (C) 1986-1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "tm-i960.h" + +#define GDBINIT_FILENAME ".vxgdbinit" + +#define DEFAULT_PROMPT "(vxgdb) " + +/* We have more complex, useful breakpoints on the target. + Amount ip must be decremented by after a breakpoint. */ + +#define DECR_PC_AFTER_BREAK 0 + +/* We are guaranteed to have a zero frame pointer at bottom of stack, too. */ + +#define FRAME_CHAIN_VALID(chain, thisframe) (chain != 0) + +/* Breakpoint patching is handled at the target end in VxWorks. */ +/* #define BREAKPOINT {0x00, 0x3e, 0x00, 0x66} */ + +/* Not needed, because we don't support core files: + #define KERNEL_U_ADDR + #define REGISTER_U_ADDR(addr, blockend, regno) + */ + +/* Address of end of stack space. + This doesn't matter for VxWorks, because it's only used + in manipulation of core files, which we don't support. */ + +/* #define STACK_END_ADDR (0xfe000000) */ diff --git a/gdb/umax-xdep.c b/gdb/umax-xdep.c new file mode 100644 index 00000000000..f3504da562f --- /dev/null +++ b/gdb/umax-xdep.c @@ -0,0 +1,139 @@ +/* umax host stuff. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include + +#include "gdbcore.h" +#include +#define PTRACE_ATTACH PT_ATTACH +#define PTRACE_DETACH PT_FREEPROC + +#include +#include + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +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) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct ptrace_user u; + int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name (filename); + data_start = exec_data_start; + + data_end = data_start + u.pt_dsize; + stack_start = stack_end - u.pt_ssize; + data_offset = sizeof u; + stack_offset = data_offset + u.pt_dsize; + reg_offset = 0; + + bcopy (&u.pt_aouthdr, &core_aouthdr, sizeof (AOUTHDR)); + printf ("Core file is from \"%s\".\n", u.pt_comm); + if (u.pt_signal > 0) + printf ("Program terminated with signal %d, %s.\n", + u.pt_signal, + u.pt_signal < NSIG + ? sys_siglist[u.pt_signal] + : "(undocumented)"); + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0) + perror_with_name (filename); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} diff --git a/gdb/values.c b/gdb/values.c new file mode 100644 index 00000000000..39ec8eab324 --- /dev/null +++ b/gdb/values.c @@ -0,0 +1,1337 @@ +/* Low level packing and unpacking of values for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "value.h" +#include "gdbcore.h" +#include "frame.h" +#include "command.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; + + check_stub_type (type); + + val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type)); + VALUE_NEXT (val) = all_values; + all_values = val; + VALUE_TYPE (val) = type; + VALUE_LVAL (val) = not_lval; + VALUE_ADDRESS (val) = 0; + VALUE_FRAME (val) = 0; + VALUE_OFFSET (val) = 0; + VALUE_BITPOS (val) = 0; + VALUE_BITSIZE (val) = 0; + VALUE_REPEATED (val) = 0; + VALUE_REPETITIONS (val) = 0; + VALUE_REGNO (val) = -1; + VALUE_LAZY (val) = 0; + VALUE_OPTIMIZED_OUT (val) = 0; + 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; + VALUE_LAZY (val) = 0; + VALUE_OPTIMIZED_OUT (val) = 0; + 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); + value_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); + VALUE_LAZY (val) = VALUE_LAZY (arg); + if (!VALUE_LAZY (val)) + { + bcopy (VALUE_CONTENTS_RAW (arg), VALUE_CONTENTS_RAW (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. + Result of -1 indicates the value was not saved; otherwise it is the + value history index of this new item. */ + +int +record_latest_value (val) + value val; +{ + int i; + + /* 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) { + (void) unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &i); + if (i) return -1; /* Indicate value not saved in history */ + } + + /* Here we treat value_history_count as origin-zero + and applying to the value being stored now. */ + + i = value_history_count % VALUE_HISTORY_CHUNK; + if (i == 0) + { + register struct value_history_chunk *new + = (struct value_history_chunk *) + xmalloc (sizeof (struct value_history_chunk)); + bzero (new->values, sizeof new->values); + new->next = value_history_chain; + value_history_chain = new; + } + + value_history_chain->values[i] = val; + release_value (val); + + /* Now we regard value_history_count as origin-one + and applying to the value just stored. */ + + return ++value_history_count; +} + +/* Return a copy of the value in the history with sequence number NUM. */ + +value +access_value_history (num) + int num; +{ + register struct value_history_chunk *chunk; + register int i; + register int absnum = num; + + if (absnum <= 0) + absnum += value_history_count; + + if (absnum <= 0) + { + if (num == 0) + error ("The history is empty."); + else if (num == 1) + error ("There is only one value in the history."); + else + error ("History does not go back to $$%d.", -num); + } + if (absnum > value_history_count) + error ("History has not yet reached $%d.", absnum); + + absnum--; + + /* Now absnum is always absolute and origin zero. */ + + chunk = value_history_chain; + for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK; + i > 0; i--) + chunk = chunk->next; + + return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]); +} + +/* Clear the value history entirely. + Must be done when new symbol tables are loaded, + because the type pointers become invalid. */ + +void +clear_value_history () +{ + register struct value_history_chunk *next; + register int i; + register value val; + + while (value_history_chain) + { + for (i = 0; i < VALUE_HISTORY_CHUNK; i++) + if (val = value_history_chain->values[i]) + free (val); + next = value_history_chain->next; + free (value_history_chain); + value_history_chain = next; + } + value_history_count = 0; +} + +static void +value_history_info (num_exp, from_tty) + char *num_exp; + int from_tty; +{ + register int i; + register value val; + static int num = 1; + + if (num_exp) + { + if (num_exp[0] == '+' && num_exp[1] == '\0') + /* "info history +" should print from the stored position. */ + ; + else + /* "info history " should print around value number . */ + num = parse_and_eval_address (num_exp) - 5; + } + else + { + /* "info history" means print the last 10 values. */ + num = value_history_count - 9; + } + + if (num <= 0) + num = 1; + + for (i = num; i < num + 10 && i <= value_history_count; i++) + { + val = access_value_history (i); + printf_filtered ("$%d = ", i); + value_print (val, stdout, 0, Val_pretty_default); + printf_filtered ("\n"); + } + + /* The next "info history +" should start after what we just printed. */ + num += 10; + + /* Hitting just return after this command should do the same thing as + "info history +". If num_exp is null, this is unnecessary, since + "info history +" is not useful after "info history". */ + if (from_tty && num_exp) + { + num_exp[0] = '+'; + num_exp[1] = '\0'; + } +} + +/* Internal variables. These are variables within the debugger + that hold values assigned by debugger commands. + The user refers to them with a '$' prefix + that does not appear in the variable names stored internally. */ + +static struct internalvar *internalvars; + +/* Look up an internal variable with name NAME. NAME should not + normally include a dollar sign. + + If the specified internal variable does not exist, + one is created, with a void value. */ + +struct internalvar * +lookup_internalvar (name) + char *name; +{ + register struct internalvar *var; + + for (var = internalvars; var; var = var->next) + if (!strcmp (var->name, name)) + return var; + + var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); + var->name = concat (name, "", ""); + var->value = allocate_value (builtin_type_void); + release_value (var->value); + var->next = internalvars; + internalvars = var; + return var; +} + +value +value_of_internalvar (var) + struct internalvar *var; +{ + register value val; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + return VALUE_OF_TRAPPED_INTERNALVAR (var); +#endif + + val = value_copy (var->value); + if (VALUE_LAZY (val)) + value_fetch_lazy (val); + VALUE_LVAL (val) = lval_internalvar; + VALUE_INTERNALVAR (val) = var; + return val; +} + +void +set_internalvar_component (var, offset, bitpos, bitsize, newval) + struct internalvar *var; + int offset, bitpos, bitsize; + value newval; +{ + register char *addr = VALUE_CONTENTS (var->value) + offset; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + SET_TRAPPED_INTERNALVAR (var, newval, bitpos, bitsize, offset); +#endif + + if (bitsize) + modify_field (addr, (int) value_as_long (newval), + bitpos, bitsize); + else + bcopy (VALUE_CONTENTS (newval), addr, + TYPE_LENGTH (VALUE_TYPE (newval))); +} + +void +set_internalvar (var, val) + struct internalvar *var; + value val; +{ +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0); +#endif + + free (var->value); + var->value = value_copy (val); + release_value (var->value); +} + +char * +internalvar_name (var) + struct internalvar *var; +{ + return var->name; +} + +/* Free all internalvars. Done when new symtabs are loaded, + because that makes the values invalid. */ + +void +clear_internalvars () +{ + register struct internalvar *var; + + while (internalvars) + { + var = internalvars; + internalvars = var->next; + free (var->name); + free (var->value); + free (var); + } +} + +static void +convenience_info () +{ + register struct internalvar *var; + int varseen = 0; + + for (var = internalvars; var; var = var->next) + { +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + continue; +#endif + if (!varseen) + { +#if 0 + /* Useless noise. */ + printf ("Debugger convenience variables:\n\n"); +#endif + varseen = 1; + } + printf ("$%s = ", var->name); + value_print (var->value, stdout, 0, Val_pretty_default); + printf ("\n"); + } + if (!varseen) + printf ("No debugger convenience variables now defined.\n\ +Convenience variables have names starting with \"$\";\n\ +use \"set\" as in \"set $foo = 5\" to define them.\n"); +} + +/* Extract a value as a C number (either long or double). + Knows how to convert fixed values to double, or + floating values to long. + Does not deallocate the value. */ + +LONGEST +value_as_long (val) + register value val; +{ + /* This coerces arrays and functions, which is necessary (e.g. + in disassemble_command). It also dereferences references, which + I suspect is the most logical thing to do. */ + if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_ENUM) + COERCE_ARRAY (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, target byte order) 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. We don't assume + any alignment for the raw data. Return value is in host byte order. + + If you want functions and arrays to be coerced to pointers, and + references to be dereferenced, call value_as_long() instead. + + 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)) + { + float retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (double)) + { + double retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + else + { + error ("Unexpected type of floating point number."); + } + } + else if (code == TYPE_CODE_INT && nosign) + { + if (len == sizeof (char)) + { + unsigned char retval = * (unsigned char *) valaddr; + /* SWAP_TARGET_AND_HOST (&retval, sizeof (unsigned char)); */ + return retval; + } + + if (len == sizeof (short)) + { + unsigned short retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (int)) + { + unsigned int retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (long)) + { + unsigned long retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } +#ifdef LONG_LONG + if (len == sizeof (long long)) + { + unsigned long long retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } +#endif + else + { + error ("That operation is not possible on an integer of that size."); + } + } + else if (code == TYPE_CODE_INT) + { + if (len == sizeof (char)) + { + char retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (short)) + { + short retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (int)) + { + int retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (long)) + { + long retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + +#ifdef LONG_LONG + if (len == sizeof (long long)) + { + long long retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } +#endif + else + { + error ("That operation is not possible on an integer of that size."); + } + } + else if (code == TYPE_CODE_PTR + || code == TYPE_CODE_REF) + { + if (len == sizeof (char *)) + { + CORE_ADDR retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + } + else if (code == TYPE_CODE_MEMBER) + error ("not implemented: member types in unpack_long"); + + error ("Value not integer or pointer."); + return 0; /* For lint -- never reached */ +} + +/* 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. Argument is in target + format, result is in host format. */ + +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)) + { + float retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + + if (len == sizeof (double)) + { + double retval; + bcopy (valaddr, &retval, sizeof (retval)); + SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); + return retval; + } + else + { + error ("Unexpected type of floating point number."); + } + } + else if (nosign) { + /* Unsigned -- be sure we compensate for signed LONGEST. */ +#ifdef LONG_LONG + return (unsigned long long) unpack_long (type, valaddr); +#else + return (unsigned long ) unpack_long (type, valaddr); +#endif + } else { + /* Signed -- we are OK with unpack_long. */ + return unpack_long (type, valaddr); + } +} + +/* Given a value ARG1 (offset by OFFSET bytes) + of a struct or union type ARG_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_primitive_field (arg1, offset, fieldno, arg_type) + register value arg1; + int offset; + register int fieldno; + register struct type *arg_type; +{ + register value v; + register struct type *type; + + check_stub_type (arg_type); + type = TYPE_FIELD_TYPE (arg_type, fieldno); + + /* Handle packed fields */ + + offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; + if (TYPE_FIELD_BITSIZE (arg_type, fieldno)) + { + v = value_from_long (type, + unpack_field_as_long (arg_type, + VALUE_CONTENTS (arg1), + fieldno)); + VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (arg_type, fieldno) % 8; + VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (arg_type, fieldno); + } + else + { + v = allocate_value (type); + if (VALUE_LAZY (arg1)) + VALUE_LAZY (v) = 1; + else + bcopy (VALUE_CONTENTS_RAW (arg1) + offset, + VALUE_CONTENTS_RAW (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; +} + +/* 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; +{ + return value_primitive_field (arg1, 0, fieldno, VALUE_TYPE (arg1)); +} + +value +value_fn_field (arg1, fieldno, subfieldno) + register value arg1; + register int fieldno; + int subfieldno; +{ + 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, NULL); + 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. ARG1 is side-effected in calling this function. + 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. */ +value +value_virtual_fn_field (arg1, f, j) + value arg1; + struct fn_field *f; + int j; +{ + /* 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 entry, vfn, vtbl; + value vi = value_from_long (builtin_type_int, + (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j)); + struct type *context = lookup_pointer_type (TYPE_FN_FIELD_FCONTEXT (f, j)); + if (TYPE_TARGET_TYPE (context) != VALUE_TYPE (arg1)) + arg1 = value_ind (value_cast (context, value_addr (arg1))); + + context = VALUE_TYPE (arg1); + + /* 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 (context) < 0) + TYPE_VPTR_FIELDNO (context) + = fill_in_vptr_fieldno (context); + + /* The virtual function table is now an array of structures + which have the form { int16 offset, delta; void *pfn; }. */ + vtbl = value_ind (value_field (arg1, TYPE_VPTR_FIELDNO (context))); + + /* Index into the virtual function table. This is hard-coded because + looking up a field is not cheap, and it may be important to save + time, e.g. if the user has set a conditional breakpoint calling + a virtual function. */ + entry = value_subscript (vtbl, vi); + + /* Move the `this' pointer according to the virtual function table. */ + VALUE_OFFSET (arg1) += value_as_long (value_field (entry, 0)); + if (! VALUE_LAZY (arg1)) + { + VALUE_LAZY (arg1) = 1; + value_fetch_lazy (arg1); + } + + vfn = value_field (entry, 2); + /* Reinstantiate the function pointer with the correct type. */ + VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)); + + return vfn; +} + +/* The value of a static class member does not depend + on its instance, only on its type. If FIELDNO >= 0, + then fieldno is a valid field number and is used directly. + Otherwise, FIELDNAME is the name of the field we are + searching for. If it is not a static field name, an + error is signaled. TYPE is the type in which we look for the + static field member. */ +value +value_static_field (type, fieldname, fieldno) + register struct type *type; + char *fieldname; + register int fieldno; +{ + register value v; + struct symbol *sym; + char *phys_name; + + if (fieldno < 0) + { + register struct type *t = type; + /* Look for static field. */ + while (t) + { + int i; + for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); 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"); + } + /* FIXME: this does not recursively check multiple baseclasses. */ + t = TYPE_N_BASECLASSES (t) ? TYPE_BASECLASS (t, 0) : 0; + } + + t = type; + + if (destructor_name_p (fieldname, t)) + error ("Cannot get value of destructor"); + + while (t) + { + int i; + + for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; i--) + { + if (! strcmp (TYPE_FN_FIELDLIST_NAME (t, i), fieldname)) + { + error ("Cannot get value of method \"%s\"", fieldname); + } + } + t = TYPE_N_BASECLASSES (t) ? TYPE_BASECLASS (t, 0) : 0; + } + error("there is no field named %s", fieldname); + } + + found: + phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno); + sym = lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL); + if (! sym) error ("Internal error: could not find physical static variable named %s", phys_name); + + type = TYPE_FIELD_TYPE (type, fieldno); + v = value_at (type, (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym)); + return v; +} + +/* Compute the address of the baseclass which is + the INDEXth baseclass of TYPE. The TYPE base + of the object is at VALADDR. */ + +char * +baseclass_addr (type, index, valaddr, valuep) + struct type *type; + int index; + char *valaddr; + value *valuep; +{ + struct type *basetype = TYPE_BASECLASS (type, index); + + if (BASETYPE_VIA_VIRTUAL (type, index)) + { + /* Must hunt for the pointer to this virtual baseclass. */ + register int i, len = TYPE_NFIELDS (type); + register int n_baseclasses = TYPE_N_BASECLASSES (type); + char *vbase_name, *type_name = type_name_no_tag (basetype); + + if (TYPE_MAIN_VARIANT (basetype)) + basetype = TYPE_MAIN_VARIANT (basetype); + + vbase_name = (char *)alloca (strlen (type_name) + 8); + sprintf (vbase_name, "_vb$%s", type_name); + /* First look for the virtual baseclass pointer + in the fields. */ + for (i = n_baseclasses; i < len; i++) + { + if (! strcmp (vbase_name, TYPE_FIELD_NAME (type, i))) + { + value v = value_at (basetype, + unpack_long (TYPE_FIELD_TYPE (type, i), + valaddr + (TYPE_FIELD_BITPOS (type, i) / 8))); + if (valuep) + *valuep = v; + return (char *) VALUE_CONTENTS (v); + } + } + /* Not in the fields, so try looking through the baseclasses. */ + for (i = index+1; i < n_baseclasses; i++) + { + char *baddr; + + baddr = baseclass_addr (type, i, valaddr, valuep); + if (baddr) + return baddr; + } + /* Not found. */ + if (valuep) + *valuep = 0; + return 0; + } + + /* Baseclass is easily computed. */ + if (valuep) + *valuep = 0; + return valaddr + TYPE_BASECLASS_BITPOS (type, index) / 8; +} + +/* Ugly hack to convert method stubs into method types. + + He ain't kiddin'. This demangles the name of the method into a string + including argument types, parses out each argument type, generates + a string casting a zero to that type, evaluates the string, and stuffs + the resulting type into an argtype vector!!! Then it knows the type + of the whole function (including argument types for overloading), + which info used to be in the stab's but was removed to hack back + the space required for them. */ +void +check_stub_method (type, i, j) + struct type *type; + int i, j; +{ + extern char *gdb_mangle_typename (), *strchr (); + struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); + char *inner_name = gdb_mangle_typename (type); + char *mangled_name + = (char *)xmalloc (strlen (TYPE_FN_FIELDLIST_NAME (type, i)) + + strlen (inner_name) + + strlen (TYPE_FN_FIELD_PHYSNAME (f, j)) + + 1); + char *demangled_name, *cplus_demangle (); + char *argtypetext, *p; + int depth = 0, argcount = 1; + struct type **argtypes; + + strcpy (mangled_name, TYPE_FN_FIELDLIST_NAME (type, i)); + strcat (mangled_name, inner_name); + strcat (mangled_name, TYPE_FN_FIELD_PHYSNAME (f, j)); + demangled_name = cplus_demangle (mangled_name, 0); + + /* Now, read in the parameters that define this type. */ + argtypetext = strchr (demangled_name, '(') + 1; + p = argtypetext; + while (*p) + { + if (*p == '(') + depth += 1; + else if (*p == ')') + depth -= 1; + else if (*p == ',' && depth == 0) + argcount += 1; + + p += 1; + } + /* We need one more slot for the void [...] or NULL [end of arglist] */ + argtypes = (struct type **)xmalloc ((argcount+1) * sizeof (struct type *)); + p = argtypetext; + argtypes[0] = lookup_pointer_type (type); + argcount = 1; + + if (*p != ')') /* () means no args, skip while */ + { + while (*p) + { + if (*p == '(') + depth += 1; + else if (*p == ')') + depth -= 1; + + if (depth <= 0 && (*p == ',' || *p == ')')) + { + char *tmp = (char *)alloca (p - argtypetext + 4); + value val; + tmp[0] = '('; + bcopy (argtypetext, tmp+1, p - argtypetext); + tmp[p-argtypetext+1] = ')'; + tmp[p-argtypetext+2] = '0'; + tmp[p-argtypetext+3] = '\0'; + val = parse_and_eval (tmp); + argtypes[argcount] = VALUE_TYPE (val); + argcount += 1; + argtypetext = p + 1; + } + p += 1; + } + } + + if (p[-2] != '.') /* ... */ + argtypes[argcount] = builtin_type_void; /* Ellist terminator */ + else + argtypes[argcount] = NULL; /* List terminator */ + + free (demangled_name); + smash_to_method_type (TYPE_FN_FIELD_TYPE (f, j), type, + TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), + argtypes); + TYPE_FN_FIELD_PHYSNAME (f, j) = mangled_name; + TYPE_FLAGS (TYPE_FN_FIELD_TYPE (f, j)) &= ~TYPE_FLAG_STUB; +} + +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); + SWAP_TARGET_AND_HOST (&val, sizeof val); + + /* Extracting bits depends on endianness of the machine. */ +#ifdef BITS_BIG_ENDIAN + val = val >> (sizeof val * 8 - bitpos % 8 - bitsize); +#else + val = val >> (bitpos % 8); +#endif + + val &= (1 << bitsize) - 1; + return val; +} + +void +modify_field (addr, fieldval, bitpos, bitsize) + char *addr; + int fieldval; + int bitpos, bitsize; +{ + long oword; + + /* Reject values too big to fit in the field in question. + Otherwise adjoining fields may be corrupted. */ + if (fieldval & ~((1< 8 bits!) */ +}; + +struct vot /* vax opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct vot_wot detail; /* rest of opcode table [datum] */ +}; + +#define vot_how args +#define vot_code code +#define vot_detail detail +#define vot_name name + +static struct vot +votstrs[] = +{ +{ "halt", {"", 0x00 } }, +{ "nop", {"", 0x01 } }, +{ "rei", {"", 0x02 } }, +{ "bpt", {"", 0x03 } }, +{ "ret", {"", 0x04 } }, +{ "rsb", {"", 0x05 } }, +{ "ldpctx", {"", 0x06 } }, +{ "svpctx", {"", 0x07 } }, +{ "cvtps", {"rwabrwab", 0x08 } }, +{ "cvtsp", {"rwabrwab", 0x09 } }, +{ "index", {"rlrlrlrlrlwl", 0x0a } }, +{ "crc", {"abrlrwab", 0x0b } }, +{ "prober", {"rbrwab", 0x0c } }, +{ "probew", {"rbrwab", 0x0d } }, +{ "insque", {"abab", 0x0e } }, +{ "remque", {"abwl", 0x0f } }, +{ "bsbb", {"bb", 0x10 } }, +{ "brb", {"bb", 0x11 } }, +{ "bneq", {"bb", 0x12 } }, +{ "bnequ", {"bb", 0x12 } }, +{ "beql", {"bb", 0x13 } }, +{ "beqlu", {"bb", 0x13 } }, +{ "bgtr", {"bb", 0x14 } }, +{ "bleq", {"bb", 0x15 } }, +{ "jsb", {"ab", 0x16 } }, +{ "jmp", {"ab", 0x17 } }, +{ "bgeq", {"bb", 0x18 } }, +{ "blss", {"bb", 0x19 } }, +{ "bgtru", {"bb", 0x1a } }, +{ "blequ", {"bb", 0x1b } }, +{ "bvc", {"bb", 0x1c } }, +{ "bvs", {"bb", 0x1d } }, +{ "bcc", {"bb", 0x1e } }, +{ "bgequ", {"bb", 0x1e } }, +{ "blssu", {"bb", 0x1f } }, +{ "bcs", {"bb", 0x1f } }, +{ "addp4", {"rwabrwab", 0x20 } }, +{ "addp6", {"rwabrwabrwab", 0x21 } }, +{ "subp4", {"rwabrwab", 0x22 } }, +{ "subp6", {"rwabrwabrwab", 0x23 } }, +{ "cvtpt", {"rwababrwab", 0x24 } }, +{ "mulp", {"rwabrwabrwab", 0x25 } }, +{ "cvttp", {"rwababrwab", 0x26 } }, +{ "divp", {"rwabrwabrwab", 0x27 } }, +{ "movc3", {"rwabab", 0x28 } }, +{ "cmpc3", {"rwabab", 0x29 } }, +{ "scanc", {"rwababrb", 0x2a } }, +{ "spanc", {"rwababrb", 0x2b } }, +{ "movc5", {"rwabrbrwab", 0x2c } }, +{ "cmpc5", {"rwabrbrwab", 0x2d } }, +{ "movtc", {"rwabrbabrwab", 0x2e } }, +{ "movtuc", {"rwabrbabrwab", 0x2f } }, +{ "bsbw", {"bw", 0x30 } }, +{ "brw", {"bw", 0x31 } }, +{ "cvtwl", {"rwwl", 0x32 } }, +{ "cvtwb", {"rwwb", 0x33 } }, +{ "movp", {"rwabab", 0x34 } }, +{ "cmpp3", {"rwabab", 0x35 } }, +{ "cvtpl", {"rwabwl", 0x36 } }, +{ "cmpp4", {"rwabrwab", 0x37 } }, +{ "editpc", {"rwababab", 0x38 } }, +{ "matchc", {"rwabrwab", 0x39 } }, +{ "locc", {"rbrwab", 0x3a } }, +{ "skpc", {"rbrwab", 0x3b } }, +{ "movzwl", {"rwwl", 0x3c } }, +{ "acbw", {"rwrwmwbw", 0x3d } }, +{ "movaw", {"awwl", 0x3e } }, +{ "pushaw", {"aw", 0x3f } }, +{ "addf2", {"rfmf", 0x40 } }, +{ "addf3", {"rfrfwf", 0x41 } }, +{ "subf2", {"rfmf", 0x42 } }, +{ "subf3", {"rfrfwf", 0x43 } }, +{ "mulf2", {"rfmf", 0x44 } }, +{ "mulf3", {"rfrfwf", 0x45 } }, +{ "divf2", {"rfmf", 0x46 } }, +{ "divf3", {"rfrfwf", 0x47 } }, +{ "cvtfb", {"rfwb", 0x48 } }, +{ "cvtfw", {"rfww", 0x49 } }, +{ "cvtfl", {"rfwl", 0x4a } }, +{ "cvtrfl", {"rfwl", 0x4b } }, +{ "cvtbf", {"rbwf", 0x4c } }, +{ "cvtwf", {"rwwf", 0x4d } }, +{ "cvtlf", {"rlwf", 0x4e } }, +{ "acbf", {"rfrfmfbw", 0x4f } }, +{ "movf", {"rfwf", 0x50 } }, +{ "cmpf", {"rfrf", 0x51 } }, +{ "mnegf", {"rfwf", 0x52 } }, +{ "tstf", {"rf", 0x53 } }, +{ "emodf", {"rfrbrfwlwf", 0x54 } }, +{ "polyf", {"rfrwab", 0x55 } }, +{ "cvtfd", {"rfwd", 0x56 } }, + /* opcode 57 is not defined yet */ +{ "adawi", {"rwmw", 0x58 } }, + /* opcode 59 is not defined yet */ + /* opcode 5a is not defined yet */ + /* opcode 5b is not defined yet */ +{ "insqhi", {"abaq", 0x5c } }, +{ "insqti", {"abaq", 0x5d } }, +{ "remqhi", {"aqwl", 0x5e } }, +{ "remqti", {"aqwl", 0x5f } }, +{ "addd2", {"rdmd", 0x60 } }, +{ "addd3", {"rdrdwd", 0x61 } }, +{ "subd2", {"rdmd", 0x62 } }, +{ "subd3", {"rdrdwd", 0x63 } }, +{ "muld2", {"rdmd", 0x64 } }, +{ "muld3", {"rdrdwd", 0x65 } }, +{ "divd2", {"rdmd", 0x66 } }, +{ "divd3", {"rdrdwd", 0x67 } }, +{ "cvtdb", {"rdwb", 0x68 } }, +{ "cvtdw", {"rdww", 0x69 } }, +{ "cvtdl", {"rdwl", 0x6a } }, +{ "cvtrdl", {"rdwl", 0x6b } }, +{ "cvtbd", {"rbwd", 0x6c } }, +{ "cvtwd", {"rwwd", 0x6d } }, +{ "cvtld", {"rlwd", 0x6e } }, +{ "acbd", {"rdrdmdbw", 0x6f } }, +{ "movd", {"rdwd", 0x70 } }, +{ "cmpd", {"rdrd", 0x71 } }, +{ "mnegd", {"rdwd", 0x72 } }, +{ "tstd", {"rd", 0x73 } }, +{ "emodd", {"rdrbrdwlwd", 0x74 } }, +{ "polyd", {"rdrwab", 0x75 } }, +{ "cvtdf", {"rdwf", 0x76 } }, + /* opcode 77 is not defined yet */ +{ "ashl", {"rbrlwl", 0x78 } }, +{ "ashq", {"rbrqwq", 0x79 } }, +{ "emul", {"rlrlrlwq", 0x7a } }, +{ "ediv", {"rlrqwlwl", 0x7b } }, +{ "clrd", {"wd", 0x7c } }, +{ "clrg", {"wg", 0x7c } }, +{ "clrq", {"wd", 0x7c } }, +{ "movq", {"rqwq", 0x7d } }, +{ "movaq", {"aqwl", 0x7e } }, +{ "movad", {"adwl", 0x7e } }, +{ "pushaq", {"aq", 0x7f } }, +{ "pushad", {"ad", 0x7f } }, +{ "addb2", {"rbmb", 0x80 } }, +{ "addb3", {"rbrbwb", 0x81 } }, +{ "subb2", {"rbmb", 0x82 } }, +{ "subb3", {"rbrbwb", 0x83 } }, +{ "mulb2", {"rbmb", 0x84 } }, +{ "mulb3", {"rbrbwb", 0x85 } }, +{ "divb2", {"rbmb", 0x86 } }, +{ "divb3", {"rbrbwb", 0x87 } }, +{ "bisb2", {"rbmb", 0x88 } }, +{ "bisb3", {"rbrbwb", 0x89 } }, +{ "bicb2", {"rbmb", 0x8a } }, +{ "bicb3", {"rbrbwb", 0x8b } }, +{ "xorb2", {"rbmb", 0x8c } }, +{ "xorb3", {"rbrbwb", 0x8d } }, +{ "mnegb", {"rbwb", 0x8e } }, +{ "caseb", {"rbrbrb", 0x8f } }, +{ "movb", {"rbwb", 0x90 } }, +{ "cmpb", {"rbrb", 0x91 } }, +{ "mcomb", {"rbwb", 0x92 } }, +{ "bitb", {"rbrb", 0x93 } }, +{ "clrb", {"wb", 0x94 } }, +{ "tstb", {"rb", 0x95 } }, +{ "incb", {"mb", 0x96 } }, +{ "decb", {"mb", 0x97 } }, +{ "cvtbl", {"rbwl", 0x98 } }, +{ "cvtbw", {"rbww", 0x99 } }, +{ "movzbl", {"rbwl", 0x9a } }, +{ "movzbw", {"rbww", 0x9b } }, +{ "rotl", {"rbrlwl", 0x9c } }, +{ "acbb", {"rbrbmbbw", 0x9d } }, +{ "movab", {"abwl", 0x9e } }, +{ "pushab", {"ab", 0x9f } }, +{ "addw2", {"rwmw", 0xa0 } }, +{ "addw3", {"rwrwww", 0xa1 } }, +{ "subw2", {"rwmw", 0xa2 } }, +{ "subw3", {"rwrwww", 0xa3 } }, +{ "mulw2", {"rwmw", 0xa4 } }, +{ "mulw3", {"rwrwww", 0xa5 } }, +{ "divw2", {"rwmw", 0xa6 } }, +{ "divw3", {"rwrwww", 0xa7 } }, +{ "bisw2", {"rwmw", 0xa8 } }, +{ "bisw3", {"rwrwww", 0xa9 } }, +{ "bicw2", {"rwmw", 0xaa } }, +{ "bicw3", {"rwrwww", 0xab } }, +{ "xorw2", {"rwmw", 0xac } }, +{ "xorw3", {"rwrwww", 0xad } }, +{ "mnegw", {"rwww", 0xae } }, +{ "casew", {"rwrwrw", 0xaf } }, +{ "movw", {"rwww", 0xb0 } }, +{ "cmpw", {"rwrw", 0xb1 } }, +{ "mcomw", {"rwww", 0xb2 } }, +{ "bitw", {"rwrw", 0xb3 } }, +{ "clrw", {"ww", 0xb4 } }, +{ "tstw", {"rw", 0xb5 } }, +{ "incw", {"mw", 0xb6 } }, +{ "decw", {"mw", 0xb7 } }, +{ "bispsw", {"rw", 0xb8 } }, +{ "bicpsw", {"rw", 0xb9 } }, +{ "popr", {"rw", 0xba } }, +{ "pushr", {"rw", 0xbb } }, +{ "chmk", {"rw", 0xbc } }, +{ "chme", {"rw", 0xbd } }, +{ "chms", {"rw", 0xbe } }, +{ "chmu", {"rw", 0xbf } }, +{ "addl2", {"rlml", 0xc0 } }, +{ "addl3", {"rlrlwl", 0xc1 } }, +{ "subl2", {"rlml", 0xc2 } }, +{ "subl3", {"rlrlwl", 0xc3 } }, +{ "mull2", {"rlml", 0xc4 } }, +{ "mull3", {"rlrlwl", 0xc5 } }, +{ "divl2", {"rlml", 0xc6 } }, +{ "divl3", {"rlrlwl", 0xc7 } }, +{ "bisl2", {"rlml", 0xc8 } }, +{ "bisl3", {"rlrlwl", 0xc9 } }, +{ "bicl2", {"rlml", 0xca } }, +{ "bicl3", {"rlrlwl", 0xcb } }, +{ "xorl2", {"rlml", 0xcc } }, +{ "xorl3", {"rlrlwl", 0xcd } }, +{ "mnegl", {"rlwl", 0xce } }, +{ "casel", {"rlrlrl", 0xcf } }, +{ "movl", {"rlwl", 0xd0 } }, +{ "cmpl", {"rlrl", 0xd1 } }, +{ "mcoml", {"rlwl", 0xd2 } }, +{ "bitl", {"rlrl", 0xd3 } }, +{ "clrf", {"wf", 0xd4 } }, +{ "clrl", {"wl", 0xd4 } }, +{ "tstl", {"rl", 0xd5 } }, +{ "incl", {"ml", 0xd6 } }, +{ "decl", {"ml", 0xd7 } }, +{ "adwc", {"rlml", 0xd8 } }, +{ "sbwc", {"rlml", 0xd9 } }, +{ "mtpr", {"rlrl", 0xda } }, +{ "mfpr", {"rlwl", 0xdb } }, +{ "movpsl", {"wl", 0xdc } }, +{ "pushl", {"rl", 0xdd } }, +{ "moval", {"alwl", 0xde } }, +{ "movaf", {"afwl", 0xde } }, +{ "pushal", {"al", 0xdf } }, +{ "pushaf", {"af", 0xdf } }, +{ "bbs", {"rlabbb", 0xe0 } }, +{ "bbc", {"rlabbb", 0xe1 } }, +{ "bbss", {"rlabbb", 0xe2 } }, +{ "bbcs", {"rlabbb", 0xe3 } }, +{ "bbsc", {"rlabbb", 0xe4 } }, +{ "bbcc", {"rlabbb", 0xe5 } }, +{ "bbssi", {"rlabbb", 0xe6 } }, +{ "bbcci", {"rlabbb", 0xe7 } }, +{ "blbs", {"rlbb", 0xe8 } }, +{ "blbc", {"rlbb", 0xe9 } }, +{ "ffs", {"rlrbvbwl", 0xea } }, +{ "ffc", {"rlrbvbwl", 0xeb } }, +{ "cmpv", {"rlrbvbrl", 0xec } }, +{ "cmpzv", {"rlrbvbrl", 0xed } }, +{ "extv", {"rlrbvbwl", 0xee } }, +{ "extzv", {"rlrbvbwl", 0xef } }, +{ "insv", {"rlrlrbvb", 0xf0 } }, +{ "acbl", {"rlrlmlbw", 0xf1 } }, +{ "aoblss", {"rlmlbb", 0xf2 } }, +{ "aobleq", {"rlmlbb", 0xf3 } }, +{ "sobgeq", {"mlbb", 0xf4 } }, +{ "sobgtr", {"mlbb", 0xf5 } }, +{ "cvtlb", {"rlwb", 0xf6 } }, +{ "cvtlw", {"rlww", 0xf7 } }, +{ "ashp", {"rbrwabrbrwab", 0xf8 } }, +{ "cvtlp", {"rlrwab", 0xf9 } }, +{ "callg", {"abab", 0xfa } }, +{ "calls", {"rlab", 0xfb } }, +{ "xfc", {"", 0xfc } }, + /* undefined opcodes here */ +{ "cvtdh", {"rdwh", 0x32fd } }, +{ "cvtgf", {"rgwh", 0x33fd } }, +{ "addg2", {"rgmg", 0x40fd } }, +{ "addg3", {"rgrgwg", 0x41fd } }, +{ "subg2", {"rgmg", 0x42fd } }, +{ "subg3", {"rgrgwg", 0x43fd } }, +{ "mulg2", {"rgmg", 0x44fd } }, +{ "mulg3", {"rgrgwg", 0x45fd } }, +{ "divg2", {"rgmg", 0x46fd } }, +{ "divg3", {"rgrgwg", 0x47fd } }, +{ "cvtgb", {"rgwb", 0x48fd } }, +{ "cvtgw", {"rgww", 0x49fd } }, +{ "cvtgl", {"rgwl", 0x4afd } }, +{ "cvtrgl", {"rgwl", 0x4bfd } }, +{ "cvtbg", {"rbwg", 0x4cfd } }, +{ "cvtwg", {"rwwg", 0x4dfd } }, +{ "cvtlg", {"rlwg", 0x4efd } }, +{ "acbg", {"rgrgmgbw", 0x4ffd } }, +{ "movg", {"rgwg", 0x50fd } }, +{ "cmpg", {"rgrg", 0x51fd } }, +{ "mnegg", {"rgwg", 0x52fd } }, +{ "tstg", {"rg", 0x53fd } }, +{ "emodg", {"rgrwrgwlwg", 0x54fd } }, +{ "polyg", {"rgrwab", 0x55fd } }, +{ "cvtgh", {"rgwh", 0x56fd } }, + /* undefined opcodes here */ +{ "addh2", {"rhmh", 0x60fd } }, +{ "addh3", {"rhrhwh", 0x61fd } }, +{ "subh2", {"rhmh", 0x62fd } }, +{ "subh3", {"rhrhwh", 0x63fd } }, +{ "mulh2", {"rhmh", 0x64fd } }, +{ "mulh3", {"rhrhwh", 0x65fd } }, +{ "divh2", {"rhmh", 0x66fd } }, +{ "divh3", {"rhrhwh", 0x67fd } }, +{ "cvthb", {"rhwb", 0x68fd } }, +{ "cvthw", {"rhww", 0x69fd } }, +{ "cvthl", {"rhwl", 0x6afd } }, +{ "cvtrhl", {"rhwl", 0x6bfd } }, +{ "cvtbh", {"rbwh", 0x6cfd } }, +{ "cvtwh", {"rwwh", 0x6dfd } }, +{ "cvtlh", {"rlwh", 0x6efd } }, +{ "acbh", {"rhrhmhbw", 0x6ffd } }, +{ "movh", {"rhwh", 0x70fd } }, +{ "cmph", {"rhrh", 0x71fd } }, +{ "mnegh", {"rhwh", 0x72fd } }, +{ "tsth", {"rh", 0x73fd } }, +{ "emodh", {"rhrwrhwlwh", 0x74fd } }, +{ "polyh", {"rhrwab", 0x75fd } }, +{ "cvthg", {"rhwg", 0x76fd } }, + /* undefined opcodes here */ +{ "clrh", {"wh", 0x7cfd } }, +{ "clro", {"wo", 0x7cfd } }, +{ "movo", {"rowo", 0x7dfd } }, +{ "movah", {"ahwl", 0x7efd } }, +{ "movao", {"aowl", 0x7efd } }, +{ "pushah", {"ah", 0x7ffd } }, +{ "pushao", {"ao", 0x7ffd } }, + /* undefined opcodes here */ +{ "cvtfh", {"rfwh", 0x98fd } }, +{ "cvtfg", {"rfwg", 0x99fd } }, + /* undefined opcodes here */ +{ "cvthf", {"rhwf", 0xf6fd } }, +{ "cvthd", {"rhwd", 0xf7fd } }, + /* undefined opcodes here */ +{ "bugl", {"rl", 0xfdff } }, +{ "bugw", {"rw", 0xfeff } }, + /* undefined opcodes here */ + +{ "" , "" } /* empty is end sentinel */ + +}; /* votstrs */ + +/* end: vax.opcode.h */ diff --git a/gdb/vax-pinsn.c b/gdb/vax-pinsn.c new file mode 100644 index 00000000000..4c159af804a --- /dev/null +++ b/gdb/vax-pinsn.c @@ -0,0 +1,240 @@ +/* Print vax instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "vax-opcode.h" + +/* Vax instructions are never longer than this. */ +#define MAXLEN 62 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof votstrs / sizeof votstrs[0]) + +extern char *reg_names[]; + +static unsigned char *print_insn_arg (); + +/* Print the vax 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; + + read_memory (memaddr, buffer, MAXLEN); + + for (i = 0; i < NOPCODES; i++) + if (votstrs[i].detail.code == buffer[0] + || votstrs[i].detail.code == *(unsigned short *)buffer) + break; + + /* Handle undefined instructions. */ + if (i == NOPCODES) + { + fprintf (stream, "0%o", buffer[0]); + return 1; + } + + fprintf (stream, "%s", votstrs[i].name); + + /* Point at first byte of argument data, + and at descriptor for first argument. */ + p = buffer + 1 + (votstrs[i].detail.code >= 0x100); + d = votstrs[i].detail.args; + + if (*d) + fputc (' ', stream); + + while (*d) + { + p = print_insn_arg (d, p, memaddr + (p - buffer), stream); + d += 2; + if (*d) + fprintf (stream, ","); + } + return p - buffer; +} + +static unsigned char * +print_insn_arg (d, p, addr, stream) + char *d; + register char *p; + CORE_ADDR addr; + FILE *stream; +{ + register int regnum = *p & 0xf; + float floatlitbuf; + + if (*d == 'b') + { + if (d[1] == 'b') + fprintf (stream, "0x%x", addr + *p++ + 1); + else + { + fprintf (stream, "0x%x", addr + *(short *)p + 2); + p += 2; + } + } + else + switch ((*p++ >> 4) & 0xf) + { + case 0: + case 1: + case 2: + case 3: /* Literal mode */ + if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h') + { + *(int *)&floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4); + fprintf (stream, "$%f", floatlitbuf); + } + else + fprintf (stream, "$%d", p[-1] & 0x3f); + break; + + case 4: /* Indexed */ + p = (char *) print_insn_arg (d, p, addr + 1, stream); + fprintf (stream, "[%s]", reg_names[regnum]); + break; + + case 5: /* Register */ + fprintf (stream, reg_names[regnum]); + break; + + case 7: /* Autodecrement */ + fputc ('-', stream); + case 6: /* Register deferred */ + fprintf (stream, "(%s)", reg_names[regnum]); + break; + + case 9: /* Autoincrement deferred */ + fputc ('@', stream); + if (regnum == PC_REGNUM) + { + fputc ('#', stream); + print_address (*(long *)p, stream); + p += 4; + break; + } + case 8: /* Autoincrement */ + if (regnum == PC_REGNUM) + { + fputc ('#', stream); + switch (d[1]) + { + case 'b': + fprintf (stream, "%d", *p++); + break; + + case 'w': + fprintf (stream, "%d", *(short *)p); + p += 2; + break; + + case 'l': + fprintf (stream, "%d", *(long *)p); + p += 4; + break; + + case 'q': + fprintf (stream, "0x%x%08x", ((long *)p)[1], ((long *)p)[0]); + p += 8; + break; + + case 'o': + fprintf (stream, "0x%x%08x%08x%08x", + ((long *)p)[3], ((long *)p)[2], + ((long *)p)[1], ((long *)p)[0]); + p += 16; + break; + + case 'f': + if (INVALID_FLOAT (p, 4)) + fprintf (stream, "<>", *(int *) p); + else + fprintf (stream, "%f", *(float *) p); + p += 4; + break; + + case 'd': + if (INVALID_FLOAT (p, 8)) + fprintf (stream, "<>", + ((long *)p)[1], ((long *)p)[0]); + else + fprintf (stream, "%f", *(double *) p); + p += 8; + break; + + case 'g': + fprintf (stream, "g-float"); + p += 8; + break; + + case 'h': + fprintf (stream, "h-float"); + p += 16; + break; + + } + } + else + fprintf (stream, "(%s)+", reg_names[regnum]); + break; + + case 11: /* Byte displacement deferred */ + fputc ('@', stream); + case 10: /* Byte displacement */ + if (regnum == PC_REGNUM) + print_address (addr + *p + 2, stream); + else + fprintf (stream, "%d(%s)", *p, reg_names[regnum]); + p += 1; + break; + + case 13: /* Word displacement deferred */ + fputc ('@', stream); + case 12: /* Word displacement */ + if (regnum == PC_REGNUM) + print_address (addr + *(short *)p + 3, stream); + else + fprintf (stream, "%d(%s)", *(short *)p, reg_names[regnum]); + p += 2; + break; + + case 15: /* Long displacement deferred */ + fputc ('@', stream); + case 14: /* Long displacement */ + if (regnum == PC_REGNUM) + print_address (addr + *(long *)p + 5, stream); + else + fprintf (stream, "%d(%s)", *(long *)p, reg_names[regnum]); + p += 4; + } + + return (unsigned char *) p; +} diff --git a/gdb/vx-share/dbgRpcLib.h b/gdb/vx-share/dbgRpcLib.h new file mode 100644 index 00000000000..c420075c281 --- /dev/null +++ b/gdb/vx-share/dbgRpcLib.h @@ -0,0 +1,28 @@ +/* dbgRpcLib.h - header file for remote debugging via rpc */ + +/* +modification history +-------------------- +01b,04oct90,maf added VX_BOOT_FILE_INQ. +01a,05jun90,llk extracted from xdr_dbx.h. +*/ + +#ifndef INCdbxRpcLibh +#define INCdbxRpcLibh 1 + +#define PROCESS_START 50 +#define PROCESS_WAIT 51 +#define VX_STATE_INQ 60 +#define VX_LOAD 61 +#define VX_SYMBOL_INQ 62 +#define VX_BREAK_ADD 63 +#define VX_BREAK_DELETE 64 +#define VX_FP_INQUIRE 65 +#define VX_TASK_SUSPEND 66 +#define VX_CALL_FUNC 67 +#define VX_CONV_FROM_68881 68 +#define VX_CONV_TO_68881 69 +#define VX_BOOT_FILE_INQ 70 +#define VX_SOURCE_STEP 71 + +#endif INCdbxRpcLibh diff --git a/gdb/vx-share/ptrace.h b/gdb/vx-share/ptrace.h new file mode 100644 index 00000000000..34801c71e06 --- /dev/null +++ b/gdb/vx-share/ptrace.h @@ -0,0 +1,44 @@ +/* @(#)ptrace.h 1.1 86/07/07 SMI */ + +/* + * Copyright (c) 1985 by Sun Microsystems, Inc. + */ + +/* +modification history +-------------------- +01a,05jun90,llk borrowed. +*/ + +#ifndef _PTRACE_ +#define _PTRACE_ + +/* + * Request values for the ptrace system call + */ +enum ptracereq { + PTRACE_TRACEME = 0, /* 0, by tracee to begin tracing */ + PTRACE_CHILDDONE = 0, /* 0, tracee is done with his half */ + PTRACE_PEEKTEXT, /* 1, read word from text segment */ + PTRACE_PEEKDATA, /* 2, read word from data segment */ + PTRACE_PEEKUSER, /* 3, read word from user struct */ + PTRACE_POKETEXT, /* 4, write word into text segment */ + PTRACE_POKEDATA, /* 5, write word into data segment */ + PTRACE_POKEUSER, /* 6, write word into user struct */ + PTRACE_CONT, /* 7, continue process */ + PTRACE_KILL, /* 8, terminate process */ + PTRACE_SINGLESTEP, /* 9, single step process */ + PTRACE_ATTACH, /* 10, attach to an existing process */ + PTRACE_DETACH, /* 11, detach from a process */ + PTRACE_GETREGS, /* 12, get all registers */ + PTRACE_SETREGS, /* 13, set all registers */ + PTRACE_GETFPREGS, /* 14, get all floating point regs */ + PTRACE_SETFPREGS, /* 15, set all floating point regs */ + PTRACE_READDATA, /* 16, read data segment */ + PTRACE_WRITEDATA, /* 17, write data segment */ + PTRACE_READTEXT, /* 18, read text segment */ + PTRACE_WRITETEXT, /* 19, write text segment */ + PTRACE_GETFPAREGS, /* 20, get all fpa regs */ + PTRACE_SETFPAREGS, /* 21, set all fpa regs */ +}; +#endif !_PTRACE diff --git a/gdb/vx-share/reg.h b/gdb/vx-share/reg.h new file mode 100644 index 00000000000..84658b7760e --- /dev/null +++ b/gdb/vx-share/reg.h @@ -0,0 +1,209 @@ +/* @(#)reg.h 1.1 86/07/07 SMI */ + +/* + * Copyright (c) 1986 by Sun Microsystems, Inc. + */ + +/* +modification history +-------------------- +01a,05jun90,llk borrowed. +*/ + +#ifndef _REG_ +#define _REG_ + +#ifdef I80960 + +/* Intel 960 register values passed over the wire by RPC: */ + +struct regs +{ + int r_lreg[16]; /* local registers */ + int r_greg[16]; /* global registers */ + int r_pcw; /* process control word */ + int r_acw; /* arithmetic control word */ + int r_tcw; /* trace control word */ +}; + +#define FP_REG_SIZE 12 + +struct fp_status { + char fps_regs[4][FP_REG_SIZE]; /* floating point regs */ +}; + +#else /* For now, just 68000 */ + +/* + * Location of the users' stored + * registers relative to R0. + * Usage is u.u_ar0[XX]. + */ +#define R0 (0) +#define R1 (1) +#define R2 (2) +#define R3 (3) +#define R4 (4) +#define R5 (5) +#define R6 (6) +#define R7 (7) +#define AR0 (8) +#define AR1 (9) +#define AR2 (10) +#define AR3 (11) +#define AR4 (12) +#define AR5 (13) +#define AR6 (14) +#define AR7 (15) +#define SP (15) +#define PS (16) +#define PC (17) + +/* + * And now for something completely the same... + */ +#ifndef LOCORE +struct regs { + int r_dreg[8]; /* data registers */ +#define r_r0 r_dreg[0] /* r0 for portability */ + int r_areg[8]; /* address registers */ +#define r_sp r_areg[7] /* user stack pointer */ + int r_sr; /* status register (actually a short) */ +#define r_ps r_sr + int r_pc; /* program counter */ +}; + +struct stkfmt { + int f_stkfmt : 4; /* stack format */ + int : 2; + int f_vector : 10; /* vector offset */ + short f_beibase; /* start of bus error info (if any) */ +}; + + +/* + * Struct for floating point registers and general state + * for the MC68881 (the sky fpp has no user visible state). + * If fps_flags == FPS_UNUSED, the other 68881 fields have no meaning. + * fps_code and fps_flags are software implemented fields. + * fps_flags is not used when set by user level programs, + * but changing fps_code has the side effect of changing u.u_code. + */ + +typedef struct ext_fp { + int fp[3]; +} ext_fp; /* extended 96-bit 68881 fp registers */ + +struct fp_status { + ext_fp fps_regs[8]; /* 68881 floating point regs */ + int fps_control; /* 68881 control reg */ + int fps_status; /* 68881 status reg */ + int fps_iaddr; /* 68881 instruction address reg */ + int fps_code; /* additional word for signals */ + int fps_flags; /* r/o - unused, idle or busy */ +}; +#endif !LOCORE + +/* + * Values defined for `fps_flags'. + */ +#define FPS_UNUSED 0 /* 68881 never used yet */ +#define FPS_IDLE 1 /* 68881 instruction completed */ +#define FPS_BUSY 2 /* 68881 instruction interrupted */ + +/* + * The EXT_FPS_FLAGS() macro is used to convert a pointer to an + * fp_istate into a value to be used for the user visible state + * found in fps_flags. As a speed optimization, this convertion + * is only done is required (e.g. the PTRACE_GETFPREGS ptrace + * call or when dumping core) instead of on each context switch. + * The tests that we base the state on are that a fpis_vers of + * FPIS_VERSNULL means NULL state, else a fpis_bufsiz of FPIS_IDLESZ + * means IDLE state, else we assume BUSY state. + */ +#define FPIS_VERSNULL 0x0 +#define FPIS_IDLESIZE 0x18 + +#define EXT_FPS_FLAGS(istatep) \ + ((istatep)->fpis_vers == FPIS_VERSNULL ? FPS_UNUSED : \ + (istatep)->fpis_bufsiz == FPIS_IDLESIZE ? FPS_IDLE : FPS_BUSY) + +#ifndef LOCORE +/* + * Struct for the internal state of the MC68881 + * Although the MC68881 can have a smaller maximum for + * internal state, we allow for more to allow for expansion. + */ +#define FPIS_BUFSIZ 0xc0 + +struct fp_istate { + unsigned char fpis_vers; /* version number */ + unsigned char fpis_bufsiz; /* size of info in fpis_buf */ + unsigned short fpis_reserved; /* reserved word */ + unsigned char fpis_buf[FPIS_BUFSIZ]; /* fpp internal state buffer */ +}; + +/* + * Structures for the status and data registers are defined here. + * Struct fpa_status are included in the u area. + * Struct fpa_regs is included in struct core. + */ + +/* struct fpa_status is saved/restored during context switch */ +struct fpa_status { + unsigned int fpas_state; /* STATE, supervisor privileged reg */ + unsigned int fpas_imask; /* IMASK */ + unsigned int fpas_load_ptr; /* LOAD_PTR */ + unsigned int fpas_ierr; /* IERR */ + unsigned int fpas_act_instr; /* pipe active instruction halves */ + unsigned int fpas_nxt_instr; /* pipe next instruction halves */ + unsigned int fpas_act_d1half;/* pipe active data first half */ + unsigned int fpas_act_d2half;/* pipe active data second half */ + unsigned int fpas_nxt_d1half;/* pipe next data first half */ + unsigned int fpas_nxt_d2half;/* pipe next data second half */ + unsigned int fpas_mode3_0; /* FPA MODE3_0 register */ + unsigned int fpas_wstatus; /* FPA WSTATUS register */ +}; + +/* + * Since there are 32 contexts supported by the FPA hardware, + * when we do context switch on the FPA, we don't save/restore + * the data registers between the FPA and the u area. + * If there are already 32 processes using the fpa concurrently, + * we give an error message to the 33rd process trying to use the fpa. + * (Hopefully there will not be this many processes using FPA concurrently.) + */ + +#define FPA_NCONTEXTS 32 +#define FPA_NDATA_REGS 32 + +typedef struct fpa_long { + int fpl_data[2]; +} fpa_long; /* 64 bit double precision registers */ + +/* Struct fpa_regs is included in struct core. */ +struct fpa_regs { + unsigned int fpar_flags; /* if zero, other fields are meaningless */ + struct fpa_status fpar_status; + fpa_long fpar_data[FPA_NDATA_REGS]; +}; + +/* + * The size of struct fpa_regs is changed from 141 ints in 3.0 to + * 77 ints in 3.x. A pad of this size difference is added to struct core. + */ +#define CORE_PADLEN 64 + +/* + * If there is going to be external FPU state then we must define the FPU + * variable + */ +struct fpu { + struct fp_status f_fpstatus; /* External FPP state, if any */ + struct fpa_regs f_fparegs; /* FPA registers, if any */ + int f_pad[CORE_PADLEN]; /* see comment above */ +}; + +#endif !LOCORE +#endif /* !I80960 */ +#endif !_REG_ diff --git a/gdb/vx-share/vxTypes.h b/gdb/vx-share/vxTypes.h new file mode 100644 index 00000000000..3ebd7c6d4b3 --- /dev/null +++ b/gdb/vx-share/vxTypes.h @@ -0,0 +1,70 @@ +/* vxTypes.h - VxWorks type definition header */ + +/* Copyright 1984-1990 Wind River Systems, Inc. */ + +/* +modification history +-------------------- +01c,05oct90,shl added copyright notice. + made #endif ANSI style. +01b,10aug90,dnw added VOIDFUNCPTR +01a,29may90,del written. +*/ + +#ifndef INCvxTypesh +#define INCvxTypesh + +/* The following stuff must NOT be included if this include file is used + * from assembly language. Just #define ASMLANGUAGE before the include, + * to get rid of it. + */ + +#ifndef ASMLANGUAGE + +/* vxWorks types */ + +typedef char INT8; +typedef short INT16; +typedef int INT32; + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned int UINT32; + +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned int UINT; +typedef unsigned long ULONG; + +typedef int BOOL; +typedef int VOID; +typedef int STATUS; +typedef int ARGINT; + +typedef int (*FUNCPTR) (); /* ptr to function returning int */ +typedef VOID (*VOIDFUNCPTR) (); /* ptr to function returning VOID */ + + +/* historical definitions - now obsolete */ + +typedef char TINY; /* obsolete */ +typedef char TBOOL; /* obsolete */ +typedef unsigned char UTINY; /* obsolete */ + + +/* architecture dependent typedefs */ + +#ifdef CPU_FAMILY + +#if CPU_FAMILY==MC680X0 +typedef unsigned short INSTR; /* word-aligned instructions */ +#endif /* CPU_FAMILY==MC680X0 */ + +#if CPU_FAMILY==SPARC +typedef unsigned long INSTR; /* 32 bit word-aligned instructions */ +#endif /* CPU_FAMILY==SPARC */ + +#endif + +#endif /* ASMLANGUAGE */ +#endif /* INCvxTypesh */ diff --git a/gdb/vx-share/vxWorks.h b/gdb/vx-share/vxWorks.h new file mode 100644 index 00000000000..483313e1f95 --- /dev/null +++ b/gdb/vx-share/vxWorks.h @@ -0,0 +1,177 @@ +/* vxWorks.h - VxWorks standard definitions header */ + +/* Copyright 1984-1990 Wind River Systems, Inc. */ + +/* +modification history +-------------------- +01z,05oct90,shl added copyright notice. + made #endif ANSI style. +01y,28sep90,del added I960 defines. +01x,29may90,del moved types to vxTypes.h +01w,09apr90,jcf added timeout definitions. +01v,24jan90,gae moved network configuration flags here from makefile's. +01u,01sep88,mcl definition of INSTR dependent on processor family; added SPARC. + +gae added MC680X0 and defined CPU_FAMILY. +01t,08apr89,dnw added ifdef to prevent inclusion of vxWorks.h more than once. +01s,22jun88,dnw moved READ, WRITE, and UPDATE back here from ioLib.h. +01r,22apr88,gae oops! forgot some #endif's in 01q. +01q,12apr88,gae removed QUICK & WAIT; added STD_{IN,OUT,ERR}. + fixed #define's of FALSE, TRUE, etc. + moved READ, WRITE, and UPDATE to ioLib.h. +01p,04dec87,dnw added undefine of MC68000 to get around Green Hills bug that + pre-defines MC68000. +01o,12nov87,ecs added type ULONG. +01n,08feb86,dnw added types INSTR, UINT, USHORT. +01m,14oct85,rdc added BUS types. +01l,16jul85,jlf added conditional for NULL and EOF. +01k,24jun85,rdc installed condtional compile so we can include in + assembly language files. See instructions below. + Added System type macro and CPU type macro. +01j,13jun85,dnw cleaned-up, removed more obsolete stuff to wrs.h +01i,11sep84,jlf changed name from wrs.h to vxWorks.h. removed GLOBAL. +01h,03jun84,dnw removed IGNORE declaration. +01g,09apr84,jlf added MEMBER_SIZE macro. +01f,14dec83,dnw added MSB, LSB macros +01e,17nov83,jlf added STATUS type, for routines which return a status. +01d,13jul83,dnw added NELEMENTS macro +01c,14May83,dnw added OFFSET macro +01b,17Feb83,dnw added stuff from Whitesmiths std.h +01a,15Feb83,dnw written +*/ + +#ifndef INCvxWorksh +#define INCvxWorksh + +#if !defined(NULL) || (NULL!=0) +#define NULL 0 +#endif + +#if !defined(EOF) || (EOF!=(-1)) +#define EOF (-1) +#endif + +#if !defined(FALSE) || (FALSE!=0) +#define FALSE 0 +#endif + +#if !defined(TRUE) || (TRUE!=1) +#define TRUE 1 +#endif + + +#define NONE (-1) /* for times when NULL won't do */ +#define EOS '\0' /* C string terminator */ + + +/* return status values */ + +#define OK 0 +#define ERROR (-1) + +/* timeout defines */ + +#define NO_WAIT 0 +#define WAIT_FOREVER (-1) + +/* low-level I/O input, output, error fd's */ + +#define STD_IN 0 +#define STD_OUT 1 +#define STD_ERR 2 + +/* modes - must match O_RDONLY/O_WRONLY/O_RDWR in ioLib.h! */ + +#define READ 0 +#define WRITE 1 +#define UPDATE 2 + +/* SYSTEM types */ + +#define V7 1 /* ATT version 7 */ +#define SYS_V 2 /* ATT System 5 */ +#define BSD_4_2 3 /* Berkeley BSD 4.2 */ + +/* CPU types */ + +/* The Green Hills compiler pre-defines "MC68000"!! */ +#ifdef MC68000 +#undef MC68000 +#endif + +#define MC68000 1 +#define MC68010 2 +#define MC68020 3 +#define MC68030 4 +#define MC68040 5 +#define MC680X0 9 + +#define SPARC 10 + +#ifndef I960 +#define I960 20 +#endif + +#define I960KB 21 +#define I960CA 22 + +#if CPU==MC68000 || CPU==MC68010 || CPU==MC68020 || CPU==MC68030 +#define CPU_FAMILY MC680X0 +#endif /* CPU==MC68000 || CPU==MC68010 || CPU==MC68020 || CPU==MC68030 */ + +#if CPU==SPARC +#define CPU_FAMILY SPARC +#endif /* CPU==SPARC */ + +#if CPU==I960KB +#define CPU_FAMILY I960 +#endif /* CPU==I960KB */ + +#if CPU==I960CA +#define CPU_FAMILY I960 +#endif /* CPU==I960CA */ + +/* BUS types */ + +#define VME_BUS 1 +#define MULTI_BUS 2 + +/* network configuration parameters */ + +#define INET /* include internet protocols */ +#define BSD 43 /* BSD 4.3 -like OS */ +#define BSDDEBUG /* turn on debug */ +#define GATEWAY /* tables to be initialized for gateway routing */ + +/* common macros */ + +#define MSB(x) (((x) >> 8) & 0xff) /* most signif byte of 2-byte integer */ +#define LSB(x) ((x) & 0xff) /* least signif byte of 2-byte integer*/ + +#define OFFSET(structure, member) /* byte offset of member in structure*/\ + ((int) &(((structure *) 0) -> member)) + +#define MEMBER_SIZE(structure, member) /* size of a member of a structure */\ + (sizeof (((structure *) 0) -> member)) + +#define NELEMENTS(array) /* number of elements in an array */ \ + (sizeof (array) / sizeof ((array) [0])) + +#define FOREVER for (;;) + +#define max(x, y) (((x) < (y)) ? (y) : (x)) +#define min(x, y) (((x) < (y)) ? (x) : (y)) + + +/* storage class specifier definitions */ + +#define FAST register +#define IMPORT extern +#define LOCAL static + + +/* include typedefs - must come after CPU_FAMILY definitions above */ + +#include "vxTypes.h" + +#endif /* INCvxWorksh */ diff --git a/gdb/vx-share/wait.h b/gdb/vx-share/wait.h new file mode 100644 index 00000000000..bb81f5b7fac --- /dev/null +++ b/gdb/vx-share/wait.h @@ -0,0 +1,42 @@ +/* wait.h - header file for remote wait call */ + +/* +modification history +-------------------- +01a,05jun90,llk borrowed. +*/ + +/* Define how to access the structure that the wait system call stores. + On many systems, there is a structure defined for this. + But on vanilla-ish USG systems there is not. */ + +#ifndef HAVE_WAIT_STRUCT +#define WAITTYPE int +#define WIFSTOPPED(w) (((w)&0377) == 0177) +#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0) +#define WIFEXITED(w) (((w)&0377) == 0) +#define WRETCODE(w) ((w) >> 8) +#define WSTOPSIG(w) ((w) >> 8) +#define WCOREDUMP(w) (((w)&0200) != 0) +#define WTERMSIG(w) ((w) & 0177) +#define WSETEXIT(w, status) ((w) = (status)) +#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8))) +#else +#if FALSE +#ifndef ORIG + +/* don't include sys/wait.h */ + +#else ORIG +#include +#endif ORIG +#endif FALSE +#define WAITTYPE union wait +#define WRETCODE(w) (w).w_retcode +#define WSTOPSIG(w) (w).w_stopsig +#define WCOREDUMP(w) (w).w_coredump +#define WTERMSIG(w) (w).w_termsig +#define WSETEXIT(w, status) ((w).w_status = (status)) +#define WSETSTOP(w,sig) \ + ((w).w_stopsig = (sig), (w).w_coredump = 0, (w).w_termsig = 0177) +#endif diff --git a/gdb/vx-share/xdr_ld.c b/gdb/vx-share/xdr_ld.c new file mode 100644 index 00000000000..4935c3402bc --- /dev/null +++ b/gdb/vx-share/xdr_ld.c @@ -0,0 +1,82 @@ +/* xdr_ld.c - xdr routines for remote dbx interface to VxWorks */ + +/* Copyright 1984,1985,1986,1987,1988,1989 Wind River Systems, Inc. */ +/*extern char copyright_wind_river[]; static char *copyright=copyright_wind_river;*/ + +/* +modification history +-------------------- +01a,05jun90,llk extracted from xdr_dbx.c. +*/ + +/* +DESCRIPTION +This module contains the eXternal Data Representation (XDR) routines +for object files that are downloaded to VxWorks. They are used by +remote debuggers that use RPC (such as dbxWorks and vxGdb). +*/ + +#include "vxWorks.h" +#include "rpc/rpc.h" +#include "xdr_ld.h" + +/* forward declarations */ + +bool_t xdr_String(); /* xdr routine for argument list */ + + +/******************************************************************************* +* +* xdr_String - xdr routine for strings. +* +* Used by xdr_arg_info to handle the actual argument +* strings. normally calls xdr_string - but does something +* reasonable encode of null pointer. +*/ + +bool_t xdr_String (xdrs, strp) + XDR *xdrs; + char **strp; + + { + if ((*strp == NULL) & (xdrs->x_op == XDR_ENCODE)) + return(FALSE); + else + return(xdr_string(xdrs, strp, MAXSTRLEN)); + } +/******************************************************************************* +* +* xdr_ldfile - xdr routine for a single element in the load table +*/ + +bool_t xdr_ldfile (xdrs, objp) + XDR *xdrs; + ldfile *objp; + + { + if (! xdr_String(xdrs, &objp->name)) + return(FALSE); + if (! xdr_int(xdrs, &objp->txt_addr)) + return(FALSE); + if (! xdr_int(xdrs, &objp->data_addr)) + return(FALSE); + if (! xdr_int(xdrs, &objp->bss_addr)) + return(FALSE); + + return(TRUE); + } +/******************************************************************************* +* +* xdr_ldtabl - +* +* xdr routine for a list of files and load addresses loaded into VxWorks. +*/ + +bool_t xdr_ldtabl (xdrs,objp) + XDR *xdrs; + ldtabl *objp; + + { + return (xdr_array (xdrs, (char *) &objp->tbl_ent, (UINT *) &objp->tbl_size, + MAXTBLSZ, sizeof(ldfile), xdr_ldfile)); + } diff --git a/gdb/vx-share/xdr_ld.h b/gdb/vx-share/xdr_ld.h new file mode 100644 index 00000000000..8021ccf8520 --- /dev/null +++ b/gdb/vx-share/xdr_ld.h @@ -0,0 +1,41 @@ +/* xdr_ld.h - xdr for additional dbxWorks structures */ + +/* +modification history +-------------------- +01a,05jun90,llk extracted from xdr_dbx.h. +*/ + +#ifndef INCxdrldh +#define INCxdrldh + +#define MAXSTRLEN 256 +#define MAXTBLSZ 100 + +/* + * structure used to pass back the information for a single file + * loaded in VxWorks + */ +struct ldfile { + char *name; + int txt_addr; + int data_addr; + int bss_addr; +}; +typedef struct ldfile ldfile; + +/* + * structure used to return a list of all files loaded over to + * VxWorks. (VX_STATE_INQ return) + */ +struct ldtabl { + u_int tbl_size; + ldfile *tbl_ent; +}; +typedef struct ldtabl ldtabl; + + +bool_t xdr_ldfile(); +bool_t xdr_ldtabl(); + +#endif INCxdrldh diff --git a/gdb/vx-share/xdr_ptrace.c b/gdb/vx-share/xdr_ptrace.c new file mode 100644 index 00000000000..08813fcc355 --- /dev/null +++ b/gdb/vx-share/xdr_ptrace.c @@ -0,0 +1,171 @@ +/* xdr_ptrace.c - xdr routines for remote ptrace calls */ + +/* Copyright 1984,1985,1986,1987,1988,1989 Wind River Systems, Inc. */ +/* extern char copyright_wind_river[]; static char *copyright=copyright_wind_river;*/ + +/* +modification history +-------------------- +01a,05jun90,llk extracted from xdr_ptrace.h, version 01c. +*/ + +#include +#include +#include + +#define MAX_LEN 32000 + +/******************************************************************** +* +* xdr_regs_ptr - +* +* xdr routine to get regs* branch of discriminated union ptrace_info +* +*/ + +LOCAL bool_t xdr_regs_ptr(xdrs,objp) + XDR *xdrs; + struct regs **objp; + { + return (xdr_pointer(xdrs, (char **) objp, sizeof(struct regs), xdr_regs)); + } /* xdr_regs_ptr */ + +/******************************************************************** +* +* xdr_fp_status_ptr - +* +* xdr routine for fp_status * branch of discrimanated union +* +*/ + +LOCAL bool_t xdr_fp_status_ptr(xdrs,objp) + XDR *xdrs; + struct fp_status **objp; + { + return(xdr_pointer(xdrs, (char **) objp, sizeof(struct fp_status), + xdr_fp_status)); + } /* xdr_fp_status_ptr */ + +#ifndef I80960 +/******************************************************************** +* +* xdr_fpa_regs_ptr - +* +* xdr routine for fpa_regs* branch of ptrace_info +* +*/ + +LOCAL bool_t xdr_fpa_regs_ptr(xdrs,objp) + XDR *xdrs; + struct fpa_regs **objp; + { + if (! xdr_pointer(xdrs, (char **) objp, sizeof(struct fpa_regs), + xdr_fpa_regs)) + return(FALSE); + else + return(TRUE); + } /* xdr_fpa_regs_ptr */ +#endif + +/******************************************************************** +* +* xdr_c_bytes_ptr - +* +* xdr routine for counted bytes branch of ptrace_info +* +*/ + +LOCAL bool_t xdr_c_bytes_ptr(xdrs,objp) + XDR *xdrs; + C_bytes **objp; + { + return(xdr_pointer(xdrs, (char **) objp, sizeof(C_bytes), xdr_c_bytes)); + } /* xdr_c_bytes_ptr */ + +/******************************************************************** +* +* xdr_ptrace_info - +* +* xdr routine for discriminated union ptrace_info +* +*/ + +bool_t xdr_ptrace_info(xdrs,objp) + XDR *xdrs; + Ptrace_info *objp; + { + static struct xdr_discrim choices[] = + { + { (int) REGS, xdr_regs_ptr }, + { (int) FPREGS, xdr_fp_status_ptr }, +#ifndef I80960 + { (int) FPAREGS, xdr_fpa_regs_ptr }, +#endif + { (int) DATA, xdr_c_bytes_ptr }, + { __dontcare__, NULL } + }; + + return(xdr_union(xdrs, (enum_t *) &objp->ttype, + (char *) &objp->more_data, choices, xdr_void)); + } /* xdr_ptrace_info */ + +/******************************************************************** +* +* xdr_rptrace - +* +* xdr routine for remote ptrace data into server +* +*/ + +bool_t xdr_rptrace(xdrs,objp) + XDR *xdrs; + Rptrace *objp; + { + if (! xdr_int(xdrs, &objp->pid)) + return(FALSE); + if (! xdr_int(xdrs, &objp->data)) + return(FALSE); + if (! xdr_int(xdrs, &objp->addr)) + return(FALSE); + if (! xdr_ptrace_info(xdrs, &objp->info)) + return(FALSE); + + return(TRUE); + } /* xdr_rptrace */ + +/******************************************************************** +* +* xdr_ptrace_return - +* +* xdr routine for remote ptrace data returned by server +* +*/ + +bool_t xdr_ptrace_return(xdrs, objp) + XDR *xdrs; + Ptrace_return *objp; + { + if (! xdr_int(xdrs, &objp->status)) + return(FALSE); + if (! xdr_int(xdrs, &objp->errno)) + return(FALSE); + if (! xdr_ptrace_info(xdrs, &objp->info)) + return(FALSE); + + return(TRUE); + } /* xdr_ptrace_return */ + +/******************************************************************** +* +* xdr_c_bytes - +* +* xdr routine for counted bytes +* +*/ +bool_t xdr_c_bytes(xdrs,objp) + XDR *xdrs; + C_bytes *objp; + { + return(xdr_bytes(xdrs, &objp->bytes, (u_int *) &objp->len, MAX_LEN)); + } /* xdr_c_bytes */ + diff --git a/gdb/vx-share/xdr_ptrace.h b/gdb/vx-share/xdr_ptrace.h new file mode 100644 index 00000000000..1fe7ab43d19 --- /dev/null +++ b/gdb/vx-share/xdr_ptrace.h @@ -0,0 +1,68 @@ +/* xdr_ptrace.h - xdr header for remote ptrace structures */ + +/* +modification history +-------------------- +01a,05jun90,llk extracted from xdr_ptrace.h. +*/ + + +#include "xdr_regs.h" +#include "reg.h" + +/* + * Counted byte structure used by READ/WRITE TEXT/DATA + */ +struct c_bytes { + u_int len; + caddr_t bytes; +}; +typedef struct c_bytes C_bytes; + +/* + * enum for discriminated union ptrace_info + */ +enum ptype { + NOINFO = 0, /* no additional infomation */ + REGS = 1, /* regs (SETREGS) */ + FPREGS = 2, /* fp_status (SETFPREGS) */ + FPAREGS = 3, /* fpa_regs (SETFPAREGS) */ + DATA = 4, /* c_bytes (WRITETEXT/DATA)*/ +}; +typedef enum ptype ptype; + +/* + * discrimnated union for passing additional data to be + * written to the debugged process. With the exception of + * c_bytes, the structures are defined in + */ +struct ptrace_info { + ptype ttype; + caddr_t more_data; +}; +typedef struct ptrace_info Ptrace_info; + +/* + * structure passed to server on all remote ptrace calls + */ +struct rptrace { + int pid; + int data; + int addr; /* FIX! this really should be caddr_t or something */ + Ptrace_info info; +}; +typedef struct rptrace Rptrace; +/* + * structure returned by server on all remote ptrace calls + */ +struct ptrace_return { + int status; + int errno; + Ptrace_info info; +}; +typedef struct ptrace_return Ptrace_return; + +bool_t xdr_c_bytes(); +bool_t xdr_ptrace_info(); +bool_t xdr_rptrace(); +bool_t xdr_ptrace_return(); diff --git a/gdb/vx-share/xdr_rdb.c b/gdb/vx-share/xdr_rdb.c new file mode 100644 index 00000000000..3c70fbf7692 --- /dev/null +++ b/gdb/vx-share/xdr_rdb.c @@ -0,0 +1,207 @@ +/* xdr_rdb.c - xdr routines for Remote Debug interface to VxWorks */ + +/* +modification history +-------------------- +01a,21mar90,llk created using modification 01d of xdr_dbx.c. +*/ + +/* +DESCRIPTION +This module contains the eXternal Data Representation (XDR) routines +for the RDB interface for VxWorks. +*/ + +#include "vxWorks.h" +#include +#include "xdr_rdb.h" + +/* forward declarations */ + +bool_t +xdr_arg_type(xdrs, objp) + XDR *xdrs; + arg_type *objp; +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_arg_value(xdrs, objp) + XDR *xdrs; + arg_value *objp; +{ + if (!xdr_arg_type(xdrs, &objp->type)) { + return (FALSE); + } + switch (objp->type) { + case T_BYTE: + if (!xdr_char(xdrs, &objp->arg_value_u.v_byte)) { + return (FALSE); + } + break; + case T_WORD: + if (!xdr_short(xdrs, &objp->arg_value_u.v_word)) { + return (FALSE); + } + break; + case T_INT: + if (!xdr_int(xdrs, &objp->arg_value_u.v_int)) { + return (FALSE); + } + break; + case T_FLOAT: + if (!xdr_float(xdrs, &objp->arg_value_u.v_fp)) { + return (FALSE); + } + break; + case T_DOUBLE: + if (!xdr_double(xdrs, &objp->arg_value_u.v_dp)) { + return (FALSE); + } + break; + case T_UNKNOWN: + break; + } + return (TRUE); +} + +bool_t +xdr_func_call(xdrs, objp) + XDR *xdrs; + func_call *objp; +{ + if (!xdr_int(xdrs, &objp->func_addr)) { + return (FALSE); + } + if (!xdr_array(xdrs, (char **)&objp->args.args_val, (u_int *)&objp->args.args_len, MAX_FUNC_ARGS, sizeof(arg_value), xdr_arg_value)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_arg_one(xdrs, objp) + XDR *xdrs; + arg_one *objp; +{ + if (!xdr_string(xdrs, objp, MAX_ARG_LEN)) { + return (FALSE); + } + return (TRUE); +} + + + + +bool_t +xdr_arg_array(xdrs, objp) + XDR *xdrs; + arg_array *objp; +{ + if (!xdr_array(xdrs, (char **)&objp->arg_array_val, (u_int *)&objp->arg_array_len, MAX_ARG_CNT, sizeof(arg_one), xdr_arg_one)) { + return (FALSE); + } + return (TRUE); +} + +/********************************************************************* +* +* xdr_EVENT_TYPE - +* +*/ + +bool_t xdr_EVENT_TYPE(xdrs, objp) + XDR *xdrs; + EVENT_TYPE *objp; + + { + if (!xdr_enum (xdrs, (enum_t *) objp)) + return (FALSE); + return (TRUE); + } + +/********************************************************************* +* +* xdr_RDB_EVENT - +* +*/ + +bool_t xdr_RDB_EVENT (xdrs, objp) + XDR *xdrs; + RDB_EVENT *objp; + + { + if (!xdr_int (xdrs, &objp->status)) + return (FALSE); + if (!xdr_int (xdrs, &objp->taskId)) + return (FALSE); + if (!xdr_EVENT_TYPE (xdrs, &objp->eventType)) + return (FALSE); + if (!xdr_int (xdrs, &objp->sigType)) + return (FALSE); + return (TRUE); + } + +/********************************************************************* +* +* xdr_TASK_START - +* +*/ + +bool_t +xdr_TASK_START (xdrs, objp) + XDR *xdrs; + TASK_START *objp; + + { + if (!xdr_int (xdrs, &objp->status)) + return (FALSE); + if (!xdr_int (xdrs, &objp->pid)) + return (FALSE); + return (TRUE); + } + + +/********************************************************************* +* +* xdr_SYMBOL_ADDR - +* +*/ + +bool_t +xdr_SYMBOL_ADDR (xdrs, objp) + XDR *xdrs; + SYMBOL_ADDR *objp; + + { + if (!xdr_int (xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int (xdrs, &objp->addr)) + return (FALSE); + return (TRUE); + } + +/********************************************************************* +* +* xdr_SOURCE_STEP - +* +*/ + +bool_t +xdr_SOURCE_STEP (xdrs, objp) + XDR *xdrs; + SOURCE_STEP *objp; + + { + if (!xdr_int (xdrs, &objp->taskId)) + return (FALSE); + if (!xdr_u_int (xdrs, &objp->startAddr)) + return (FALSE); + if (!xdr_u_int (xdrs, &objp->endAddr)) + return (FALSE); + return (TRUE); + } diff --git a/gdb/vx-share/xdr_rdb.h b/gdb/vx-share/xdr_rdb.h new file mode 100644 index 00000000000..eebec43dc8c --- /dev/null +++ b/gdb/vx-share/xdr_rdb.h @@ -0,0 +1,132 @@ +/* xdr_rdb.h - xdr for additional rdb structures */ + +/* +modification history +-------------------- +01a,23may90,llk created using xdr_dbx.h. + added arg_array to replace arg_info. arg_info had + MAXNCMDARGS (= 100) as the max limit of char strings, + but it should be MAX_TASK_ARGS (= 10). +*/ + +#ifndef INCxdrrdbh +#define INCxdrrdbh + +enum arg_type { + T_UNKNOWN = 0, + T_BYTE = 1, + T_WORD = 2, + T_INT = 3, + T_FLOAT = 4, + T_DOUBLE = 5, +}; +typedef enum arg_type arg_type; +bool_t xdr_arg_type(); + + +struct arg_value { + arg_type type; + union { + char v_byte; + short v_word; + int v_int; + float v_fp; + double v_dp; + } arg_value_u; +}; +typedef struct arg_value arg_value; +bool_t xdr_arg_value(); + +struct func_call { + int func_addr; + struct { + u_int args_len; + arg_value *args_val; + } args; +}; +typedef struct func_call func_call; +bool_t xdr_func_call(); + + +typedef char *arg_one; +bool_t xdr_arg_one(); + + +typedef struct { + u_int arg_array_len; + arg_one *arg_array_val; +} arg_array; +bool_t xdr_arg_array(); + + +/* + * Structures used to pass structures required for + * process control but not part of the standard ptrace interface + */ + +/* + * arg_info is used to pass arguments into process start + */ +struct arg_info { + int rargc; + char **rargv; +}; +typedef struct arg_info Arg_info; + + +enum EVENT_TYPE { + EVENT_BREAK = 0, + EVENT_STOP = 1, + EVENT_EXIT = 2, + EVENT_BUS_ERR = 3, + EVENT_SUSPEND = 4, + EVENT_ZERO_DIV = 5, + EVENT_SIGNAL = 6, + EVENT_START = 7, +}; +typedef enum EVENT_TYPE EVENT_TYPE; + + +struct RDB_EVENT { + int status; + int taskId; + EVENT_TYPE eventType; + int sigType; +}; +typedef struct RDB_EVENT RDB_EVENT; + + +struct TASK_START { + int status; + int pid; +}; +typedef struct TASK_START TASK_START; + + +struct SYMBOL_ADDR { + int status; + u_int addr; +}; +typedef struct SYMBOL_ADDR SYMBOL_ADDR; + +struct SOURCE_STEP { + int taskId; + u_int startAddr; + u_int endAddr; +}; +typedef struct SOURCE_STEP SOURCE_STEP; + +#define MAX_ARG_CNT 10 +#define MAX_FUNC_ARGS 100 +#define MAX_ARG_LEN 100 + +bool_t xdr_arg_info(); +bool_t xdr_EVENT_TYPE(); +bool_t xdr_RDB_EVENT(); +bool_t xdr_TASK_START(); +bool_t xdr_SYMBOL_ADDR(); +bool_t xdr_SOURCE_STEP(); + +#define RDBPROG (u_long) 0x44444444 +#define RDBVERS (u_long) 1 +#endif INCxdrrdbh diff --git a/gdb/vx-share/xdr_regs.c b/gdb/vx-share/xdr_regs.c new file mode 100644 index 00000000000..9152423142b --- /dev/null +++ b/gdb/vx-share/xdr_regs.c @@ -0,0 +1,216 @@ +/* xdr_regs.c - xdr routines for 68k registers */ + +/* Copyright 1984,1985,1986,1987,1988,1989 Wind River Systems, Inc. */ + +/* +DESCRIPTION +This module contains the eXternal Data Representation (XDR) routines +for the GDB interface for VxWorks. +*/ + +#include +#include +#include +#include + + +#ifdef I80960 +/******************************************************************************* +* +* xdr_regs - xdr routine for i960 registers +*/ + +bool_t xdr_regs (xdrs, objp) + XDR *xdrs; + struct regs *objp; + + { + if (! xdr_opaque(xdrs, (char *) objp->r_lreg, 16 * sizeof(int))) + return(FALSE); + if (! xdr_opaque(xdrs, (char *) objp->r_greg, 16 * sizeof(int))) + return(FALSE); + if (! xdr_opaque(xdrs, (char *) &objp->r_pcw, sizeof(int))) + return(FALSE); + if (! xdr_opaque(xdrs, (char *) &objp->r_acw, sizeof(int))) + return(FALSE); + if (! xdr_opaque(xdrs, (char *) &objp->r_tcw, sizeof(int))) + return(FALSE); + + return(TRUE); + } + +/******************************************************************************* +* +* xdr_fp_status - xdr routine for i960 floating point registers +*/ + +bool_t xdr_fp_status (xdrs, objp) + XDR *xdrs; + struct fp_status *objp; + + { + unsigned int size = 4 * FP_REG_SIZE; + + /* We use xdr_bytes to indicate how many bytes of FP regs there are! */ + if (! xdr_bytes (xdrs, (char *) objp->fps_regs, &size, 4 * FP_REG_SIZE)) + return (FALSE); + return (TRUE); + } + +/******************************************************************************* +* +* xdr_ext_fp - xdr for a single fp register +*/ + +bool_t xdr_ext_fp (xdrs, objp) + XDR *xdrs; + char *objp; + + { + unsigned int size = FP_REG_SIZE; + + if (! xdr_bytes (xdrs, objp, &size, FP_REG_SIZE)) + return(FALSE); + + return(TRUE); + } +#else /* Must be 68K if it isn't i960 -- for now. FIXME! */ + +/******************************************************************************* +* +* xdr_regs - xdr routine for 68k registers +*/ + +bool_t xdr_regs (xdrs, objp) + XDR *xdrs; + struct regs *objp; + + { + if (! xdr_opaque(xdrs, (char *) objp->r_dreg, 8 * sizeof(int))) + return(FALSE); + if (! xdr_opaque(xdrs, (char *) objp->r_areg, 8 * sizeof(int))) + return(FALSE); + if (! xdr_opaque(xdrs, (char *) &objp->r_sr, sizeof(int))) + return(FALSE); + if (! xdr_opaque(xdrs, (char *) &objp->r_pc, sizeof(int))) + return(FALSE); + + return(TRUE); + } + +/******************************************************************************* +* +* xdr_ext_fp - xdr for a single fp register +*/ + +bool_t xdr_ext_fp (xdrs, objp) + XDR *xdrs; + ext_fp *objp; + + { + if (! xdr_vector(xdrs, (char *) objp->fp, 3, sizeof(int), xdr_int)) + return(FALSE); + + return(TRUE); + } +/******************************************************************************* +* +* xdr_fp_status - xdr routine for floating point registers +*/ + +bool_t xdr_fp_status (xdrs, objp) + XDR *xdrs; + struct fp_status *objp; + + { + if (! xdr_vector (xdrs, (char *) objp->fps_regs, 8, + sizeof(ext_fp), xdr_ext_fp)) + return (FALSE); + if (! xdr_int (xdrs, &objp->fps_control)) + return (FALSE); + if (! xdr_int (xdrs, &objp->fps_status)) + return (FALSE); + if (! xdr_int (xdrs, &objp->fps_iaddr)) + return (FALSE); + if (! xdr_int (xdrs, &objp->fps_code)) + return (FALSE); + if (! xdr_int (xdrs, &objp->fps_flags)) + return (FALSE); + + return (TRUE); + } +/******************************************************************************* +* +* xdr_fpa_status - xdr for fpa status +*/ + +bool_t xdr_fpa_status (xdrs, objp) + XDR *xdrs; + struct fpa_status *objp; + + { + if (! xdr_u_int (xdrs, &objp->fpas_state)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_imask)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_load_ptr)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_ierr)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_act_instr)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_nxt_instr)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_act_d1half)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_act_d2half)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_nxt_d1half)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_nxt_d2half)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_mode3_0)) + return (FALSE); + if (! xdr_u_int (xdrs, &objp->fpas_wstatus)) + return (FALSE); + + return (TRUE); + } +/******************************************************************************* +* +* xdr_fpa_long - xdr for fpa data register +*/ + +bool_t xdr_fpa_long (xdrs,objp) + XDR *xdrs; + fpa_long *objp; + + { + if (! xdr_vector (xdrs, (char *) objp->fpl_data, 2, sizeof(int), xdr_int)) + return (FALSE); + + return (TRUE); + } +/******************************************************************************* +* +* xdr_fpa_regs - xdr for fpa_regs +*/ + +bool_t xdr_fpa_regs (xdrs, objp) + XDR *xdrs; + struct fpa_regs *objp; + + { + if (! xdr_u_int (xdrs, &objp->fpar_flags)) + return (FALSE); + if (! xdr_fpa_status (xdrs, &objp->fpar_status)) + return (FALSE); + if (! xdr_vector (xdrs, (char *) objp->fpar_data, + FPA_NDATA_REGS, sizeof(fpa_long), xdr_fpa_long)) + return (FALSE); + + return (TRUE); + } + +#endif /* I80960 */ + diff --git a/gdb/vx-share/xdr_regs.h b/gdb/vx-share/xdr_regs.h new file mode 100644 index 00000000000..c829d643493 --- /dev/null +++ b/gdb/vx-share/xdr_regs.h @@ -0,0 +1,16 @@ +/* xdr_regs.h - xdr header for 68k registers */ + +/* +modification history +-------------------- +01a,05jun90,llk extracted from xdr_regs.h. +*/ + +/* xdr structures are defined in reg.h (a bad place for them, i might add) */ + +bool_t xdr_regs(); +bool_t xdr_ext_fp(); +bool_t xdr_fp_status(); +bool_t xdr_fpa_status(); +bool_t xdr_fpa_long(); +bool_t xdr_fpa_regs(); diff --git a/gdb/xm-3b1.h b/gdb/xm-3b1.h new file mode 100644 index 00000000000..6efef40dad7 --- /dev/null +++ b/gdb/xm-3b1.h @@ -0,0 +1,87 @@ +/* Parameters for execution on a 3b1. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +#define HAVE_TERMIO +#define USG + +#define MAXPATHLEN 200 + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR 0x70000 + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ addr = blockend + regno * 4; } + +/* 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 ("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"); } + +#endif diff --git a/gdb/xm-altos.h b/gdb/xm-altos.h new file mode 100644 index 00000000000..3a4dc5fba91 --- /dev/null +++ b/gdb/xm-altos.h @@ -0,0 +1,208 @@ +/* Definitions to make GDB run on an Altos 3068 (m68k running SVR2) + Copyright (C) 1987,1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* The altos support would make a good base for a port to other USGR2 systems + (like the 3b1 and the Convergent miniframe). */ + +/* This is only needed in one file, but it's cleaner to put it here than + putting in more #ifdef's. */ +#include +#include + +#define USG + +#define HAVE_TERMIO + +#define CBREAK XTABS /* It takes all kinds... */ + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_OK 0 +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN (1024) +#endif + +/* Get sys/wait.h ie. from a Sun and edit it a little (mc68000 to m68k) */ +/* Why bother? */ +#if 0 +#define HAVE_WAIT_STRUCT +#endif + +#define vfork fork + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR 0x1fbf000 + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ if (regno <= SP_REGNUM) \ + addr = blockend + regno * 4; \ + else if (regno == PS_REGNUM) \ + addr = blockend + regno * 4 + 4; \ + else if (regno == PC_REGNUM) \ + addr = blockend + regno * 4 + 2; \ +} + +#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))) + + +#ifndef __GNUC__ +#undef USE_GAS +#define ALTOS_AS +#else +#define USE_GAS +#endif + +/* Motorola assembly format */ +#if !defined(USE_GAS) && !defined(ALTOS) +#define MOTOROLA +#endif + +/* 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. */ + +#ifdef MOTOROLA +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("move.l $ end, sp"); \ + asm ("clr.l fp"); } +#else +#ifdef ALTOS_AS +#define INIT_STACK(beg, end) \ +{ asm ("global end"); \ + asm ("mov.l &end,%sp"); \ + asm ("clr.l %fp"); } +#else +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movel $ end, sp"); \ + asm ("clrl fp"); } +#endif +#endif + +/* Push the frame pointer register on the stack. */ +#ifdef MOTOROLA +#define PUSH_FRAME_PTR \ + asm ("move.l fp, -(sp)"); +#else +#ifdef ALTOS_AS +#define PUSH_FRAME_PTR \ + asm ("mov.l %fp, -(%sp)"); +#else +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); +#endif +#endif + +/* Copy the top-of-stack to the frame pointer register. */ +#ifdef MOTOROLA +#define POP_FRAME_PTR \ + asm ("move.l (sp), fp"); +#else +#ifdef ALTOS_AS +#define POP_FRAME_PTR \ + asm ("mov.l (%sp), %fp"); +#else +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); +#endif +#endif + +/* 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. */ + +#ifdef MOTOROLA +#define PUSH_REGISTERS \ +{ asm ("clr.w -(sp)"); \ + asm ("pea (10,sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } +#else +#ifdef ALTOS_AS +#define PUSH_REGISTERS \ +{ asm ("clr.w -(%sp)"); \ + asm ("pea (10,%sp)"); \ + asm ("movm.l &0xfffe,-(%sp)"); } +#else +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } +#endif +#endif + +/* 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. */ + +#ifdef MOTOROLA +#define POP_REGISTERS \ +{ asm ("subi.l $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } +#else +#ifdef ALTOS_AS +#define POP_REGISTERS \ +{ asm ("sub.l &8,28(%sp)"); \ + asm ("movem (%sp),&0xffff"); \ + asm ("rte"); } +#else +#define POP_REGISTERS \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } +#endif +#endif diff --git a/gdb/xm-arm.h b/gdb/xm-arm.h new file mode 100644 index 00000000000..3251faefd06 --- /dev/null +++ b/gdb/xm-arm.h @@ -0,0 +1,88 @@ +/* Definitions to make GDB run on an ARM under RISCiX (4.3bsd). + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR (0x01000000 - (UPAGES * NBPG)) + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + + +#if 0 +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \ + 0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movl $ end, sp"); \ + asm ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("pushl fp"); + +/* 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 ("pushl 8(sp)"); \ + asm ("pushl 8(sp)"); \ + asm ("pushal 0x14(sp)"); \ + asm ("pushr $037777"); } + +/* 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 ("popr $037777"); \ + asm ("subl2 $8,(sp)"); \ + asm ("movl (sp),sp"); \ + asm ("rei"); } +#endif /* 0 */ diff --git a/gdb/xm-bigmips.h b/gdb/xm-bigmips.h new file mode 100644 index 00000000000..0c1102d10d0 --- /dev/null +++ b/gdb/xm-bigmips.h @@ -0,0 +1,21 @@ +/* Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +#include "xm-mips.h" diff --git a/gdb/xm-convex.h b/gdb/xm-convex.h new file mode 100644 index 00000000000..ed102bb2209 --- /dev/null +++ b/gdb/xm-convex.h @@ -0,0 +1,51 @@ +/* Definitions to make GDB run on Convex Unix (4bsd) + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +#define LONG_LONG +#define ATTACH_DETACH +#define HAVE_WAIT_STRUCT +#define NO_SIGINTERRUPT + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* Use SIGCONT rather than SIGTSTP because convex Unix occasionally + turkeys SIGTSTP. I think. */ + +#define STOP_SIGNAL SIGCONT + +/* Use csh to do argument expansion so we get ~ and such. */ + +/* Doesn't work. */ +/* #define SHELL_FILE "/bin/csh" */ + +/* Compensate for lack of `vprintf' function. */ +#define MISSING_VPRINTF + +/* Hook to call after creating inferior process. */ + +#define CREATE_INFERIOR_HOOK create_inferior_hook + + +/* Interface definitions for kernel debugger KDB. */ + +/* (no kdb) */ diff --git a/gdb/xm-hp300bsd.h b/gdb/xm-hp300bsd.h new file mode 100644 index 00000000000..4ae5a5cbbc9 --- /dev/null +++ b/gdb/xm-hp300bsd.h @@ -0,0 +1,113 @@ +/* Parameters for execution on a Hewlett-Packard 9000/300, running bsd. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Configuration file for HP9000/300 series machine running + * University of Utah's 4.3bsd port. This is NOT for HP-UX. + * Problems to hpbsd-bugs@cs.utah.edu + */ + +#include + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* Get kernel u area address at run-time using BSD style nlist (). */ +#define KERNEL_U_ADDR_BSD + +/* This is a piece of magic that is given a register number REGNO + and as BLOCKEND the address in the system of the end of the user structure + and stores in ADDR the address in the kernel or core dump + of that register. */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ \ + if (regno < PS_REGNUM) \ + addr = (int) &((struct frame *)(blockend))->f_regs[regno]; \ + else if (regno == PS_REGNUM) \ + addr = (int) &((struct frame *)(blockend))->f_stackadj; \ + else if (regno == PC_REGNUM) \ + addr = (int) &((struct frame *)(blockend))->f_pc; \ + else if (regno < FPC_REGNUM) \ + addr = (int) \ + &((struct user *)0)->u_pcb.pcb_fpregs.fpf_regs[((regno)-FP0_REGNUM)*3];\ + else if (regno == FPC_REGNUM) \ + addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpcr; \ + else if (regno == FPS_REGNUM) \ + addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpsr; \ + else \ + addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpiar; \ +} + +/* Compensate for lack of `vprintf' function. */ +#define MISSING_VPRINTF + + +/* 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"); } diff --git a/gdb/xm-hp300hpux.h b/gdb/xm-hp300hpux.h new file mode 100644 index 00000000000..6583748b494 --- /dev/null +++ b/gdb/xm-hp300hpux.h @@ -0,0 +1,173 @@ +/* Parameters for execution on an HP 9000 model 320, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* Define this to indicate problems with traps after continuing. */ +#define HP_OS_BUG + +/* fetch_inferior_registers is in hp300hpux-dep.c. */ +#define FETCH_INFERIOR_REGISTERS + +/* Set flag to indicate whether HP's assembler is in use. */ +#ifdef __GNUC__ +#ifdef __HPUX_ASM__ +#define HPUX_ASM +#endif +#else /* not GNU C. */ +#define HPUX_ASM +#endif /* not GNU C. */ + +/* 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 */ +#undef USG /* In case it was defined in the Makefile for cplus-dem.c */ +#define USG + +#define HAVE_TERMIO + +/* Get rid of any system-imposed stack limit if possible. */ +/* The hp9k320.h doesn't seem to have this feature. */ +/* #define SET_STACK_LIMIT_HUGE */ +/* So we'll just have to avoid big alloca's. */ +#define BROKEN_LARGE_ALLOCA + +/* 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 /* Not HPUX version 5. */ +/* Use HPUX-style nlist() to get kernel_u_addr. */ +#define KERNEL_U_ADDR_HPUX +#endif /* Not HPUX version 5. */ + +#define REGISTER_ADDR(u_ar0, regno) \ + (unsigned int) \ + (((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))) + +/* Do implement the attach and detach commands. */ + +#define ATTACH_DETACH + +/* 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 */ diff --git a/gdb/xm-i386v.h b/gdb/xm-i386v.h new file mode 100644 index 00000000000..840cb581d08 --- /dev/null +++ b/gdb/xm-i386v.h @@ -0,0 +1,99 @@ +/* Macro defintions for i386. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* I'm running gdb 3.4 under 386/ix 2.0.2, which is a derivative of AT&T's +Sys V/386 3.2. + +On some machines, gdb crashes when it's starting up while calling the +vendor's termio tgetent() routine. It always works when run under +itself (actually, under 3.2, it's not an infinitely recursive bug.) +After some poking around, it appears that depending on the environment +size, or whether you're running YP, or the phase of the moon or something, +the stack is not always long-aligned when main() is called, and tgetent() +takes strong offense at that. On some machines this bug never appears, but +on those where it does, it occurs quite reliably. */ +#define ALIGN_STACK_ON_STARTUP + +/* define USG if you are using sys5 /usr/include's */ +#define USG + +/* USG systems need these */ +#define vfork() fork() +#define MAXPATHLEN 500 + +#define HAVE_TERMIO + +/* Get rid of any system-imposed stack limit if possible. */ + +/* #define SET_STACK_LIMIT_HUGE not in sys5 */ + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR 0xe0000000 + + +#if 0 +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) {} + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR {} + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR {} + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS {} + +/* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + +#define POP_REGISTERS {} +#endif /* 0 */ diff --git a/gdb/xm-i386v32.h b/gdb/xm-i386v32.h new file mode 100644 index 00000000000..b343be0c77f --- /dev/null +++ b/gdb/xm-i386v32.h @@ -0,0 +1,28 @@ +/* Macro defintions for i386, running System V 3.2. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "xm-i386v.h" + +/* Apparently there is inconsistency among various System V's about what + the name of this field is. */ +#define U_FPSTATE(u) u.u_fps.u_fpstate + +/* TIOCGETC is defined in System V 3.2 termio.h, but struct tchars + is not. This makes problems for inflow.c. */ +#define TIOCGETC_BROKEN diff --git a/gdb/xm-isi.h b/gdb/xm-isi.h new file mode 100644 index 00000000000..21c0134616d --- /dev/null +++ b/gdb/xm-isi.h @@ -0,0 +1,95 @@ +/* Definitions to make GDB run on an ISI Optimum V (3.05) under 4.3bsd. + Copyright (C) 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* This has not been tested on ISI's running BSD 4.2, but it will probably + work. */ + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +/*#define KERNEL_U_ADDR 0x10800000*/ +#define KERNEL_U_ADDR 0 + +/* expects blockend to be u.u_ar0 */ +extern int rloc[]; /* Defined in isi-dep.c */ +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ blockend &= UPAGES*NBPG - 1; \ + if (regno < 18) addr = (int)blockend + rloc[regno]*4; \ + else if (regno < 26) addr = (int) &((struct user *)0)->u_68881_regs \ + + (regno - 18) * 12; \ + else if (regno < 29) addr = (int) &((struct user *)0)->u_68881_regs \ + + 8 * 12 + (regno - 26) * 4; \ +} + +/* Compensate for lack of `vprintf' function. */ +#define MISSING_VPRINTF + +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movl $ end, sp"); \ + asm ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } + +/* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + +#define POP_REGISTERS \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } diff --git a/gdb/xm-m88k.h b/gdb/xm-m88k.h new file mode 100644 index 00000000000..240459bc89f --- /dev/null +++ b/gdb/xm-m88k.h @@ -0,0 +1,124 @@ +/* Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This is currently for a 88000 running DGUX. If other 88k ports are + done, OS-specific stuff should be moved (see tm-68k.h, for example). */ +/* g++ support is not yet included. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +#define USG +/* DGUX has bcopy(), etc. */ +#define USG_UTILS 0 + +#include + +#define vfork() fork() +#define index strchr +#define rindex strrchr +#define getwd(BUF) getcwd(BUF,MAXPATHLEN); +#define bzero(ptr,count) (memset((ptr),0,(count))) +#define bcopy(src,dst,count) (memcpy((dst),(src),(count))) +#define bcmp(left,right,count) (memcmp((right),(left),(count))) +#ifdef __GNUC__ +#define memcpy __builtin_memcpy +#define memset __builtin_memset +#define strcmp __builtin_strcmp +#endif + +#ifdef DGUX +#define x_foff _x_x._x_offset +#define x_fname _x_name +#define USER ptrace_user +#define _BSD_WAIT_FLAVOR +#endif + +#define HAVE_TERMIO + + +#define USIZE 2048 +#define NBPG NBPC +#define UPAGES USIZE + +#define HAVE_GETPAGESIZE + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* number of traps that happen between exec'ing the shell + * to run an inferior, and when we finally get to + * the inferior code. This is 2 on most implementations. + */ +#define START_INFERIOR_TRAPS_EXPECTED 2 + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +/* Since registers r0 through r31 are stored directly in the struct ptrace_user, + (for m88k BCS) + the ptrace_user offsets are sufficient and KERNEL_U_ADDRESS can be 0 */ + +#define KERNEL_U_ADDR 0 + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = m88k_register_u_addr ((blockend),(regno)); + +#define HAVE_WAIT_STRUCT + +#define FETCH_INFERIOR_REGISTERS + +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) {} + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR {} + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR {} + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS {} + +/* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + +#define POP_REGISTERS {} diff --git a/gdb/xm-merlin.h b/gdb/xm-merlin.h new file mode 100644 index 00000000000..54c1bafe8e9 --- /dev/null +++ b/gdb/xm-merlin.h @@ -0,0 +1,120 @@ +/* Definitions to make GDB run on a merlin under utek 2.1 + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This machine doesn't have the siginterrupt call. */ +#define NO_SIGINTERRUPT + +/* Under Utek, a ptrace'd process can be the only active process for + an executable. Therefore instead of /bin/sh use gdb-sh (which should + just be a copy of /bin/sh which is world readable and writeable). */ +#define SHELL_FILE "/usr/gnu/lib/gdb-sh" + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR (0xfef000) + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ \ + switch (regno) { \ + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: \ + addr = blockend + (R0 - regno) * sizeof (int); break; \ + case PC_REGNUM: \ + addr = blockend + PC * sizeof (int); break; \ + case SP_REGNUM: \ + addr = blockend + SP * sizeof (int); break; \ + case FP_REGNUM: \ + addr = blockend + FP * sizeof (int); break; \ + case PS_REGNUM: \ + addr = blockend + 12 * sizeof (int); break; \ + case FPS_REGNUM: \ + addr = 108; break; \ + case FP0_REGNUM + 0: case FP0_REGNUM + 1: \ + case FP0_REGNUM + 2: case FP0_REGNUM + 3: \ + case FP0_REGNUM + 4: case FP0_REGNUM + 5: \ + case FP0_REGNUM + 6: case FP0_REGNUM + 7: \ + addr = 76 + (regno - FP0_REGNUM) * sizeof (float); break; \ + case LP0_REGNUM + 0: case LP0_REGNUM + 1: \ + case LP0_REGNUM + 2: case LP0_REGNUM + 3: \ + addr = 76 + (regno - LP0_REGNUM) * sizeof (double); break; \ + default: \ + printf ("bad argument to REGISTER_U_ADDR %d\n", regno); \ + abort (); \ + } \ +} + +/* Compensate for lack of `vprintf' function. */ +#define MISSING_VPRINTF + +#if 0 +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \ + 0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movl $ end, sp"); \ + asm ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("pushl fp"); + +/* 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 ("pushl 8(sp)"); \ + asm ("pushl 8(sp)"); \ + asm ("pushal 0x14(sp)"); \ + asm ("pushr $037777"); } + +/* 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 ("popr $037777"); \ + asm ("subl2 $8,(sp)"); \ + asm ("movl (sp),sp"); \ + asm ("rei"); } +#endif /* 0 */ diff --git a/gdb/xm-mips.h b/gdb/xm-mips.h new file mode 100644 index 00000000000..3f7fce27a3b --- /dev/null +++ b/gdb/xm-mips.h @@ -0,0 +1,44 @@ +/* Definitions to make GDB run on a mips box under 4.3bsd. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + Contributed by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin + and by Alessandro Forin(af@cs.cmu.edu) at CMU + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (HOST_BYTE_ORDER) +#define HOST_BYTE_ORDER LITTLE_ENDIAN +#endif + +/* wait.h */ +#define HAVE_WAIT_STRUCT + +/* Get rid of any system-imposed stack limit if possible */ + +#define SET_STACK_LIMIT_HUGE + +/* This WOULD BE the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. + But Mips' ptrace works on regnums, not displacements */ + +#define KERNEL_U_ADDR (int)u.u_ar0 + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + +/* Interface definitions for kernel debugger KDB */ + +/* I am not going to pretend I've done anything about this */ diff --git a/gdb/xm-news.h b/gdb/xm-news.h new file mode 100644 index 00000000000..1c5c6f15d1f --- /dev/null +++ b/gdb/xm-news.h @@ -0,0 +1,143 @@ +/* Parameters for execution on a Sony/NEWS, for GDB, the GNU debugger. + Copyright (C) 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +#define HAVE_WAIT_STRUCT + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* We can't use "isatty" or "fileno" on this machine. This isn't good, + but it will have to do. */ +#define ISATTY(FP) ((FP) == stdin || (FP) == stdout) + +/* THis is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR UADDR + +/* The offsets in this macro are from /usr/include/machine/reg.h */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ static char offsets[] = { \ + /*d0-d7:*/1,2,3,4,5,6,7,8, \ + /*a0-a6:*/9,10,11,12,13,14,15, /*sp:*/-4, /*ps:*/0, /*pc:*/-1, \ + /*fp0-fp7:*/19,22,25,28,31,34,37,40, /*fpc:*/16,17,18 }; \ + addr = blockend + 4 * offsets[regno]; \ +} + +/* Compensate for lack of `vprintf' function. */ +#define MISSING_VPRINTF + +/* NewsOS 3 apparently dies on large alloca's -- roland@ai.mit.edu. */ +#define BROKEN_LARGE_ALLOCA + + +/* Interface definitions for kernel debugger KDB. */ + +/* Use GNU assembler instead of standard assembler */ +#define USE_GAS + +/* Motorola assembly format */ +#ifndef USE_GAS +#define MOTOROLA +#endif + +/* 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. */ + +#ifdef MOTOROLA +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("move.l $ end, sp"); \ + asm ("clr.l fp"); } +#else +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movel $ end, sp"); \ + asm ("clrl fp"); } +#endif + +/* Push the frame pointer register on the stack. */ +#ifdef MOTOROLA +#define PUSH_FRAME_PTR \ + asm ("move.l fp, -(sp)"); +#else +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); +#endif + +/* Copy the top-of-stack to the frame pointer register. */ +#ifdef MOTOROLA +#define POP_FRAME_PTR \ + asm ("move.l (sp), fp"); +#else +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); +#endif + +/* 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. */ + +#ifdef MOTOROLA +#define PUSH_REGISTERS \ +{ asm ("clr.w -(sp)"); \ + asm ("pea (10,sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } +#else +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } +#endif + +/* 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. */ + +#ifdef MOTOROLA +#define POP_REGISTERS \ +{ asm ("subi.l $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } +#else +#define POP_REGISTERS \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } +#endif diff --git a/gdb/xm-news1000.h b/gdb/xm-news1000.h new file mode 100644 index 00000000000..aade8987406 --- /dev/null +++ b/gdb/xm-news1000.h @@ -0,0 +1,26 @@ +/* Parameters for a Sony/NEWS series 1000 with News-OS version 3, + for GDB, the GNU debugger. + Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This is required by Sony include files like so we + get the right offset into the u area. Relying on the compiler + to define this only works for cc, not gcc. */ +#undef mc68030 +#define mc68030 +#include "xm-news.h" diff --git a/gdb/xm-np1.h b/gdb/xm-np1.h new file mode 100644 index 00000000000..0608e363378 --- /dev/null +++ b/gdb/xm-np1.h @@ -0,0 +1,99 @@ +/* Parameters for execution on a Gould NP1, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* Get rid of any system-imposed stack limit if possible. */ +#define SET_STACK_LIMIT_HUGE + +/* Address of U in kernel space */ +#define KERNEL_U_ADDR 0x7fffc000 + +/* 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) { \ + addr = blockend + regno * 4; \ + if (regno == VE_REGNUM) addr = blockend - 9 * 4; \ + if (regno == PC_REGNUM) addr = blockend - 8 * 4; \ + if (regno == PS_REGNUM) addr = blockend - 7 * 4; \ + if (regno == FP_REGNUM) addr = blockend - 6 * 4; \ + if (regno >= V1_REGNUM) \ + addr = blockend + 16 * 4 + (regno - V1_REGNUM) * VR_SIZE; \ +} + +/* Don't try to write the frame pointer. */ +#define CANNOT_STORE_REGISTER(regno) ((regno) == FP_REGNUM) + +#define MISSING_VPRINTF + +/* + * No KDB support, Yet! */ +/* 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 ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } + +/* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + +#define POP_REGISTERS \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } diff --git a/gdb/xm-pn.h b/gdb/xm-pn.h new file mode 100644 index 00000000000..f9fa9864ead --- /dev/null +++ b/gdb/xm-pn.h @@ -0,0 +1,82 @@ +/* Parameters for execution on a Gould PN, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* Get rid of any system-imposed stack limit if possible. */ +#define SET_STACK_LIMIT_HUGE + +#define MISSING_VPRINTF + +/* Address of U in kernel space */ +#define KERNEL_U_ADDR 0x3fc000 + +/* + * No KDB support, Yet! */ +/* 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 ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } + +/* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + +#define POP_REGISTERS \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } diff --git a/gdb/xm-pyr.h b/gdb/xm-pyr.h new file mode 100644 index 00000000000..8a01569a15f --- /dev/null +++ b/gdb/xm-pyr.h @@ -0,0 +1,105 @@ +/* Definitions to make GDB run on a Pyramidax under OSx 4.0 (4.2bsd). + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* Define PYRAMID_CONTROL_FRAME_DEBUGGING to get copious messages + about reading the control stack on standard output. This + makes gdb unusable as a debugger. */ + +/* #define PYRAMID_CONTROL_FRAME_DEBUGGING */ + +/* Define PYRAMID_FRAME_DEBUGGING for ? */ + +/* use Pyramid's slightly strange ptrace */ +#define PYRAMID_PTRACE + +/* Traditional Unix virtual address spaces have thre regions: text, + data and stack. The text, initialised data, and uninitialised data + are represented in separate segments of the a.out file. + When a process dumps core, the data and stack regions are written + to a core file. This gives a debugger enough information to + reconstruct (and debug) the virtual address space at the time of + the coredump. + Pyramids have an distinct fourth region of the virtual address + space, in which the contents of the windowed registers are stacked + in fixed-size frames. Pyramid refer to this region as the control + stack. Each call (or trap) automatically allocates a new register + frame; each return deallocates the current frame and restores the + windowed registers to their values before the call. + + When dumping core, the control stack is written to a core files as + a third segment. The core-handling functions need to know to deal + with it. */ + +/* Tell dep.c what the extra segment is. */ +#define PYRAMID_CORE + +#define NO_SIGINTERRUPT + +#define HAVE_WAIT_STRUCT + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR (0x80000000 - (UPAGES * NBPG)) + +/* Define offsets of registers in the core file (or maybe u area) */ +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ struct user __u; \ + addr = blockend + (regno - 16 ) * 4; \ + if (regno == 67) { \ + printf("\\geting reg 67\\"); \ + addr = (int)(&__u.u_pcb.pcb_csp) - (int) &__u; \ + } else if (regno == KSP_REGNUM) { \ + printf("\\geting KSP (reg %d)\\", KSP_REGNUM); \ + addr = (int)(&__u.u_pcb.pcb_ksp) - (int) &__u; \ + } else if (regno == CSP_REGNUM) { \ + printf("\\geting CSP (reg %d\\",CSP_REGNUM); \ + addr = (int)(&__u.u_pcb.pcb_csp) - (int) &__u; \ + } else if (regno == 64) { \ + printf("\\geting reg 64\\"); \ + addr = (int)(&__u.u_pcb.pcb_csp) - (int) &__u; \ + } else if (regno == PS_REGNUM) \ + addr = blockend - 4; \ + else if (1 && ((16 > regno) && (regno > 11))) \ + addr = last_frame_offset + (4 *(regno+32)); \ + else if (0 && (12 > regno)) \ + addr = global_reg_offset + (4 *regno); \ + else if (16 > regno) \ + addr = global_reg_offset + (4 *regno); \ + else \ + addr = blockend + (regno - 16 ) * 4; \ +} + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + +/* Compensate for lack of `vprintf' function. */ +#define MISSING_VPRINTF + + +/* Interface definitions for kernel debugger KDB. */ + +/* I have *no idea* how to debug OSx kernels, so this + is flushed, possible forever. */ diff --git a/gdb/xm-sparc.h b/gdb/xm-sparc.h new file mode 100644 index 00000000000..c8b9b349252 --- /dev/null +++ b/gdb/xm-sparc.h @@ -0,0 +1,60 @@ +/* Parameters for execution on a Sun 4, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* 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 + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ + +#define FETCH_INFERIOR_REGISTERS + +/* Before storing, we need to read all the registers. */ + +#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) + +/* It does have a wait structure, and it might help things out . . . */ + +#define HAVE_WAIT_STRUCT + +/* Optimization for storing registers to the inferior. The hook + DO_DEFERRED_STORES + actually executes any deferred stores. It is called any time + we are going to proceed the child, or read its registers. + The hook CLEAR_DEFERRED_STORES is called when we want to throw + away the inferior process, e.g. when it dies or we kill it. + FIXME, this does not handle remote debugging cleanly. */ + +extern int deferred_stores; +extern int store_inferior_registers (); +#define DO_DEFERRED_STORES \ + if (deferred_stores) \ + store_inferior_registers (-2); +#define CLEAR_DEFERRED_STORES \ + deferred_stores = 0; diff --git a/gdb/xm-sun2.h b/gdb/xm-sun2.h new file mode 100644 index 00000000000..278198a56fe --- /dev/null +++ b/gdb/xm-sun2.h @@ -0,0 +1,96 @@ +/* Parameters for execution on a Sun, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR 0x2800 + +/* 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 + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + +/* 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) \ +{ addr = blockend + regno * 4; } + +/* 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 ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } + +/* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + +#define POP_REGISTERS \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } diff --git a/gdb/xm-sun3.h b/gdb/xm-sun3.h new file mode 100644 index 00000000000..e67cc134ea5 --- /dev/null +++ b/gdb/xm-sun3.h @@ -0,0 +1,93 @@ +/* Parameters for execution on a Sun, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* 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 + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ + +#define FETCH_INFERIOR_REGISTERS + +/* We have to grab the regs since we store all regs at once. */ + +#define CHILD_PREPARE_TO_STORE() \ + read_register_bytes (0, (char *)NULL, REGISTER_BYTES) + +/* 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"); } diff --git a/gdb/xm-sun386.h b/gdb/xm-sun386.h new file mode 100644 index 00000000000..69b367324a9 --- /dev/null +++ b/gdb/xm-sun386.h @@ -0,0 +1,37 @@ +/* Parameters for execution on a Sun 386i, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* 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 + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + +#define PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) diff --git a/gdb/xm-sun3os4.h b/gdb/xm-sun3os4.h new file mode 100644 index 00000000000..b9ffc8d8aed --- /dev/null +++ b/gdb/xm-sun3os4.h @@ -0,0 +1,28 @@ +/* Macro definitions for a sun 3 running os 4. + Copyright (C) 1989, Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "xm-sun3.h" +#define FPU + +/* There is a bug which can cause alloca to fail to allocate large + areas of memory one time in every 4096 (we think). */ +/* chase@orc.olivetti.com says that 4 megabyte alloca's consistently fail, + even though the stack limit (SET_STACK_LIMIT_HUGE) has been set + to 250 megabytes. */ +#define BROKEN_LARGE_ALLOCA diff --git a/gdb/xm-sun4os4.h b/gdb/xm-sun4os4.h new file mode 100644 index 00000000000..eaf74738062 --- /dev/null +++ b/gdb/xm-sun4os4.h @@ -0,0 +1,22 @@ +/* Macro definitions for running gdb on a Sun 4 running sunos 4. + Copyright (C) 1989, Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "xm-sparc.h" + +#define FPU diff --git a/gdb/xm-symmetry.h b/gdb/xm-symmetry.h new file mode 100644 index 00000000000..c941cf05d1e --- /dev/null +++ b/gdb/xm-symmetry.h @@ -0,0 +1,152 @@ +/* Definitions to make GDB run on a Sequent Symmetry under dynix 3.0, + with Weitek 1167 and i387 support. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Symmetry version by Jay Vosburgh (uunet!sequent!fubar) */ + +/* This machine doesn't have the siginterrupt call. */ +#define NO_SIGINTERRUPT + +#define HAVE_WAIT_STRUCT + +/* XPT_DEBUG doesn't work yet under Dynix 3.0.12, but UNDEBUG does... */ +/* #define PTRACE_ATTACH XPT_DEBUG +#define PTRACE_DETACH XPT_UNDEBUG +#define ATTACH_DETACH */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR (0x80000000 - (UPAGES * NBPG)) + +/* Compensate for lack of `vprintf' function. */ + +#define MISSING_VPRINTF + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ + +#define FETCH_INFERIOR_REGISTERS + +/* We must fetch all the regs before storing, since we store all at once. */ + +#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) + +/* Interface definitions for kernel debugger KDB. */ +/* This doesn't work... */ +/* 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, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \ + 0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movl $ end, %esp"); \ + asm ("movl %ebp, $0"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("pushl %ebp"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl (%esp), %ebp"); + +/* 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("pushad"); } +/* +{ asm("pushl %eax"); \ + asm("pushl %edx"); \ + asm("pushl %ecx"); \ + asm("pushl %st(0)"); \ + asm("pushl %st(1)"); \ + asm("pushl %ebx"); \ + asm("pushl %esi"); \ + asm("pushl %edi"); \ + asm("pushl %st(2)"); \ + asm("pushl %st(3)"); \ + asm("pushl %st(4)"); \ + asm("pushl %st(5)"); \ + asm("pushl %st(6)"); \ + asm("pushl %st(7)"); \ + asm("pushl %esp"); \ + asm("pushl %ebp"); \ + asm("pushl %eip"); \ + asm("pushl %eflags"); \ + asm("pushl %fp1"); \ + asm("pushl %fp2"); \ + asm("pushl %fp3"); \ + asm("pushl %fp4"); \ + asm("pushl %fp5"); \ + asm("pushl %fp6"); \ + asm("pushl %fp7"); \ + asm("pushl %fp8"); \ + asm("pushl %fp9"); \ + asm("pushl %fp10"); \ + asm("pushl %fp11"); \ + asm("pushl %fp12"); \ + asm("pushl %fp13"); \ + asm("pushl %fp14"); \ + asm("pushl %fp15"); \ + asm("pushl %fp16"); \ + asm("pushl %fp17"); \ + asm("pushl %fp18"); \ + asm("pushl %fp19"); \ + asm("pushl %fp20"); \ + asm("pushl %fp21"); \ + asm("pushl %fp22"); \ + asm("pushl %fp23"); \ + asm("pushl %fp24"); \ + asm("pushl %fp25"); \ + asm("pushl %fp26"); \ + asm("pushl %fp27"); \ + asm("pushl %fp28"); \ + asm("pushl %fp29"); \ + asm("pushl %fp30"); \ + asm("pushl %fp31"); \ +} +*/ +/* 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 ("popad"); } diff --git a/gdb/xm-umax.h b/gdb/xm-umax.h new file mode 100644 index 00000000000..873e8082858 --- /dev/null +++ b/gdb/xm-umax.h @@ -0,0 +1,64 @@ +/* Definitions to make GDB run on an encore under umax 4.2 + Copyright (C) 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +#define HAVE_WAIT_STRUCT + +/* Offset of registers within u area. */ +#define U_REGS_OFFSET 0 + +/* Do implement the attach and detach commands... */ +#define ATTACH_DETACH + +/* Doesn't have siginterupt. */ +#define NO_SIGINTERRUPT + +/* called from register_addr() -- blockend not used for now */ +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ \ + switch (regno) { \ + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: \ + addr = PU_R0 - (regno * sizeof (int)); break; \ + case SP_REGNUM: \ + addr = PU_SP; break; \ + case PC_REGNUM: \ + addr = PU_PC; break; \ + case FP_REGNUM: \ + addr = PU_FP; break; \ + case PS_REGNUM: \ + addr = PU_PSL; break; \ + case FPS_REGNUM: \ + addr = PU_FSR; break; \ + case FP0_REGNUM + 0: case FP0_REGNUM + 1: \ + case FP0_REGNUM + 2: case FP0_REGNUM + 3: \ + case FP0_REGNUM + 4: case FP0_REGNUM + 5: \ + case FP0_REGNUM + 6: case FP0_REGNUM + 7: \ + addr = PU_F0 + (regno - FP0_REGNUM) * sizeof (float); break; \ + case LP0_REGNUM + 0: case LP0_REGNUM + 1: \ + case LP0_REGNUM + 2: case LP0_REGNUM + 3: \ + addr = PU_F0 + (regno - LP0_REGNUM) * sizeof (double); break; \ + default: \ + printf ("bad argument to REGISTER_U_ADDR %d\n", regno); \ + abort (); \ + } \ +} + +/* Compensate for lack of `vprintf' function. */ +#define MISSING_VPRINTF diff --git a/gdb/xm-vax.h b/gdb/xm-vax.h new file mode 100644 index 00000000000..1bc6aa484e4 --- /dev/null +++ b/gdb/xm-vax.h @@ -0,0 +1,90 @@ +/* Definitions to make GDB run on a vax under 4.2bsd. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR (0x80000000 - (UPAGES * NBPG)) + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ addr = blockend - 0110 + regno * 4; \ + if (regno == PC_REGNUM) addr = blockend - 8; \ + if (regno == PS_REGNUM) addr = blockend - 4; \ + if (regno == FP_REGNUM) addr = blockend - 0120; \ + if (regno == AP_REGNUM) addr = blockend - 0124; \ + if (regno == SP_REGNUM) addr = blockend - 20; } + +/* 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, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \ + 0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movl $ end, sp"); \ + asm ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("pushl fp"); + +/* 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 ("pushl 8(sp)"); \ + asm ("pushl 8(sp)"); \ + asm ("pushal 0x14(sp)"); \ + asm ("pushr $037777"); } + +/* 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 ("popr $037777"); \ + asm ("subl2 $8,(sp)"); \ + asm ("movl (sp),sp"); \ + asm ("rei"); } diff --git a/include/a.out.hp.h b/include/a.out.hp.h new file mode 100755 index 00000000000..87e72199d70 --- /dev/null +++ b/include/a.out.hp.h @@ -0,0 +1,79 @@ +/* Special version of for use under hp-ux. + Copyright (C) 1988 Free Software Foundation, Inc. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The `exec' structure and overall layout must be close to HP's when + we are running on an HP system, otherwise we will not be able to + execute the resulting file. */ + +/* Allow this file to be included twice. */ +#ifndef __GNU_EXEC_MACROS__ + +struct exec +{ + unsigned short a_machtype; /* machine type */ + unsigned short a_magic; /* magic number */ + unsigned long a_spare1; + unsigned long a_spare2; + unsigned long a_text; /* length of text, in bytes */ + unsigned long a_data; /* length of data, in bytes */ + unsigned long a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned long a_trsize; /* length of relocation info for text, in bytes */ + unsigned long a_drsize; /* length of relocation info for data, in bytes */ + unsigned long a_spare3; /* HP = pascal interface size */ + unsigned long a_spare4; /* HP = symbol table size */ + unsigned long a_spare5; /* HP = debug name table size */ + unsigned long a_entry; /* start address */ + unsigned long a_spare6; /* HP = source line table size */ + unsigned long a_spare7; /* HP = value table size */ + unsigned long a_syms; /* length of symbol table data in file, in bytes */ + unsigned long a_spare8; +}; + +/* Tell a.out.gnu.h not to define `struct exec'. */ +#define __STRUCT_EXEC_OVERRIDE__ + +#include "../a.out.gnu.h" + +#undef N_MAGIC +#undef N_MACHTYPE +#undef N_FLAGS +#undef N_SET_INFO +#undef N_SET_MAGIC +#undef N_SET_MACHTYPE +#undef N_SET_FLAGS + +#define N_MAGIC(exec) ((exec) . a_magic) +#define N_MACHTYPE(exec) ((exec) . a_machtype) +#define N_SET_MAGIC(exec, magic) (((exec) . a_magic) = (magic)) +#define N_SET_MACHTYPE(exec, machtype) (((exec) . a_machtype) = (machtype)) + +#undef N_BADMAG +#define N_BADMAG(x) ((_N_BADMAG (x)) || (_N_BADMACH (x))) + +#define _N_BADMACH(x) \ +(((N_MACHTYPE (x)) != HP9000S200_ID) && \ + ((N_MACHTYPE (x)) != HP98x6_ID)) + +#define HP98x6_ID 0x20A +#define HP9000S200_ID 0x20C + +#undef _N_HDROFF +#define _N_HDROFF(x) (SEGMENT_SIZE - (sizeof (struct exec))) + +#define SEGMENT_SIZE 0x1000 + +#endif /* __GNU_EXEC_MACROS__ */ diff --git a/readline/ChangeLog b/readline/ChangeLog new file mode 100644 index 00000000000..5136177a8ed --- /dev/null +++ b/readline/ChangeLog @@ -0,0 +1,82 @@ +Sun Mar 11 04:32:03 1990 Brian Fox (bfox at gnuwest.fsf.org) + + * Signals are now supposedly handled inside of SYSV compilation. + +Wed Jan 17 19:24:09 1990 Brian Fox (bfox at sbphy.ucsb.edu) + + * history.c: history_expand (); fixed overwriting memory error, + added needed argument to call to get_history_event (). + +Thu Jan 11 10:54:04 1990 Brian Fox (bfox at sbphy.ucsb.edu) + + * readline.c, readline.h: added rl_show_star to control the + display of an asterisk on modified history lines. + +Thu Jan 4 10:38:05 1990 Brian Fox (bfox at sbphy.ucsb.edu) + + * readline.c: start_insert (). Only use IC if we don't have an im + capability. + +Fri Sep 8 09:00:45 1989 Brian Fox (bfox at aurel) + + * readline.c: rl_prep_terminal (). Only turn on 8th bit + as meta-bit iff the terminal is not using parity. + +Sun Sep 3 08:57:40 1989 Brian Fox (bfox at aurel) + + * readline.c: start_insert (). Uses multiple + insertion call in cases where that makes sense. + + rl_insert (). Read type-ahead buffer for additional + keys that are bound to rl_insert, and insert them + all at once. Make insertion of single keys given + with an argument much more efficient. + +Tue Aug 8 18:13:57 1989 Brian Fox (bfox at aurel) + + * readline.c: Changed handling of EOF. readline () returns + (char *)EOF or consed string. The EOF character is read from the + tty, or if the tty doesn't have one, defaults to C-d. + + * readline.c: Added support for event driven programs. + rl_event_hook is the address of a function you want called + while Readline is waiting for input. + + * readline.c: Cleanup time. Functions without type declarations + do not use return with a value. + + * history.c: history_expand () has new variable which is the + characters to ignore immediately following history_expansion_char. + +Sun Jul 16 08:14:00 1989 Brian Fox (bfox at aurel) + + * rl_prep_terminal () + BSD version turns off C-s, C-q, C-y, C-v. + + * readline.c -- rl_prep_terminal () + SYSV version hacks readline_echoing_p. + BSD version turns on passing of the 8th bit for the duration + of reading the line. + +Tue Jul 11 06:25:01 1989 Brian Fox (bfox at aurel) + + * readline.c: new variable rl_tilde_expander. + If non-null, this contains the address of a function to call if + the standard meaning for expanding a tilde fails. The function is + called with the text sans tilde (as in "foo"), and returns a + malloc()'ed string which is the expansion, or a NULL pointer if + there is no expansion. + + * readline.h - new file chardefs.h + Separates things that only readline.c needs from the standard + header file publishing interesting things about readline. + + * readline.c: + readline_default_bindings () now looks at terminal chararacters + and binds those as well. + +Wed Jun 28 20:20:51 1989 Brian Fox (bfox at aurel) + + * Made readline and history into independent libraries. + + diff --git a/readline/history.texinfo b/readline/history.texinfo new file mode 100755 index 00000000000..1e619e1acfb --- /dev/null +++ b/readline/history.texinfo @@ -0,0 +1,194 @@ +\input texinfo.tex +@setfilename history.info + +@ifinfo +This file documents the GNU History library. + +Copyright (C) 1988 Free Software Foundation, Inc. +Authored by Brian Fox. + +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 +GNU Copyright statement is available to the distributee, 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. +@end ifinfo + +@node Top, Introduction, , (DIR) + +This document describes the GNU History library, a programming tool that +provides a consistent user interface for recalling lines of previously +typed input. + +@menu +* Introduction:: What is the GNU History library for? +* Interactive Use:: What it feels like using History as a user. +* Programming:: How to use History in your programs. +@end menu + +@node Introduction, Interactive Use, , Top +@unnumbered Introduction + +Many programs read input from the user a line at a time. The GNU history +library is able to keep track of those lines, associate arbitrary data with +each line, and utilize information from previous lines in making up new +ones. + +The programmer using the History library has available to him functions for +remembering lines on a history stack, associating arbitrary data with a +line, removing lines from the stack, searching through the stack for a +line containing an arbitrary text string, and referencing any line on the +stack directly. In addition, a history @dfn{expansion} function is +available which provides for a consistent user interface across many +different programs. + +The end-user using programs written with the History library has the +benifit of a consistent user interface, with a set of well-known commands +for manipulating the text of previous lines and using that text in new +commands. The basic history manipulation commands are similar to the +history substitution used by Csh. + +If the programmer desires, he can use the Readline library, which includes +history manipulation by default, and has the added advantage of Emacs style +command line editing. + +@node Interactive Use, Programming, Introduction, Top +@chapter Interactive Use + +@section History Expansion +@cindex expansion + +The History library provides a history expansion feature that is similar to +the history expansion in Csh. The following text describes what syntax +features are available. + +History expansion takes place in two parts. The first is to determine +which line from the previous history should be used during substitution. +The second is to select portions of that line for inclusion into the +current one. The line selected from the previous history is called the +@dfn{event}, and the portions of that line that are acted upon are called +@dfn{words}. The line is broken into words in the same fashion that the +Bash shell does, so that several English (or Unix) words surrounded by +quotes are considered as one word. + +@menu +* Event Designators:: How to specify which history line to use. +* Word Designators:: Specifying which words are of interest. +* Modifiers:: Modifying the results of susbstitution. +@end menu + +@node Event Designators, Word Designators, , Interactive Use +@subsection Event Designators +@cindex event designators + +An event designator is a reference to a command line entry in the history +list. + +@table @var + +@item ! +Start a history subsititution, except when followed by a @key{SPC}, +@key{TAB}, @key{RET}, @key{=} or @key{(}. + +@item !! +Refer to the previous command. This is a synonym for @code{!-1}. + +@item !n +Refer to command line @var{n}. + +@item !-n +Refer to the current command line minus @var{n}. + +@item !string +Refer to the most recent command starting with @var{string}. + +@item !?string[?] +Refer to the most recent command containing @var{string}. + +@end table + +@node Word Designators, Modifiers, Event Designators, Interactive Use +@subsection Word Designators + +A @key{:} separates the event specification from the word designator. It +can be omitted if the word designator begins with a @key{^}, @key{$}, +@key{*} or @key{%}. Words are numbered from the beginning of the line, +with the first word being denoted by a 0 (zero). + +@table @asis + +@item @var{0} (zero) +The zero'th word. For many applications, this is the command word. + +@item n +The @var{n}'th word. + +@item @var{^} +The first argument. that is, word 1. + +@item @var{$} +The last argument. + +@item @var{%} +The word matched by the most recent @code{?string?} search. + +@item @var{x}-@var{y} +A range of words; @code{-@var{y}} is equivalent to @code{0-@var{y}}. + +@item @var{*} +All of the words, excepting the zero'th. This is a synonym for @samp{1-$}. +It is not an error to use @samp{*} if there is just one word in the event. +The empty string is returned in that case. + +@end table + +@node Modifiers, , Word Designators, Interactive Use +@subsection Modifiers + +After the optional word designator, you can add a sequence of one or more +of the following modifiers, each preceded by a @key{:}. + +@table @code + +@item # +The entire command line typed so far. This means the current command, +not the previous command, so it really isn't a word designator, and doesn't +belong in this section. + +@item h +Remove a trailing pathname component, leaving only the head. + +@item r +Remove a trailing suffix of the form ".xxx", leaving the basename (root). + +@item e +Remove all but the suffix (end). + +@item t +Remove all leading pathname components (before the last slash), leaving +the tail. + +@item p +Print the new command but do not execute it. This takes effect +immediately, so it should be the last specifier on the line. + +@end table + +@node Programming, , Interactive Use, Top +@chapter Programming + +@bye diff --git a/readline/readline.texinfo b/readline/readline.texinfo new file mode 100755 index 00000000000..36fe7a98ee8 --- /dev/null +++ b/readline/readline.texinfo @@ -0,0 +1,434 @@ +\input texinfo @c -*-texinfo-*- +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename readline.info +@settitle Line Editing Commands +@comment %**end of header (This is for running Texinfo on a region.) +@synindex fn vr + +@iftex +@comment finalout +@end iftex + +@ifinfo +This document describes the GNU Readline Library, a utility for aiding +in the consitency of user interface across discrete programs that need +to provide a command line interface. + +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 +pare 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 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 this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@setchapternewpage odd +@titlepage +@sp 11 +@center @titlefont{GNU Readline Library} +@sp 2 +@center by Brian Fox +@sp 2 +@center Version 1.0 +@sp 2 +@center February 1989 + +@comment Include the Distribution inside the titlepage environment so +@c that headings are turned off. + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1989 Free Software Foundation, Inc. + +@sp 2 +This document describes the GNU Readline Library, a utility for aiding +in the consistency of user interface across discrete programs that need +to provide a command line interface. +@sp 2 + +Published by the Free Software Foundation @* +675 Massachusetts Avenue, @* +Cambridge, MA 02139 USA + +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 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 this permission notice may be stated in a translation approved +by the Foundation. + +@end titlepage + +@node Top, Readline Top, ,(DIR) +@chapter GNU Readline Library + +@ifinfo +This document describes the GNU Readline Library, a utility for aiding +in the consistency of user interface across discrete programs that need +to provide a command line interface. +@end ifinfo + +@menu +* Readline Top:: GNU Readline User's Manual +* Readline Technical:: GNU Readline Programmer's Manual +@end menu +@include inc-readline.texinfo +@node Readline Technical, , Top, Top +@chapter Readline Programmer's Manual + +This manual describes the interface between the GNU Readline Library and +user programs. If you are a programmer, and you wish to include the +features found in GNU Readline in your own programs, such as completion, +line editing, and interactive history manipulation, this documentation +is for you. + +@menu +* Default Behaviour:: Using the default behaviour of Readline. +* Custom Functions:: Adding your own functions to Readline. +* Custom Completers:: Supplanting or supplementing Readline's + completion functions. +* Variable Index:: Index of externally tweakable variables. +@end menu + +@node Default Behaviour, Custom Functions, Readline Technical, Readline Technical +@section Default Behaviour + +Many programs provide a command line interface, such as @code{mail}, +@code{ftp}, and @code{sh}. For such programs, the default behaviour of +Readline is sufficient. This section describes how to use Readline in +the simplest way possible, perhaps to replace calls in your code to +@code{gets ()}. + +@findex readline () +@cindex readline, function +The function @code{readline} prints a prompt and then reads and returns +a single line of text from the user. The line which @code{readline ()} +returns is allocated with @code{malloc ()}; you should @code{free ()} +the line when you are done with it. The declaration in ANSI C is + +@example +@code{char *readline (char *@var{prompt});} +@end example +or, preferably, +@example +@code{#include } +@end example + +So, one might say +@example +@code{char *line = readline ("Enter a line: ");} +@end example +in order to read a line of text from the user. + +The line which is returned has the final newline removed, so only the +text of the line remains. + +If readline encounters an EOF while reading the line, and the line is +empty at that point, then @code{(char *)NULL} is returned. Otherwise, +the line is ended just as if a newline was typed. + +If you want the user to be able to get at the line later, (with +@key{C-p} for example), you must call @code{add_history ()} to save the +line away in a @dfn{history} list of such lines. + +@example +@code{add_history (line)}; +@end example + +If you use @code{add_history ()}, you should also +@code{#include } +For full details on the GNU History Library, see the associated manual. + +It is polite to avoid saving empty lines on the history list, since +no one has a burning need to reuse a blank line. Here is a function +which usefully replaces the standard @code{gets ()} library function: + +@example +#include +#include + +/* A static variable for holding the line. */ +static char *my_gets_line = (char *)NULL; + +/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +char * +my_gets () +@{ + /* If the buffer has already been allocated, return the memory + to the free pool. */ + if (my_gets_line != (char *)NULL) + free (my_gets_line); + + /* Get a line from the user. */ + my_gets_line = readline (""); + + /* If the line has any text in it, save it on the history. */ + if (my_get_line && *my_gets_line) + add_history (my_gets_line); + + return (my_gets_line); +@} +@end example + +The above code gives the user the default behaviour of @key{TAB} +completion: completion on file names. If you do not want readline to +complete on filenames, you can change the binding of the @key{TAB} key +with @code{rl_bind_key ()}. + +@findex rl_bind_key () + +@example +@code{int rl_bind_key (int @var{key}, (int (*)())@var{function});} +@end example + +@code{rl_bind_key ()} takes 2 arguments; @var{key} is the character that +you want to bind, and @var{function} is the address of the function to +run when @var{key} is pressed. Binding @key{TAB} to @code{rl_insert ()} +makes @key{TAB} just insert itself. + +@code{rl_bind_key ()} returns non-zero if @var{key} is not a valid +ASCII character code (between 0 and 255). + +@example +@code{rl_bind_key ('\t', rl_insert);} +@end example + +@node Custom Functions, Custom Completers, Default Behaviour, Readline Technical +@section Custom Functions + +Readline provides a great many functions for manipulating the text of +the line. But it isn't possible to anticipate the needs of all +programs. This section describes the various functions and variables +defined in within the Readline library which allow a user program to add +customized functionality to Readline. + +@menu +* The Function Type:: C declarations to make code readable. +* Function Naming:: How to give a function you write a name. +* Keymaps:: Making keymaps. +* Binding Keys:: Changing Keymaps. +* Function Writing:: Variables and calling conventions. +* Allowing Undoing:: How to make your functions undoable. +@end menu + +@node The Function Type, Function Naming, Custom Functions, Custom Functions +For the sake of readabilty, we declare a new type of object, called +@dfn{Function}. `Function' is a C language function which returns an +@code{int}. The type declaration for `Function' is: + +@code{typedef int Function ();} + +The reason for declaring this new type is to make it easier to discuss +pointers to C functions. Let us say we had a variable called @var{func} +which was a pointer to a function. Instead of the classic C declaration + +@code{int (*)()func;} + +we have + +@code{Function *func;} + +@node Function Naming, Keymaps, The Function Type, Custom Functions +@subsection Naming a Function + +The user can dynamically change the bindings of keys while using +Readline. This is done by representing the function with a descriptive +name. The user is able to type the descriptive name when referring to +the function. Thus, in an init file, one might find + +@example +Meta-Rubout: backward-kill-word +@end example + +This binds @key{Meta-Rubout} to the function @emph{descriptively} named +@code{backward-kill-word}. You, as a programmer, should bind the +functions you write to descriptive names as well. Here is how to do +that. + +@defun rl_add_defun (char *name, Function *function, int key) +Add @var{name} to the list of named functions. Make @var{function} be +the function that gets called. If @var{key} is not -1, then bind it to +@var{function} using @code{rl_bind_key ()}. +@end defun + +Using this function alone is sufficient for most applications. It is +the recommended way to add a few functions to the default functions that +Readline has built in already. If you need to do more or different +things than adding a function to Readline, you may need to use the +underlying functions described below. + +@node Keymaps, Binding Keys, Function Naming, Custom Functions +@subsection Selecting a Keymap + +Key bindings take place on a @dfn{keymap}. The keymap is the +association between the keys that the user types and the functions that +get run. You can make your own keymaps, copy existing keymaps, and tell +Readline which keymap to use. + +@defun rl_make_bare_keymap () +Returns a new, empty keymap. The space for the keymap is allocated with +@code{malloc ()}; you should @code{free ()} it when you are done. +@end defun + +@defun rl_copy_keymap (Keymap map) +Return a new keymap which is a copy of @var{map}. +@end defun + +@defun rl_make_keymap () +Return a new keymap with the printing characters bound to rl_insert, +the lowercase Meta characters bound to run their equivalents, and +the Meta digits bound to produce numeric arguments. +@end defun + +@node Binding Keys, Function Writing, Keymaps, Custom Functions +@subsection Binding Keys + +You associate keys with functions through the keymap. Here are +the functions for doing that. + +@defun rl_bind_key (int key, Function *function) +Binds @var{key} to @var{function} in the currently selected keymap. +Returns non-zero in the case of an invalid @var{key}. +@end defun + +@defun rl_bind_key_in_map (int key, Function *function, Keymap map) +Bind @var{key} to @var{function} in @var{map}. Returns non-zero in the case +of an invalid @var{key}. +@end defun + +@defun rl_unbind_key (int key) +Make @var{key} do nothing in the currently selected keymap. +Returns non-zero in case of error. +@end defun + +@defun rl_unbind_key_in_map (int key, Keymap map) +Make @var{key} be bound to the null function in @var{map}. +Returns non-zero in case of error. +@end defun + +@node Function Writing, Allowing Undoing, Binding Keys, Custom Functions +@subsection Writing a New Function + +In order to write new functions for Readline, you need to know the +calling conventions for keyboard invoked functions, and the names of the +variables that describe the current state of the line gathered so far. + +@defvar char *rl_line_buffer +This is the line gathered so far. You are welcome to modify the +contents of this, but see Undoing, below. +@end defvar + +@defvar int rl_point +The offset of the current cursor position in @var{rl_line_buffer}. +@end defvar + +@defvar int rl_end +The number of characters present in @code{rl_line_buffer}. When +@code{rl_point} is at the end of the line, then @code{rl_point} and +@code{rl_end} are equal. +@end defvar + +The calling sequence for a command @code{foo} looks like + +@example +@code{foo (count, key)} +@end example + +where @var{count} is the numeric argument (or 1 if defaulted) and +@var{key} is the key that invoked this function. + +It is completely up to the function as to what should be done with the +numeric argument; some functions use it as a repeat count, other +functions as a flag, and some choose to ignore it. In general, if a +function uses the numeric argument as a repeat count, it should be able +to do something useful with a negative argument as well as a positive +argument. At the very least, it should be aware that it can be passed a +negative argument. + +@node Allowing Undoing, , Function Writing, Custom Functions +@subsection Allowing Undoing + +Supporting the undo command is a painless thing to do, and makes your +function much more useful to the end user. It is certainly easy to try +something if you know you can undo it. I could use an undo function for +the stock market. + +If your function simply inserts text once, or deletes text once, and it +calls @code{rl_insert_text ()} or @code{rl_delete_text ()} to do it, then +undoing is already done for you automatically, and you can safely skip +this section. + +If you do multiple insertions or multiple deletions, or any combination +of these operations, you will want to group them together into one +operation. This can be done with @code{rl_begin_undo_group ()} and +@code{rl_end_undo_group ()}. + +@defun rl_begin_undo_group () +Begins saving undo information in a group construct. The undo +information usually comes from calls to @code{rl_insert_text ()} and +@code{rl_delete_text ()}, but they could be direct calls to +@code{rl_add_undo ()}. +@end defun + +@defun rl_end_undo_group () +Closes the current undo group started with @code{rl_begin_undo_group +()}. There should be exactly one call to @code{rl_end_undo_group ()} +for every call to @code{rl_begin_undo_group ()}. +@end defun + +Finally, if you neither insert nor delete text, but directly modify the +existing text (e.g. change its case), you call @code{rl_modifying ()} +once, just before you modify the text. You must supply the indices of +the text range that you are going to modify. + +@defun rl_modifying (int start, int end) +Tell Readline to save the text between @var{start} and @var{end} as a +single undo unit. It is assumed that subsequent to this call you will +modify that range of text in some way. +@end defun + +@subsection An Example + +Let us say that we are actually going to put an example here. + +@node Custom Completers, Variable Index, Custom Functions, Readline Technical + +Typically, a program that reads commands from the user has a way of +disambiguating between commands and data. If your program is one of +these, then it can provide completion for either commands, or data, or +both commands and data. The following sections describe how your +program and Readline cooperate to provide this service to end users. + +@menu +@end menu + +@node Variable Index, , Custom Completers, Readline Technical +@appendix Variable Index +@printindex vr +@contents + +@bye +