gdb-3.1
This commit is contained in:
parent
bb7592f010
commit
e91b87a368
13
gdb/.gdbinit
Normal file
13
gdb/.gdbinit
Normal file
@ -0,0 +1,13 @@
|
||||
b fatal
|
||||
|
||||
b info_command
|
||||
commands
|
||||
silent
|
||||
return
|
||||
end
|
||||
|
||||
define rr
|
||||
run
|
||||
end
|
||||
|
||||
set prompt (top-gdb)
|
2629
gdb/ChangeLog
2629
gdb/ChangeLog
File diff suppressed because it is too large
Load Diff
287
gdb/Makefile
287
gdb/Makefile
@ -1,109 +1,240 @@
|
||||
# Makefile for GDB
|
||||
# Copyright (C) 1986, 1988 Free Software Foundation, Inc.
|
||||
#
|
||||
#GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
#WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
#for the consequences of using it or for whether it serves any
|
||||
#particular purpose or works at all, unless he says so in writing.
|
||||
#Refer to the GDB General Public License for full details.
|
||||
#
|
||||
#Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
#but only under the conditions described in the GDB General Public
|
||||
#License. A copy of this license is supposed to have been given to you
|
||||
#along with GDB so you can know your rights and responsibilities. It
|
||||
#should be in a file named COPYING. Among other things, the copyright
|
||||
#notice and this notice must be preserved on all copies.
|
||||
#
|
||||
#In other words, go ahead and share GDB, but don't try to stop
|
||||
#anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
|
||||
# On HPUX, you need to add -Ihpux to CFLAGS.
|
||||
# The headers in the subdir hpux override system headers
|
||||
# On HPUX, you need to add -Ihp-include to CFLAGS.
|
||||
# The headers in the directory hp-include override system headers
|
||||
# and tell GDB to use BSD executable file format.
|
||||
# You also need to add -lGNU to CLIBS, and perhaps CC = gcc.
|
||||
# You must also define REGEX & REGEX1 below and ALLOCA & ALLOCA1 (get
|
||||
# alloca.c from the emacs distribution) to the CLIBS.
|
||||
# If you compile GDB with GCC on HPUX, you must make sure that the "nm" used
|
||||
# in "munch" is GNU's nm. This is because gcc uses a different .o
|
||||
# file format than the native HPUX compiler.
|
||||
|
||||
# -I. for "#include <obstack.h>"
|
||||
CFLAGS = -g -I.
|
||||
# NOTE!!! -O may FAIL TO WORK! See initialize.h for some weird hacks.
|
||||
# On USG (System V) machines, you must make sure to setup REGEX &
|
||||
# REGEX1 to point at regex.o and use the USG version of CLIBS.
|
||||
# If your system has a broken alloca() -- most do -- then get
|
||||
# alloca.c from the GNU Emacs distribution and set ALLOCA & ALLOCA1.
|
||||
# Also, if you compile gdb with a compiler which uses the coff
|
||||
# encapsulation feature (this is a function of the compiler used, NOT
|
||||
# of the m-?.h file selected by config.gdb), you must make sure that
|
||||
# the GNU nm is the one that is used by munch.
|
||||
|
||||
# On Sunos 4.0 machines, make sure to compile *without* shared
|
||||
# libraries if you want to run gdb on itself. Make sure to compile
|
||||
# any program on which you want to run gdb without shared libraries.
|
||||
|
||||
# If you are compiling with GCC, make sure that either 1) You use the
|
||||
# -traditional flag, or 2) You have the fixed include files where GCC
|
||||
# can reach them. Otherwise the ioctl calls in inflow.c will be
|
||||
# incorrectly compiled. The "fixincludes" script in the gcc
|
||||
# distribution will probably fix your include files up.
|
||||
|
||||
CC=cc
|
||||
SHELL=/bin/sh
|
||||
|
||||
# Set this up with gcc if you have gnu ld and the loader will print out
|
||||
# line numbers for undefinded refs.
|
||||
CC-LD=${CC}
|
||||
|
||||
# -I. for "#include <obstack.h>". Possibly regex.h also.
|
||||
#CFLAGS = -g -pg -I. -O
|
||||
CFLAGS = -I. -g
|
||||
#LDFLAGS = -pg -g
|
||||
LDFLAGS = -g
|
||||
|
||||
# define this to be "obstack.o" if you don't have the obstack library installed
|
||||
# you must at the same time define OBSTACK1 as "obstack.o"
|
||||
# so that the dependencies work right.
|
||||
# so that the dependencies work right. Similarly with REGEX and "regex.o".
|
||||
# You must define REGEX and REGEX1 on USG machines.
|
||||
# If your system is missing alloca(), or, more likely, it's there but it
|
||||
# doesn't work, define ALLOCA and ALLOCA1.
|
||||
OBSTACK = obstack.o
|
||||
OBSTACK1 = obstack.o
|
||||
REGEX = regex.o
|
||||
REGEX1 = regex.o
|
||||
ALLOCA = alloca.o
|
||||
ALLOCA1 = alloca.o
|
||||
ADD_FILES = $(OBSTACK) $(REGEX) $(ALLOCA) $(GNU_MALLOC)
|
||||
ADD_DEPS = $(OBSTACK1) $(REGEX1) $(ALLOCA1) $(GNU_MALLOC)
|
||||
|
||||
CLIBS = $(OBSTACK)
|
||||
#
|
||||
# define this to be "malloc.o" if you want to use the gnu malloc routine
|
||||
# (useful for debugging memory allocation problems in gdb). Otherwise, leave
|
||||
# it blank.
|
||||
GNU_MALLOC =
|
||||
#GNU_MALLOC = malloc.o
|
||||
|
||||
STARTOBS = main.o firstfile.o
|
||||
# Flags to be used in compiling malloc.o
|
||||
# Specify range checking for storage allocation.
|
||||
MALLOC_FLAGS =
|
||||
#MALLOC_FLAGS = ${CFLAGS} -Drcheck -Dbotch=fatal -DMSTATS
|
||||
|
||||
OBS = blockframe.o breakpoint.o findvar.o stack.o source.o \
|
||||
# for BSD
|
||||
CLIBS = $(ADD_FILES)
|
||||
# for USG
|
||||
#CLIBS= $(ADD_FILES) -lPW
|
||||
|
||||
SFILES = blockframe.c breakpoint.c coffread.c command.c core.c dbxread.c \
|
||||
environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \
|
||||
kdb-start.c main.c printcmd.c \
|
||||
remote.c source.c stack.c standalone.c stuff.c symmisc.c symtab.c \
|
||||
utils.c valarith.c valops.c valprint.c values.c version.c expread.y \
|
||||
xgdb.c
|
||||
|
||||
DEPFILES = convex-dep.c umax-dep.c gould-dep.c default-dep.c sun3-dep.c \
|
||||
sparc-dep.c hp9k320-dep.c news-dep.c i386-dep.c
|
||||
|
||||
PINSNS = gld-pinsn.c i386-pinsn.c sparc-pinsn.c vax-pinsn.c m68k-pinsn.c \
|
||||
ns32k-pinsn.c
|
||||
|
||||
HFILES = command.h defs.h environ.h expression.h frame.h getpagesize.h \
|
||||
inferior.h symseg.h symtab.h value.h wait.h \
|
||||
a.out.encap.h a.out.gnu.h stab.gnu.h
|
||||
|
||||
OPCODES = m68k-opcode.h pn-opcode.h sparc-opcode.h npl-opcode.h vax-opcode.h \
|
||||
ns32k-opcode.h
|
||||
|
||||
MFILES = m-hp9k320.h m-i386.h m-i386gas.h m-isi.h m-merlin.h m-news.h \
|
||||
m-npl.h m-pn.h m-sparc.h m-sun2.h m-sun3.h m-sun2os4.h \
|
||||
m-sun3os4.h m-sun4os4.h m-umax.h m-vax.h
|
||||
|
||||
POSSLIBS = obstack.h obstack.c regex.c regex.h malloc.c
|
||||
|
||||
TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c
|
||||
|
||||
OTHERS = Makefile createtags munch config.gdb ChangeLog README TAGS \
|
||||
gdb.texinfo .gdbinit COPYING expread.tab.c stab.def hp-include
|
||||
|
||||
TAGFILES = ${SFILES} ${DEPFILES} ${PINSNS} ${HFILES} ${OPCODES} ${MFILES} \
|
||||
${POSSLIBS}
|
||||
TARFILES = ${TAGFILES} ${OTHERS}
|
||||
|
||||
OBS = main.o blockframe.o breakpoint.o findvar.o stack.o source.o \
|
||||
values.o eval.o valops.o valarith.o valprint.o printcmd.o \
|
||||
symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o
|
||||
symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o \
|
||||
command.o utils.o expread.o expprint.o pinsn.o environ.o version.o
|
||||
|
||||
TSOBS = core.o inflow.o
|
||||
TSOBS = core.o inflow.o dep.o
|
||||
|
||||
NTSOBS = standalone.o
|
||||
|
||||
ENDOBS = lastfile.o command.o utils.o expread.o expprint.o pinsn.o \
|
||||
environ.o version.o
|
||||
|
||||
TSSTART = /lib/crt0.o
|
||||
|
||||
NTSSTART = kdb-start.o
|
||||
|
||||
gdb+ : $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) $(OBSTACK1)
|
||||
$(CC) $(LDFLAGS) -o gdb+ $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) $(CLIBS)
|
||||
gdb : $(OBS) $(TSOBS) $(ADD_DEPS)
|
||||
-rm -f init.c
|
||||
./munch $(OBS) $(TSOBS) > init.c
|
||||
${CC-LD} $(LDFLAGS) -o gdb init.c $(OBS) $(TSOBS) $(CLIBS)
|
||||
|
||||
xgdb+ : $(STARTOBS) $(OBS) $(TSOBS) xgdb.o $(ENDOBS) $(OBSTACK1)
|
||||
$(CC) $(LDFLAGS) -o xgdb+ $(STARTOBS) $(OBS) $(TSOBS) xgdb.o $(ENDOBS) \
|
||||
-lXaw -lXt -lX11 $(CLIBS)
|
||||
xgdb : $(OBS) $(TSOBS) xgdb.o $(ADD_DEPS)
|
||||
-rm -f init.c
|
||||
./munch $(OBS) $(TSOBS) xgdb.o > init.c
|
||||
$(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \
|
||||
-lXaw -lXt -lX11 $(CLIBS)
|
||||
|
||||
kdb : $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) $(OBSTACK1)
|
||||
ld -o kdb $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) -lc $(CLIBS)
|
||||
kdb : $(NTSSTART) $(OBS) $(NTSOBS) $(ADD_DEPS)
|
||||
-rm -f init.c
|
||||
./munch $(OBS) $(NTSOBS) > init.c
|
||||
$(CC-LD) $(LDFLAGS) -c init.c $(CLIBS)
|
||||
ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o -lc $(CLIBS)
|
||||
|
||||
# If it can figure out the appropriate order, createtags will make sure
|
||||
# that the proper m-*, *-dep, *-pinsn, and *-opcode files come first
|
||||
# in the tags list. It will attempt to do the same for dbxread.c and
|
||||
# coffread.c. This makes using M-. on machine dependent routines much
|
||||
# easier.
|
||||
#
|
||||
TAGS: ${TAGFILES}
|
||||
createtags ${TAGFILES}
|
||||
tags: TAGS
|
||||
|
||||
gdb.tar: ${TARFILES}
|
||||
rm -f gdb.tar
|
||||
mkdir dist-gdb
|
||||
cd dist-gdb ; for i in ${TARFILES} ; do ln -s ../$$i . ; done
|
||||
tar chf gdb.tar dist-gdb
|
||||
rm -rf dist-gdb
|
||||
|
||||
gdb.tar.Z: gdb.tar
|
||||
compress gdb.tar
|
||||
|
||||
clean:
|
||||
-rm -f ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX}
|
||||
-rm -f init.c init.o
|
||||
-rm -f gdb
|
||||
|
||||
realclean: clean
|
||||
-rm -f expread.tab.c tags TAGS
|
||||
|
||||
xgdb.o : xgdb.c defs.h param.h symtab.h frame.h
|
||||
$(CC) -c $(CFLAGS) xgdb.c -o $@
|
||||
|
||||
blockframe.o : blockframe.c defs.h initialize.h param.h symtab.h frame.h
|
||||
breakpoint.o : breakpoint.c defs.h initialize.h param.h symtab.h frame.h
|
||||
command.o : command.c command.h
|
||||
coffread.o : coffread.c defs.h initialize.h param.h symtab.h
|
||||
core.o : core.c defs.h initialize.h param.h
|
||||
dbxread.o : dbxread.c defs.h initialize.h param.h symtab.h
|
||||
environ.o : environ.c environ.h
|
||||
expprint.o : expprint.c defs.h symtab.h expression.h
|
||||
expread.tab.c : expread.y
|
||||
@echo 'Expect 96 shift/reduce conflicts.'
|
||||
@echo 'Expect 101 shift/reduce conflicts and 1 reduce/reduce conflict.'
|
||||
yacc expread.y
|
||||
mv y.tab.c expread.tab.c
|
||||
|
||||
expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h
|
||||
$(CC) -c ${CFLAGS} expread.tab.c
|
||||
mv expread.tab.o expread.o
|
||||
eval.o : eval.c defs.h initialize.h symtab.h value.h expression.h
|
||||
findvar.o : findvar.c defs.h initialize.h param.h symtab.h frame.h value.h
|
||||
firstfile.o : firstfile.c initialize.h
|
||||
infcmd.o : infcmd.c defs.h initialize.h param.h symtab.h frame.h inferior.h environ.h value.h
|
||||
inflow.o : inflow.c defs.h initialize.h param.h frame.h inferior.h
|
||||
infrun.o : infrun.c defs.h initialize.h param.h symtab.h frame.h inferior.h wait.h
|
||||
kdb-start.o : kdb-start.c defs.h param.h
|
||||
lastfile.o : lastfile.c
|
||||
main.o : main.c defs.h command.h
|
||||
|
||||
#
|
||||
# Only useful if you are using the gnu malloc routines.
|
||||
#
|
||||
malloc.o : malloc.c
|
||||
${CC} -c ${MALLOC_FLAGS} malloc.c
|
||||
|
||||
#
|
||||
# dep.o depends on ALL the dep files since we don't know which one
|
||||
# is really being used.
|
||||
#
|
||||
dep.o : ${DEPFILES} defs.h param.h frame.h inferior.h obstack.h \
|
||||
a.out.encap.h
|
||||
|
||||
# pinsn.o depends on ALL the opcode printers
|
||||
# since we don't know which one is really being used.
|
||||
pinsn.o : pinsn.c defs.h param.h symtab.h \
|
||||
vax-opcode.h vax-pinsn.c m68k-opcode.h m68k-pinsn.c sparc-opcode.h sparc-pinsn.c
|
||||
printcmd.o : printcmd.c defs.h initialize.h param.h symtab.h value.h expression.h
|
||||
remote.o : remote.c defs.h initialize.h param.h frame.h inferior.h
|
||||
source.o : source.c defs.h initialize.h symtab.h
|
||||
stack.o : stack.c defs.h initialize.h param.h symtab.h frame.h
|
||||
standalone.o : standalone.c defs.h initialize.h param.h symtab.h frame.h inferior.h wait.h
|
||||
symmisc.o : symmisc.c defs.h initialize.h symtab.h
|
||||
symtab.o : symtab.c defs.h initialize.h param.h symtab.h
|
||||
utils.o : utils.c defs.h
|
||||
valarith.o : valarith.c defs.h initialize.h param.h symtab.h value.h expression.h
|
||||
valops.o : valops.c defs.h initialize.h param.h symtab.h value.h
|
||||
valprint.o : valprint.c defs.h initialize.h param.h symtab.h value.h
|
||||
values.o : values.c defs.h initialize.h param.h symtab.h value.h
|
||||
version.o : version.c
|
||||
xgdb.o : xgdb.c defs.h initialize.h param.h symtab.h frame.h
|
||||
$(CC) -c $(CFLAGS) xgdb.c -o $@
|
||||
pinsn.o : ${PINSNS} defs.h param.h symtab.h obstack.h symseg.h frame.h \
|
||||
${OPCODES}
|
||||
|
||||
obstack.o : obstack.c
|
||||
#
|
||||
# The rest of this is a standard dependencies list (hand edited output of
|
||||
# cpp -M). It does not include dependencies of .o files on .c files.
|
||||
#
|
||||
blockframe.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
|
||||
breakpoint.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
|
||||
coffread.o : defs.h param.h
|
||||
command.o : command.h defs.h
|
||||
core.o : defs.h param.h a.out.encap.h
|
||||
dbxread.o : param.h defs.h symtab.h obstack.h symseg.h a.out.encap.h \
|
||||
stab.gnu.h
|
||||
environ.o : environ.h
|
||||
eval.o : defs.h param.h symtab.h obstack.h symseg.h value.h expression.h
|
||||
expprint.o : defs.h symtab.h obstack.h symseg.h param.h expression.h
|
||||
findvar.o : defs.h param.h symtab.h obstack.h symseg.h frame.h value.h
|
||||
infcmd.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \
|
||||
environ.h value.h
|
||||
inflow.o : defs.h param.h frame.h inferior.h
|
||||
infrun.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \
|
||||
wait.h
|
||||
kdb-start.o : defs.h param.h
|
||||
main.o : defs.h command.h param.h
|
||||
malloc.o : getpagesize.h
|
||||
obstack.o : obstack.h
|
||||
printcmd.o : defs.h param.h frame.h symtab.h obstack.h symseg.h value.h \
|
||||
expression.h
|
||||
regex.o : regex.h
|
||||
remote.o : defs.h param.h frame.h inferior.h wait.h
|
||||
source.o : defs.h symtab.h obstack.h symseg.h param.h
|
||||
stack.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
|
||||
standalone.o : defs.h param.h symtab.h obstack.h symseg.h frame.h \
|
||||
inferior.h wait.h
|
||||
symmisc.o : defs.h symtab.h obstack.h symseg.h obstack.h
|
||||
symtab.o : defs.h symtab.h obstack.h symseg.h param.h obstack.h
|
||||
utils.o : defs.h param.h
|
||||
valarith.o : defs.h param.h symtab.h obstack.h symseg.h value.h expression.h
|
||||
valops.o : defs.h param.h symtab.h obstack.h symseg.h value.h frame.h \
|
||||
inferior.h
|
||||
valprint.o : defs.h param.h symtab.h obstack.h symseg.h value.h
|
||||
values.o : defs.h param.h symtab.h obstack.h symseg.h value.h
|
||||
|
||||
robotussin.h : getpagesize.h
|
||||
symtab.h : obstack.h symseg.h
|
||||
a.out.encap.h : a.out.gnu.h
|
||||
|
367
gdb/RCS/Makefile,v
Normal file
367
gdb/RCS/Makefile,v
Normal file
@ -0,0 +1,367 @@
|
||||
head 1.4;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @# @;
|
||||
|
||||
|
||||
1.4
|
||||
date 89.03.27.21.28.33; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.3;
|
||||
|
||||
1.3
|
||||
date 89.03.27.18.33.31; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.2;
|
||||
|
||||
1.2
|
||||
date 89.03.13.19.02.58; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.02.09.03.15.53; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.4
|
||||
log
|
||||
@More general support for ALLOCA and other local library routines;
|
||||
other minor cleanup.
|
||||
@
|
||||
text
|
||||
@# On HPUX, you need to add -Ihp-include to CFLAGS.
|
||||
# The headers in the directory hp-include override system headers
|
||||
# and tell GDB to use BSD executable file format.
|
||||
# You must also define REGEX & REGEX1 below and ALLOCA & ALLOCA1 (get
|
||||
# alloca.c from the emacs distribution) to the CLIBS.
|
||||
# If you compile GDB with GCC on HPUX, you must make sure that the "nm" used
|
||||
# in "munch" is GNU's nm. This is because gcc uses a different .o
|
||||
# file format than the native HPUX compiler.
|
||||
|
||||
# On USG (System V) machines, you must make sure to setup REGEX &
|
||||
# REGEX1 to point at regex.o and use the USG version of CLIBS.
|
||||
# If your system has a broken alloca() -- most do -- then get
|
||||
# alloca.c from the GNU Emacs distribution and set ALLOCA & ALLOCA1.
|
||||
# Also, if you compile gdb with a compiler which uses the coff
|
||||
# encapsulation feature (this is a function of the compiler used, NOT
|
||||
# of the m-?.h file selected by config.gdb), you must make sure that
|
||||
# the GNU nm is the one that is used by munch.
|
||||
|
||||
# On Sunos 4.0 machines, make sure to compile *without* shared
|
||||
# libraries if you want to run gdb on itself. Make sure to compile
|
||||
# any program on which you want to run gdb without shared libraries.
|
||||
|
||||
# If you are compiling with GCC, make sure that either 1) You use the
|
||||
# -traditional flag, or 2) You have the fixed include files where GCC
|
||||
# can reach them. Otherwise the ioctl calls in inflow.c will be
|
||||
# incorrectly compiled. The "fixincludes" script in the gcc
|
||||
# distribution will probably fix your include files up.
|
||||
|
||||
CC=cc
|
||||
SHELL=/bin/sh
|
||||
|
||||
# Set this up with gcc if you have gnu ld and the loader will print out
|
||||
# line numbers for undefinded refs.
|
||||
CC-LD=${CC}
|
||||
|
||||
# -I. for "#include <obstack.h>". Possibly regex.h also.
|
||||
#CFLAGS = -g -pg -I. -O
|
||||
CFLAGS = -I. -g
|
||||
#LDFLAGS = -pg -g
|
||||
LDFLAGS = -g
|
||||
|
||||
# define this to be "obstack.o" if you don't have the obstack library installed
|
||||
# you must at the same time define OBSTACK1 as "obstack.o"
|
||||
# so that the dependencies work right. Similarly with REGEX and "regex.o".
|
||||
# You must define REGEX and REGEX1 on USG machines.
|
||||
# If your system is missing alloca(), or, more likely, it's there but it
|
||||
# doesn't work, define ALLOCA and ALLOCA1.
|
||||
OBSTACK = obstack.o
|
||||
OBSTACK1 = obstack.o
|
||||
REGEX = regex.o
|
||||
REGEX1 = regex.o
|
||||
ALLOCA = alloca.o
|
||||
ALLOCA1 = alloca.o
|
||||
ADD_FILES = $(OBSTACK) $(REGEX) $(ALLOCA) $(GNU_MALLOC)
|
||||
ADD_DEPS = $(OBSTACK1) $(REGEX1) $(ALLOCA1) $(GNU_MALLOC)
|
||||
|
||||
#
|
||||
# define this to be "malloc.o" if you want to use the gnu malloc routine
|
||||
# (useful for debugging memory allocation problems in gdb). Otherwise, leave
|
||||
# it blank.
|
||||
GNU_MALLOC =
|
||||
#GNU_MALLOC = malloc.o
|
||||
|
||||
# Flags to be used in compiling malloc.o
|
||||
# Specify range checking for storage allocation.
|
||||
MALLOC_FLAGS =
|
||||
#MALLOC_FLAGS = ${CFLAGS} -Drcheck -Dbotch=fatal -DMSTATS
|
||||
|
||||
# for BSD
|
||||
CLIBS = $(ADD_FILES)
|
||||
# for USG
|
||||
#CLIBS= $(ADD_FILES) -lPW
|
||||
|
||||
SFILES = blockframe.c breakpoint.c coffread.c command.c core.c dbxread.c \
|
||||
environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \
|
||||
kdb-start.c main.c printcmd.c \
|
||||
remote.c source.c stack.c standalone.c stuff.c symmisc.c symtab.c \
|
||||
utils.c valarith.c valops.c valprint.c values.c version.c expread.y \
|
||||
xgdb.c
|
||||
|
||||
DEPFILES = convex-dep.c umax-dep.c gould-dep.c default-dep.c sun3-dep.c \
|
||||
sparc-dep.c hp9k320-dep.c news-dep.c i386-dep.c
|
||||
|
||||
PINSNS = gld-pinsn.c i386-pinsn.c sparc-pinsn.c vax-pinsn.c m68k-pinsn.c \
|
||||
ns32k-pinsn.c
|
||||
|
||||
HFILES = command.h defs.h environ.h expression.h frame.h getpagesize.h \
|
||||
inferior.h symseg.h symtab.h value.h wait.h \
|
||||
a.out.encap.h a.out.gnu.h stab.gnu.h
|
||||
|
||||
OPCODES = m68k-opcode.h pn-opcode.h sparc-opcode.h npl-opcode.h vax-opcode.h \
|
||||
ns32k-opcode.h
|
||||
|
||||
MFILES = m-hp9k320.h m-i386.h m-i386gas.h m-isi.h m-merlin.h m-news.h \
|
||||
m-npl.h m-pn.h m-sparc.h m-sun2.h m-sun3.h m-sun2os4.h \
|
||||
m-sun3os4.h m-sun4os4.h m-umax.h m-vax.h
|
||||
|
||||
POSSLIBS = obstack.h obstack.c regex.c regex.h malloc.c
|
||||
|
||||
TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c
|
||||
|
||||
OTHERS = Makefile createtags munch config.gdb ChangeLog README TAGS \
|
||||
gdb.texinfo .gdbinit COPYING expread.tab.c stab.def hp-include
|
||||
|
||||
TAGFILES = ${SFILES} ${DEPFILES} ${PINSNS} ${HFILES} ${OPCODES} ${MFILES} \
|
||||
${POSSLIBS}
|
||||
TARFILES = ${TAGFILES} ${OTHERS}
|
||||
|
||||
OBS = main.o blockframe.o breakpoint.o findvar.o stack.o source.o \
|
||||
values.o eval.o valops.o valarith.o valprint.o printcmd.o \
|
||||
symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o \
|
||||
command.o utils.o expread.o expprint.o pinsn.o environ.o version.o
|
||||
|
||||
TSOBS = core.o inflow.o dep.o
|
||||
|
||||
NTSOBS = standalone.o
|
||||
|
||||
TSSTART = /lib/crt0.o
|
||||
|
||||
NTSSTART = kdb-start.o
|
||||
|
||||
gdb : $(OBS) $(TSOBS) $(ADD_DEPS)
|
||||
-rm -f init.c
|
||||
./munch $(OBS) $(TSOBS) > init.c
|
||||
${CC-LD} $(LDFLAGS) -o gdb init.c $(OBS) $(TSOBS) $(CLIBS)
|
||||
|
||||
xgdb : $(OBS) $(TSOBS) xgdb.o $(ADD_DEPS)
|
||||
-rm -f init.c
|
||||
./munch $(OBS) $(TSOBS) xgdb.o > init.c
|
||||
$(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \
|
||||
-lXaw -lXt -lX11 $(CLIBS)
|
||||
|
||||
kdb : $(NTSSTART) $(OBS) $(NTSOBS) $(ADD_DEPS)
|
||||
-rm -f init.c
|
||||
./munch $(OBS) $(NTSOBS) > init.c
|
||||
$(CC-LD) $(LDFLAGS) -c init.c $(CLIBS)
|
||||
ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o -lc $(CLIBS)
|
||||
|
||||
# If it can figure out the appropriate order, createtags will make sure
|
||||
# that the proper m-*, *-dep, *-pinsn, and *-opcode files come first
|
||||
# in the tags list. It will attempt to do the same for dbxread.c and
|
||||
# coffread.c. This makes using M-. on machine dependent routines much
|
||||
# easier.
|
||||
#
|
||||
TAGS: ${TAGFILES}
|
||||
createtags ${TAGFILES}
|
||||
tags: TAGS
|
||||
|
||||
gdb.tar: ${TARFILES}
|
||||
rm -f gdb.tar
|
||||
mkdir dist-gdb
|
||||
cd dist-gdb ; for i in ${TARFILES} ; do ln -s ../$$i . ; done
|
||||
tar chf gdb.tar dist-gdb
|
||||
rm -rf dist-gdb
|
||||
|
||||
gdb.tar.Z: gdb.tar
|
||||
compress gdb.tar
|
||||
|
||||
clean:
|
||||
-rm -f ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX}
|
||||
-rm -f init.c init.o
|
||||
-rm -f gdb
|
||||
|
||||
realclean: clean
|
||||
-rm -f expread.tab.c tags TAGS
|
||||
|
||||
xgdb.o : xgdb.c defs.h param.h symtab.h frame.h
|
||||
$(CC) -c $(CFLAGS) xgdb.c -o $@@
|
||||
|
||||
expread.tab.c : expread.y
|
||||
@@echo 'Expect 101 shift/reduce conflicts and 1 reduce/reduce conflict.'
|
||||
yacc expread.y
|
||||
mv y.tab.c expread.tab.c
|
||||
|
||||
expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h
|
||||
$(CC) -c ${CFLAGS} expread.tab.c
|
||||
mv expread.tab.o expread.o
|
||||
|
||||
#
|
||||
# Only useful if you are using the gnu malloc routines.
|
||||
#
|
||||
malloc.o : malloc.c
|
||||
${CC} -c ${MALLOC_FLAGS} malloc.c
|
||||
|
||||
#
|
||||
# dep.o depends on ALL the dep files since we don't know which one
|
||||
# is really being used.
|
||||
#
|
||||
dep.o : ${DEPFILES} defs.h param.h frame.h inferior.h obstack.h \
|
||||
a.out.encap.h
|
||||
|
||||
# pinsn.o depends on ALL the opcode printers
|
||||
# since we don't know which one is really being used.
|
||||
pinsn.o : ${PINSNS} defs.h param.h symtab.h obstack.h symseg.h frame.h \
|
||||
${OPCODES}
|
||||
|
||||
#
|
||||
# The rest of this is a standard dependencies list (hand edited output of
|
||||
# cpp -M). It does not include dependencies of .o files on .c files.
|
||||
#
|
||||
blockframe.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
|
||||
breakpoint.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
|
||||
coffread.o : defs.h param.h
|
||||
command.o : command.h defs.h
|
||||
core.o : defs.h param.h a.out.encap.h
|
||||
dbxread.o : param.h defs.h symtab.h obstack.h symseg.h a.out.encap.h \
|
||||
stab.gnu.h
|
||||
environ.o : environ.h
|
||||
eval.o : defs.h param.h symtab.h obstack.h symseg.h value.h expression.h
|
||||
expprint.o : defs.h symtab.h obstack.h symseg.h param.h expression.h
|
||||
findvar.o : defs.h param.h symtab.h obstack.h symseg.h frame.h value.h
|
||||
infcmd.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \
|
||||
environ.h value.h
|
||||
inflow.o : defs.h param.h frame.h inferior.h
|
||||
infrun.o : defs.h param.h symtab.h obstack.h symseg.h frame.h inferior.h \
|
||||
wait.h
|
||||
kdb-start.o : defs.h param.h
|
||||
main.o : defs.h command.h param.h
|
||||
malloc.o : getpagesize.h
|
||||
obstack.o : obstack.h
|
||||
printcmd.o : defs.h param.h frame.h symtab.h obstack.h symseg.h value.h \
|
||||
expression.h
|
||||
regex.o : regex.h
|
||||
remote.o : defs.h param.h frame.h inferior.h wait.h
|
||||
source.o : defs.h symtab.h obstack.h symseg.h param.h
|
||||
stack.o : defs.h param.h symtab.h obstack.h symseg.h frame.h
|
||||
standalone.o : defs.h param.h symtab.h obstack.h symseg.h frame.h \
|
||||
inferior.h wait.h
|
||||
symmisc.o : defs.h symtab.h obstack.h symseg.h obstack.h
|
||||
symtab.o : defs.h symtab.h obstack.h symseg.h param.h obstack.h
|
||||
utils.o : defs.h param.h
|
||||
valarith.o : defs.h param.h symtab.h obstack.h symseg.h value.h expression.h
|
||||
valops.o : defs.h param.h symtab.h obstack.h symseg.h value.h frame.h \
|
||||
inferior.h
|
||||
valprint.o : defs.h param.h symtab.h obstack.h symseg.h value.h
|
||||
values.o : defs.h param.h symtab.h obstack.h symseg.h value.h
|
||||
|
||||
robotussin.h : getpagesize.h
|
||||
symtab.h : obstack.h symseg.h
|
||||
a.out.encap.h : a.out.gnu.h
|
||||
@
|
||||
|
||||
|
||||
1.3
|
||||
log
|
||||
@A/UX changes. Use cc, use local regex.o, use local alloca.o
|
||||
@
|
||||
text
|
||||
@d4 2
|
||||
a5 2
|
||||
# You must also define REGEX & REGEX1 below and add alloca.o (from
|
||||
# the emacs distribution) to the CLIBS.
|
||||
d12 2
|
||||
d26 2
|
||||
a27 1
|
||||
# incorrectly compiled.
|
||||
d46 2
|
||||
d52 4
|
||||
d70 1
|
||||
a70 1
|
||||
#CLIBS = $(OBSTACK) $(REGEX) $(GNU_MALLOC)
|
||||
d72 1
|
||||
a72 1
|
||||
CLIBS= $(OBSTACK) $(REGEX) $(GNU_MALLOC) alloca.o
|
||||
d122 1
|
||||
a122 1
|
||||
gdb : $(OBS) $(TSOBS) $(OBSTACK1) $(REGEX1) ${GNU_MALLOC}
|
||||
d127 1
|
||||
a127 1
|
||||
xgdb : $(OBS) $(TSOBS) xgdb.o $(OBSTACK1) $(REGEX1) ${GNU_MALLOC}
|
||||
d133 1
|
||||
a133 1
|
||||
kdb : $(NTSSTART) $(OBS) $(NTSOBS) $(OBSTACK1) $(REGEX1) ${GNU_MALLOC}
|
||||
d161 1
|
||||
a161 1
|
||||
-rm -f init.c
|
||||
d165 1
|
||||
a165 1
|
||||
-rm -f expread.tab.c
|
||||
@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@All rm's to rm -f's.
|
||||
@
|
||||
text
|
||||
@d26 1
|
||||
a26 1
|
||||
CC=gcc
|
||||
d45 2
|
||||
a46 2
|
||||
REGEX =
|
||||
REGEX1 =
|
||||
d61 1
|
||||
a61 1
|
||||
CLIBS = $(OBSTACK) $(REGEX) $(GNU_MALLOC)
|
||||
d63 1
|
||||
a63 1
|
||||
#CLIBS= $(OBSTACK) $(REGEX) $(GNU_MALLOC) -lPW
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d26 1
|
||||
a26 1
|
||||
CC=/bin/cc
|
||||
d114 1
|
||||
a114 1
|
||||
-rm init.c
|
||||
d119 1
|
||||
a119 1
|
||||
-rm init.c
|
||||
d125 1
|
||||
a125 1
|
||||
-rm init.c
|
||||
d151 3
|
||||
a153 3
|
||||
-rm ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX}
|
||||
-rm init.c
|
||||
-rm gdb
|
||||
d156 1
|
||||
a156 1
|
||||
-rm expread.tab.c
|
||||
@
|
606
gdb/RCS/blockframe.c,v
Normal file
606
gdb/RCS/blockframe.c,v
Normal file
@ -0,0 +1,606 @@
|
||||
head 1.3;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.3
|
||||
date 89.03.16.21.09.52; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.2;
|
||||
|
||||
1.2
|
||||
date 89.02.09.23.21.53; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.02.09.15.15.16; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.3
|
||||
log
|
||||
@Don't stop the stack trace until the "next frame pointer" is zero.
|
||||
@
|
||||
text
|
||||
@/* Get info from stack frames;
|
||||
convert between frames, blocks, functions and pc values.
|
||||
Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
|
||||
/* Address of end of first object file.
|
||||
This file is assumed to be a startup file
|
||||
and frames with pc's inside it
|
||||
are treated as nonexistent. */
|
||||
|
||||
CORE_ADDR first_object_file_end;
|
||||
|
||||
/* Address of innermost stack frame (contents of FP register) */
|
||||
|
||||
static FRAME current_frame;
|
||||
|
||||
struct block *block_for_pc ();
|
||||
CORE_ADDR get_pc_function_start ();
|
||||
|
||||
/*
|
||||
* Cache for frame addresses already read by gdb. Valid only while
|
||||
* inferior is stopped. Control variables for the frame cache should
|
||||
* be local to this module.
|
||||
*/
|
||||
struct obstack frame_cache_obstack;
|
||||
|
||||
/* Return the innermost (currently executing) stack frame. */
|
||||
|
||||
FRAME
|
||||
get_current_frame ()
|
||||
{
|
||||
/* We assume its address is kept in a general register;
|
||||
param.h says which register. */
|
||||
|
||||
return current_frame;
|
||||
}
|
||||
|
||||
void
|
||||
set_current_frame (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
current_frame = frame;
|
||||
}
|
||||
|
||||
FRAME
|
||||
create_new_frame (addr, pc)
|
||||
FRAME_ADDR addr;
|
||||
CORE_ADDR pc;
|
||||
{
|
||||
struct frame_info *fci; /* Same type as FRAME */
|
||||
|
||||
fci = (struct frame_info *)
|
||||
obstack_alloc (&frame_cache_obstack,
|
||||
sizeof (struct frame_info));
|
||||
|
||||
/* Arbitrary frame */
|
||||
fci->next = (struct frame_info *) 0;
|
||||
fci->prev = (struct frame_info *) 0;
|
||||
fci->frame = addr;
|
||||
fci->next_frame = 0; /* Since arbitrary */
|
||||
fci->pc = pc;
|
||||
|
||||
#ifdef INIT_EXTRA_FRAME_INFO
|
||||
INIT_EXTRA_FRAME_INFO (fci);
|
||||
#endif
|
||||
|
||||
return fci;
|
||||
}
|
||||
|
||||
/* Return the frame that called FRAME.
|
||||
If FRAME is the original frame (it has no caller), return 0. */
|
||||
|
||||
FRAME
|
||||
get_prev_frame (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
/* We're allowed to know that FRAME and "struct frame_info *" are
|
||||
the same */
|
||||
return get_prev_frame_info (frame);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush the entire frame cache.
|
||||
*/
|
||||
void
|
||||
flush_cached_frames ()
|
||||
{
|
||||
/* Since we can't really be sure what the first object allocated was */
|
||||
obstack_free (&frame_cache_obstack, 0);
|
||||
obstack_init (&frame_cache_obstack);
|
||||
|
||||
current_frame = (struct frame_info *) 0; /* Invalidate cache */
|
||||
}
|
||||
|
||||
/* Return a structure containing various interesting information
|
||||
about a specified stack frame. */
|
||||
/* How do I justify including this function? Well, the FRAME
|
||||
identifier format has gone through several changes recently, and
|
||||
it's not completely inconceivable that it could happen again. If
|
||||
it does, have this routine around will help */
|
||||
|
||||
struct frame_info *
|
||||
get_frame_info (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
|
||||
/* Return a structure containing various interesting information
|
||||
about the frame that called NEXT_FRAME. */
|
||||
|
||||
struct frame_info *
|
||||
get_prev_frame_info (next_frame)
|
||||
FRAME next_frame;
|
||||
{
|
||||
FRAME_ADDR address;
|
||||
struct frame_info *prev;
|
||||
int fromleaf = 0;
|
||||
|
||||
/* If we are within "start" right now, don't go any higher. */
|
||||
/* This truncates stack traces of things at sigtramp() though,
|
||||
because sigtramp() doesn't have a normal return PC, it has
|
||||
garbage or a small value (seen: 3) in the return PC slot.
|
||||
It's VITAL to see where the signal occurred, so punt this. */
|
||||
#if 0
|
||||
if (next_frame && next_frame->pc < first_object_file_end)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
/* If the requested entry is in the cache, return it.
|
||||
Otherwise, figure out what the address should be for the entry
|
||||
we're about to add to the cache. */
|
||||
|
||||
if (!next_frame)
|
||||
{
|
||||
if (!current_frame)
|
||||
error ("No frame is currently selected.");
|
||||
|
||||
return current_frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we have the prev one, return it */
|
||||
if (next_frame->prev)
|
||||
return next_frame->prev;
|
||||
|
||||
/* There is a questionable, but probably always correct
|
||||
assumption being made here. The assumption is that if
|
||||
functions on a specific machine has a FUNCTION_START_OFFSET,
|
||||
then this is used by the function call instruction for some
|
||||
purpose. If the function call instruction has this much hair
|
||||
in it, it probably also sets up the frame pointer
|
||||
automatically (ie. we'll never have what I am calling a
|
||||
"leaf node", one which shares a frame pointer with it's
|
||||
calling function). This is true on a vax. The only other
|
||||
way to find this out would be to setup a seperate macro
|
||||
"FUNCTION_HAS_FRAME_POINTER", which would often be equivalent
|
||||
to SKIP_PROLOGUE modifying a pc value. */
|
||||
|
||||
#if FUNCTION_START_OFFSET == 0
|
||||
if (!(next_frame->next))
|
||||
{
|
||||
/* Innermost */
|
||||
CORE_ADDR func_start, after_prologue;
|
||||
|
||||
func_start = (get_pc_function_start (next_frame->pc) +
|
||||
FUNCTION_START_OFFSET);
|
||||
after_prologue = func_start;
|
||||
SKIP_PROLOGUE (after_prologue);
|
||||
if (after_prologue == func_start)
|
||||
{
|
||||
fromleaf = 1;
|
||||
address = next_frame->frame;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!fromleaf)
|
||||
{
|
||||
/* Two macros defined in param.h specify the machine-dependent
|
||||
actions to be performed here. */
|
||||
/* First, get the frame's chain-pointer.
|
||||
If that is zero, the frame is the outermost frame. */
|
||||
address = FRAME_CHAIN (next_frame);
|
||||
if (!FRAME_CHAIN_VALID (address, next_frame))
|
||||
return 0;
|
||||
|
||||
/* If frame has a caller, combine the chain pointer and
|
||||
the frame's own address to get the address of the caller. */
|
||||
address = FRAME_CHAIN_COMBINE (address, next_frame);
|
||||
}
|
||||
}
|
||||
|
||||
prev = (struct frame_info *)
|
||||
obstack_alloc (&frame_cache_obstack,
|
||||
sizeof (struct frame_info));
|
||||
|
||||
if (next_frame)
|
||||
next_frame->prev = prev;
|
||||
prev->next = next_frame;
|
||||
prev->prev = (struct frame_info *) 0;
|
||||
prev->frame = address;
|
||||
prev->next_frame = prev->next ? prev->next->frame : 0;
|
||||
|
||||
#ifdef INIT_EXTRA_FRAME_INFO
|
||||
INIT_EXTRA_FRAME_INFO(prev);
|
||||
#endif
|
||||
|
||||
/* This entry is in the frame queue now, which is good since
|
||||
FRAME_SAVED_PC may use that queue to figure out it's value
|
||||
(see m-sparc.h). We want the pc saved in the inferior frame. */
|
||||
prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) :
|
||||
next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ());
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
get_frame_pc (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
struct frame_info *fi;
|
||||
fi = get_frame_info (frame);
|
||||
return fi->pc;
|
||||
}
|
||||
|
||||
/* Find the addresses in which registers are saved in FRAME. */
|
||||
|
||||
void
|
||||
get_frame_saved_regs (frame_info_addr, saved_regs_addr)
|
||||
struct frame_info *frame_info_addr;
|
||||
struct frame_saved_regs *saved_regs_addr;
|
||||
{
|
||||
#if 1
|
||||
FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr);
|
||||
#else
|
||||
{
|
||||
register int regnum;
|
||||
register int regmask;
|
||||
register CORE_ADDR next_addr;
|
||||
register CORE_ADDR pc;
|
||||
int nextinsn;
|
||||
bzero (&*saved_regs_addr, sizeof *saved_regs_addr);
|
||||
if ((frame_info_addr)->pc >= ((frame_info_addr)->frame
|
||||
- CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4)
|
||||
&& (frame_info_addr)->pc <= (frame_info_addr)->frame)
|
||||
{
|
||||
next_addr = (frame_info_addr)->frame;
|
||||
pc = (frame_info_addr)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
pc = get_pc_function_start ((frame_info_addr)->pc);
|
||||
/* Verify we have a link a6 instruction next;
|
||||
if not we lose. If we win, find the address above the saved
|
||||
regs using the amount of storage from the link instruction. */
|
||||
if (044016 == read_memory_integer (pc, 2))
|
||||
{
|
||||
next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 4);
|
||||
pc += 4;
|
||||
}
|
||||
else if (047126 == read_memory_integer (pc, 2))
|
||||
{
|
||||
next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 2);
|
||||
pc+=2;
|
||||
}
|
||||
else goto lose;
|
||||
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774)
|
||||
{
|
||||
next_addr += read_memory_integer (pc += 2, 4);
|
||||
pc += 4;
|
||||
}
|
||||
}
|
||||
/* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
|
||||
/* But before that can come an fmovem. Check for it. */
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2);
|
||||
if (0xf227 == nextinsn
|
||||
&& (regmask & 0xff00) == 0xe000)
|
||||
{
|
||||
pc += 4; /* Regmask's low bit is for register fp7, the first pushed */
|
||||
for (regnum = FP0_REGNUM + 7;
|
||||
regnum >= FP0_REGNUM;
|
||||
regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr -= 12);
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
}
|
||||
if (0044327 == read_memory_integer (pc, 2))
|
||||
{
|
||||
pc += 4; /* Regmask's low bit is for register 0, the first written */
|
||||
for (regnum = 0; regnum < 16; regnum++, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr += 4) - 4;
|
||||
}
|
||||
else if (0044347 == read_memory_integer (pc, 2))
|
||||
{ pc += 4; /* Regmask's low bit is for register 15, the first pushed */
|
||||
for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr -= 4); }
|
||||
else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2)))
|
||||
{ regnum = 0xf & read_memory_integer (pc, 2); pc += 2;
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr -= 4); }
|
||||
/* fmovemx to index of sp may follow. */
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2);
|
||||
if (0xf236 == nextinsn
|
||||
&& (regmask & 0xff00) == 0xf000)
|
||||
{
|
||||
pc += 10; /* Regmask's low bit is for register fp0, the first written */
|
||||
for (regnum = FP0_REGNUM + 7;
|
||||
regnum >= FP0_REGNUM;
|
||||
regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr += 12) - 12;
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
}
|
||||
/* clrw -(sp); movw ccr,-(sp) may follow. */
|
||||
if (0x426742e7 == read_memory_integer (pc, 4))
|
||||
(*saved_regs_addr).regs[PS_REGNUM] = (next_addr -= 4);
|
||||
lose: ;
|
||||
(*saved_regs_addr).regs[SP_REGNUM] = (frame_info_addr)->frame + 8;
|
||||
(*saved_regs_addr).regs[FP_REGNUM] = (frame_info_addr)->frame;
|
||||
(*saved_regs_addr).regs[PC_REGNUM] = (frame_info_addr)->frame + 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the innermost lexical block in execution
|
||||
in a specified stack frame. The frame address is assumed valid. */
|
||||
|
||||
struct block *
|
||||
get_frame_block (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
struct frame_info *fi;
|
||||
|
||||
fi = get_frame_info (frame);
|
||||
return block_for_pc (fi->pc);
|
||||
}
|
||||
|
||||
struct block *
|
||||
get_current_block ()
|
||||
{
|
||||
return block_for_pc (read_pc ());
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
get_pc_function_start (pc)
|
||||
CORE_ADDR pc;
|
||||
{
|
||||
register struct block *bl = block_for_pc (pc);
|
||||
register struct symbol *symbol;
|
||||
if (bl == 0 || (symbol = block_function (bl)) == 0)
|
||||
{
|
||||
register int misc_index = find_pc_misc_function (pc);
|
||||
if (misc_index >= 0)
|
||||
return misc_function_vector[misc_index].address;
|
||||
return 0;
|
||||
}
|
||||
bl = SYMBOL_BLOCK_VALUE (symbol);
|
||||
return BLOCK_START (bl);
|
||||
}
|
||||
|
||||
/* Return the symbol for the function executing in frame FRAME. */
|
||||
|
||||
struct symbol *
|
||||
get_frame_function (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
register struct block *bl = get_frame_block (frame);
|
||||
if (bl == 0)
|
||||
return 0;
|
||||
return block_function (bl);
|
||||
}
|
||||
|
||||
/* Return the innermost lexical block containing the specified pc value,
|
||||
or 0 if there is none. */
|
||||
|
||||
extern struct symtab *psymtab_to_symtab ();
|
||||
|
||||
struct block *
|
||||
block_for_pc (pc)
|
||||
register CORE_ADDR pc;
|
||||
{
|
||||
register struct block *b;
|
||||
register int bot, top, half;
|
||||
register struct symtab *s;
|
||||
register struct partial_symtab *ps;
|
||||
struct blockvector *bl;
|
||||
|
||||
/* First search all symtabs for one whose file contains our pc */
|
||||
|
||||
for (s = symtab_list; s; s = s->next)
|
||||
{
|
||||
bl = BLOCKVECTOR (s);
|
||||
b = BLOCKVECTOR_BLOCK (bl, 0);
|
||||
if (BLOCK_START (b) <= pc
|
||||
&& BLOCK_END (b) > pc)
|
||||
break;
|
||||
}
|
||||
|
||||
if (s == 0)
|
||||
for (ps = partial_symtab_list; ps; ps = ps->next)
|
||||
{
|
||||
if (ps->textlow <= pc
|
||||
&& ps->texthigh > pc)
|
||||
{
|
||||
s = psymtab_to_symtab (ps);
|
||||
bl = BLOCKVECTOR (s);
|
||||
b = BLOCKVECTOR_BLOCK (bl, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == 0)
|
||||
return 0;
|
||||
|
||||
/* Then search that symtab for the smallest block that wins. */
|
||||
/* Use binary search to find the last block that starts before PC. */
|
||||
|
||||
bot = 0;
|
||||
top = BLOCKVECTOR_NBLOCKS (bl);
|
||||
|
||||
while (top - bot > 1)
|
||||
{
|
||||
half = (top - bot + 1) >> 1;
|
||||
b = BLOCKVECTOR_BLOCK (bl, bot + half);
|
||||
if (BLOCK_START (b) <= pc)
|
||||
bot += half;
|
||||
else
|
||||
top = bot + half;
|
||||
}
|
||||
|
||||
/* Now search backward for a block that ends after PC. */
|
||||
|
||||
while (bot >= 0)
|
||||
{
|
||||
b = BLOCKVECTOR_BLOCK (bl, bot);
|
||||
if (BLOCK_END (b) > pc)
|
||||
return b;
|
||||
bot--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the function containing pc value PC.
|
||||
Returns 0 if function is not known. */
|
||||
|
||||
struct symbol *
|
||||
find_pc_function (pc)
|
||||
CORE_ADDR pc;
|
||||
{
|
||||
register struct block *b = block_for_pc (pc);
|
||||
if (b == 0)
|
||||
return 0;
|
||||
return block_function (b);
|
||||
}
|
||||
|
||||
/* Find the misc function whose address is the largest
|
||||
while being less than PC. Return its index in misc_function_vector.
|
||||
Returns -1 if PC is not in suitable range. */
|
||||
|
||||
int
|
||||
find_pc_misc_function (pc)
|
||||
register CORE_ADDR pc;
|
||||
{
|
||||
register int lo = 0;
|
||||
register int hi = misc_function_count-1;
|
||||
register int new;
|
||||
register int distance;
|
||||
|
||||
/* Note that the last thing in the vector is always _etext. */
|
||||
|
||||
/* Above statement is not *always* true - fix for case where there are */
|
||||
/* no misc functions at all (ie no symbol table has been read). */
|
||||
if (hi < 0) return -1; /* no misc functions recorded */
|
||||
|
||||
/* trivial reject range test */
|
||||
if (pc < misc_function_vector[0].address ||
|
||||
pc > misc_function_vector[hi].address)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
new = (lo + hi) >> 1;
|
||||
distance = misc_function_vector[new].address - pc;
|
||||
if (distance == 0)
|
||||
return new; /* an exact match */
|
||||
else if (distance > 0)
|
||||
hi = new;
|
||||
else
|
||||
lo = new;
|
||||
} while (hi-lo != 1);
|
||||
|
||||
/* if here, we had no exact match, so return the lower choice */
|
||||
return lo;
|
||||
}
|
||||
|
||||
/* Return the innermost stack frame executing inside of the specified block,
|
||||
or zero if there is no such frame. */
|
||||
|
||||
FRAME
|
||||
block_innermost_frame (block)
|
||||
struct block *block;
|
||||
{
|
||||
struct frame_info *fi;
|
||||
register FRAME frame;
|
||||
register CORE_ADDR start = BLOCK_START (block);
|
||||
register CORE_ADDR end = BLOCK_END (block);
|
||||
|
||||
frame = 0;
|
||||
while (1)
|
||||
{
|
||||
frame = get_prev_frame (frame);
|
||||
if (frame == 0)
|
||||
return 0;
|
||||
fi = get_frame_info (frame);
|
||||
if (fi->pc >= start && fi->pc < end)
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_blockframe ()
|
||||
{
|
||||
obstack_init (&frame_cache_obstack);
|
||||
}
|
||||
@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Avoid fatal error for simple user error
|
||||
@
|
||||
text
|
||||
@d142 5
|
||||
d149 1
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d152 1
|
||||
a152 1
|
||||
fatal ("get_prev_frame_info: Called before cache primed");
|
||||
@
|
2047
gdb/RCS/coffread.c,v
Normal file
2047
gdb/RCS/coffread.c,v
Normal file
File diff suppressed because it is too large
Load Diff
229
gdb/RCS/config.gdb,v
Executable file
229
gdb/RCS/config.gdb,v
Executable file
@ -0,0 +1,229 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @@;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.03.27.18.38.55; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.13.19.14.24; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Add A/UX option (config.gdb aux).
|
||||
@
|
||||
text
|
||||
@#!/bin/sh
|
||||
|
||||
#
|
||||
# Shell script to create proper links to machine-dependent files in
|
||||
# preparation for compiling gdb.
|
||||
#
|
||||
# Usage: config.gdb machine [operating-system]
|
||||
#
|
||||
# If config.gdb succeeds, it leaves its status in config.status.
|
||||
# If config.gdb fails after disturbing the status quo,
|
||||
# config.status is removed.
|
||||
#
|
||||
|
||||
progname=$0
|
||||
|
||||
case $# in
|
||||
1)
|
||||
machine=$1
|
||||
os="none"
|
||||
;;
|
||||
2)
|
||||
machine=$1
|
||||
os=$2
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $progname machine [operating-system]"
|
||||
echo "Available machine types:"
|
||||
echo m-*.h | sed 's/m-//g' | sed 's/\.h//g'
|
||||
if [ -r config.status ]
|
||||
then
|
||||
cat config.status
|
||||
fi
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
paramfile=m-${machine}.h
|
||||
pinsnfile=${machine}-pinsn.c
|
||||
opcodefile=${machine}-opcode.h
|
||||
if [ -r ${machine}-dep.c ]
|
||||
then
|
||||
depfile=${machine}-dep.c
|
||||
else
|
||||
depfile=default-dep.c
|
||||
fi
|
||||
|
||||
#
|
||||
# Special cases.
|
||||
# If a file is not needed, set the filename to 'skip' and it will be
|
||||
# ignored.
|
||||
#
|
||||
case $machine in
|
||||
aux)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
vax)
|
||||
pinsnfile=vax-pinsn.c
|
||||
opcodefile=vax-opcode.h
|
||||
;;
|
||||
hp9k320)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
isi)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
i386)
|
||||
echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile"
|
||||
opcodefile=skip
|
||||
;;
|
||||
i386gas)
|
||||
echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile"
|
||||
echo "Use of the coff encapsulation features also requires the GNU binutils utilities"
|
||||
echo "to be ahead of their System V counterparts in your path."
|
||||
pinsnfile=i386-pinsn.c
|
||||
depfile=i386-dep.c
|
||||
opcodefile=skip
|
||||
;;
|
||||
merlin)
|
||||
pinsnfile=ns32k-pinsn.c
|
||||
opcodefile=ns32k-opcode.h
|
||||
;;
|
||||
news)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
npl)
|
||||
pinsnfile=gld-pinsn.c
|
||||
;;
|
||||
pn)
|
||||
pinsnfile=gld-pinsn.c
|
||||
;;
|
||||
sun2)
|
||||
case $os in
|
||||
os4|sunos4)
|
||||
paramfile=m-sun2os4.h
|
||||
;;
|
||||
os2|sunos2)
|
||||
paramfile=m-sun2os2.h
|
||||
esac
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun2os2)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun2os4)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun3)
|
||||
case $os in
|
||||
os4|sunos4)
|
||||
paramfile=m-sun3os4.h
|
||||
esac
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun3os4)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
depfile=sun3-dep.c
|
||||
;;
|
||||
sun4os4)
|
||||
pinsnfile=sparc-pinsn.c
|
||||
opcodefile=sparc-opcode.h
|
||||
depfile=sparc-dep.c
|
||||
;;
|
||||
umax)
|
||||
pinsnfile=ns32k-pinsn.c
|
||||
opcodefile=ns32k-opcode.h
|
||||
;;
|
||||
sparc|sun4)
|
||||
case $os in
|
||||
os4|sunos4)
|
||||
paramfile=m-sun4os4.h
|
||||
esac
|
||||
pinsnfile=sparc-pinsn.c
|
||||
opcodefile=sparc-opcode.h
|
||||
depfile=sparc-dep.c
|
||||
paramfile=m-sparc.h
|
||||
;;
|
||||
test)
|
||||
paramfile=one
|
||||
pinsnfile=three
|
||||
opcodefile=four
|
||||
;;
|
||||
*)
|
||||
echo "Unknown machine type: \`$machine'"
|
||||
echo "Available types:"
|
||||
echo m-*.h | sed 's/m-//g' | sed 's/\.h//g'
|
||||
exit 1
|
||||
esac
|
||||
|
||||
files="$paramfile $pinsnfile $opcodefile $depfile"
|
||||
links="param.h pinsn.c opcode.h dep.c"
|
||||
|
||||
while [ -n "$files" ]
|
||||
do
|
||||
# set file to car of files, files to cdr of files
|
||||
set $files; file=$1; shift; files=$*
|
||||
set $links; link=$1; shift; links=$*
|
||||
|
||||
if [ "$file" != skip ]
|
||||
then
|
||||
if [ ! -r $file ]
|
||||
then
|
||||
echo "$progname: cannot create a link \`$link',"
|
||||
echo "since the file \`$file' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f $link config.status
|
||||
# Make a symlink if possible, otherwise try a hard link
|
||||
ln -s $file $link 2>/dev/null || ln $file $link
|
||||
|
||||
if [ ! -r $link ]
|
||||
then
|
||||
echo "$progname: unable to link \`$link' to \`$file'."
|
||||
exit 1
|
||||
fi
|
||||
echo "Linked \`$link' to \`$file'."
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Links are now set up for use with a $machine." \
|
||||
| tee config.status
|
||||
exit 0
|
||||
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d53 4
|
||||
@
|
651
gdb/RCS/core.c,v
Normal file
651
gdb/RCS/core.c,v
Normal file
@ -0,0 +1,651 @@
|
||||
head 1.4;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.4
|
||||
date 89.03.27.18.39.18; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.3;
|
||||
|
||||
1.3
|
||||
date 89.02.10.01.39.45; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.2;
|
||||
|
||||
1.2
|
||||
date 89.02.09.23.22.33; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.02.09.22.49.56; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.4
|
||||
log
|
||||
@Unisoft Assholes changes for user.ps. Avoid sys/fcntl.h.
|
||||
@
|
||||
text
|
||||
@/* Work with core dump and executable files, for GDB.
|
||||
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef COFF_ENCAPSULATE
|
||||
#include "a.out.encap.h"
|
||||
#else
|
||||
#include <a.out.h>
|
||||
#endif
|
||||
|
||||
#ifndef N_MAGIC
|
||||
#ifdef COFF_FORMAT
|
||||
#define N_MAGIC(exec) ((exec).magic)
|
||||
#else
|
||||
#define N_MAGIC(exec) ((exec).a_magic)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
#define PMMU
|
||||
#define NEW_PMMU
|
||||
#include <sys/seg.h> /* Required for user.ps */
|
||||
#include <sys/time.h> /* '' */
|
||||
#include <sys/mmu.h> /* '' */
|
||||
#include <sys/reg.h>
|
||||
#define mc68881 /* Required to get float in user.ps */
|
||||
#endif
|
||||
|
||||
#ifdef UMAX_CORE
|
||||
#include <sys/ptrace.h>
|
||||
#else
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
|
||||
#ifndef N_TXTADDR
|
||||
#define N_TXTADDR(hdr) 0
|
||||
#endif /* no N_TXTADDR */
|
||||
|
||||
#ifndef N_DATADDR
|
||||
#define N_DATADDR(hdr) hdr.a_text
|
||||
#endif /* no N_DATADDR */
|
||||
|
||||
#ifndef COFF_FORMAT
|
||||
#define AOUTHDR struct exec
|
||||
#endif
|
||||
|
||||
extern char *sys_siglist[];
|
||||
|
||||
extern core_file_command (), exec_file_command ();
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
void (*exec_file_display_hook) ();
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
char *corefile;
|
||||
char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
int corechan;
|
||||
int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
|
||||
int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
CORE_ADDR data_start;
|
||||
CORE_ADDR data_end;
|
||||
CORE_ADDR stack_start;
|
||||
CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
|
||||
CORE_ADDR text_start;
|
||||
CORE_ADDR text_end;
|
||||
|
||||
CORE_ADDR exec_data_start;
|
||||
CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
int stack_offset;
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
/* various coff data structures */
|
||||
|
||||
FILHDR file_hdr;
|
||||
SCNHDR text_hdr;
|
||||
SCNHDR data_hdr;
|
||||
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
/* a.out header saved in core file. */
|
||||
|
||||
AOUTHDR core_aouthdr;
|
||||
|
||||
/* a.out header of exec file. */
|
||||
|
||||
AOUTHDR exec_aouthdr;
|
||||
|
||||
void validate_files ();
|
||||
unsigned int register_addr ();
|
||||
|
||||
/* Call this to specify the hook for exec_file_command to call back.
|
||||
This is called from the x-window display code. */
|
||||
|
||||
void
|
||||
specify_exec_file_hook (hook)
|
||||
void (*hook) ();
|
||||
{
|
||||
exec_file_display_hook = hook;
|
||||
}
|
||||
|
||||
/* The exec file must be closed before running an inferior.
|
||||
If it is needed again after the inferior dies, it must
|
||||
be reopened. */
|
||||
|
||||
void
|
||||
close_exec_file ()
|
||||
{
|
||||
if (execchan >= 0)
|
||||
close (execchan);
|
||||
execchan = -1;
|
||||
}
|
||||
|
||||
void
|
||||
reopen_exec_file ()
|
||||
{
|
||||
if (execchan < 0 && execfile != 0)
|
||||
{
|
||||
char *filename = concat (execfile, "", "");
|
||||
exec_file_command (filename, 0);
|
||||
free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have both a core file and an exec file,
|
||||
print a warning if they don't go together.
|
||||
This should really check that the core file came
|
||||
from that exec file, but I don't know how to do it. */
|
||||
|
||||
void
|
||||
validate_files ()
|
||||
{
|
||||
if (execfile != 0 && corefile != 0)
|
||||
{
|
||||
struct stat st_core;
|
||||
|
||||
fstat (corechan, &st_core);
|
||||
|
||||
if (N_MAGIC (core_aouthdr) != 0
|
||||
&& bcmp (&core_aouthdr, &exec_aouthdr, sizeof core_aouthdr))
|
||||
printf ("Warning: core file does not match specified executable file.\n");
|
||||
else if (exec_mtime > st_core.st_mtime)
|
||||
printf ("Warning: exec file is newer than core file.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the name of the executable file as a string.
|
||||
ERR nonzero means get error if there is none specified;
|
||||
otherwise return 0 in that case. */
|
||||
|
||||
char *
|
||||
get_exec_file (err)
|
||||
int err;
|
||||
{
|
||||
if (err && execfile == 0)
|
||||
error ("No executable file specified.\n\
|
||||
Use the \"exec-file\" and \"symbol-file\" commands.");
|
||||
return execfile;
|
||||
}
|
||||
|
||||
int
|
||||
have_core_file_p ()
|
||||
{
|
||||
return corefile != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
files_info ()
|
||||
{
|
||||
char *symfile;
|
||||
extern char *get_sym_file ();
|
||||
|
||||
if (execfile)
|
||||
printf ("Executable file \"%s\".\n", execfile);
|
||||
else
|
||||
printf ("No executable file\n");
|
||||
|
||||
if (corefile)
|
||||
printf ("Core dump file \"%s\".\n", corefile);
|
||||
else
|
||||
printf ("No core dump file\n");
|
||||
|
||||
if (have_inferior_p ())
|
||||
printf ("Using the running image of the program, rather than these files.\n");
|
||||
|
||||
symfile = get_sym_file ();
|
||||
if (symfile != 0)
|
||||
printf ("Symbols from \"%s\".\n", symfile);
|
||||
|
||||
if (! have_inferior_p ())
|
||||
{
|
||||
if (execfile)
|
||||
{
|
||||
printf ("Text segment in executable from 0x%x to 0x%x.\n",
|
||||
text_start, text_end);
|
||||
printf ("Data segment in executable from 0x%x to 0x%x.\n",
|
||||
exec_data_start, exec_data_end);
|
||||
if (corefile)
|
||||
printf("(But since we have a core file, we're using...)\n");
|
||||
}
|
||||
if (corefile)
|
||||
{
|
||||
printf ("Data segment in core file from 0x%x to 0x%x.\n",
|
||||
data_start, data_end);
|
||||
printf ("Stack segment in core file from 0x%x to 0x%x.\n",
|
||||
stack_start, stack_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read "memory data" from core file and/or executable file.
|
||||
Returns zero if successful, 1 if xfer_core_file failed, errno value if
|
||||
ptrace failed. */
|
||||
|
||||
int
|
||||
read_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
return read_inferior_memory (memaddr, myaddr, len);
|
||||
else
|
||||
return xfer_core_file (memaddr, myaddr, len);
|
||||
}
|
||||
|
||||
/* Write LEN bytes of data starting at address MYADDR
|
||||
into debugged program memory at address MEMADDR.
|
||||
Returns zero if successful, or an errno value if ptrace failed. */
|
||||
|
||||
int
|
||||
write_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
return write_inferior_memory (memaddr, myaddr, len);
|
||||
else
|
||||
error ("Can write memory only when program being debugged is running.");
|
||||
}
|
||||
|
||||
/* Read from the program's memory (except for inferior processes).
|
||||
This function is misnamed, since it only reads, never writes; and
|
||||
since it will use the core file and/or executable file as necessary.
|
||||
|
||||
It should be extended to write as well as read, FIXME, for patching files.
|
||||
|
||||
Return 0 if address could be read, 1 if not. */
|
||||
|
||||
int
|
||||
xfer_core_file (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
register int val;
|
||||
int xferchan;
|
||||
char **xferfile;
|
||||
int fileptr;
|
||||
int returnval = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
xferfile = 0;
|
||||
xferchan = 0;
|
||||
|
||||
/* Determine which file the next bunch of addresses reside in,
|
||||
and where in the file. Set the file's read/write pointer
|
||||
to point at the proper place for the desired address
|
||||
and set xferfile and xferchan for the correct file.
|
||||
|
||||
If desired address is nonexistent, leave them zero.
|
||||
|
||||
i is set to the number of bytes that can be handled
|
||||
along with the next address.
|
||||
|
||||
We put the most likely tests first for efficiency. */
|
||||
|
||||
/* Note that if there is no core file
|
||||
data_start and data_end are equal. */
|
||||
if (memaddr >= data_start && memaddr < data_end)
|
||||
{
|
||||
i = min (len, data_end - memaddr);
|
||||
fileptr = memaddr - data_start + data_offset;
|
||||
xferfile = &corefile;
|
||||
xferchan = corechan;
|
||||
}
|
||||
/* Note that if there is no core file
|
||||
stack_start and stack_end are equal. */
|
||||
else if (memaddr >= stack_start && memaddr < stack_end)
|
||||
{
|
||||
i = min (len, stack_end - memaddr);
|
||||
fileptr = memaddr - stack_start + stack_offset;
|
||||
xferfile = &corefile;
|
||||
xferchan = corechan;
|
||||
}
|
||||
else if (corechan < 0
|
||||
&& memaddr >= exec_data_start && memaddr < exec_data_end)
|
||||
{
|
||||
i = min (len, exec_data_end - memaddr);
|
||||
fileptr = memaddr - exec_data_start + exec_data_offset;
|
||||
xferfile = &execfile;
|
||||
xferchan = execchan;
|
||||
}
|
||||
else if (memaddr >= text_start && memaddr < text_end)
|
||||
{
|
||||
i = min (len, text_end - memaddr);
|
||||
fileptr = memaddr - text_start + text_offset;
|
||||
xferfile = &execfile;
|
||||
xferchan = execchan;
|
||||
}
|
||||
else if (memaddr < text_start)
|
||||
{
|
||||
i = min (len, text_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= text_end
|
||||
&& memaddr < (corechan >= 0? data_start : exec_data_start))
|
||||
{
|
||||
i = min (len, data_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end)
|
||||
&& memaddr < stack_start)
|
||||
{
|
||||
i = min (len, stack_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= stack_end && stack_end != 0)
|
||||
{
|
||||
i = min (len, - memaddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Address did not classify into one of the known ranges.
|
||||
This could be because data_start != exec_data_start
|
||||
or data_end similarly. */
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Now we know which file to use.
|
||||
Set up its pointer and transfer the data. */
|
||||
if (xferfile)
|
||||
{
|
||||
if (*xferfile == 0)
|
||||
if (xferfile == &execfile)
|
||||
error ("No program file to examine.");
|
||||
else
|
||||
error ("No core dump file or running program to examine.");
|
||||
val = lseek (xferchan, fileptr, 0);
|
||||
if (val < 0)
|
||||
perror_with_name (*xferfile);
|
||||
val = myread (xferchan, myaddr, i);
|
||||
if (val < 0)
|
||||
perror_with_name (*xferfile);
|
||||
}
|
||||
/* If this address is for nonexistent memory,
|
||||
read zeros if reading, or do nothing if writing.
|
||||
(FIXME we never write.) */
|
||||
else
|
||||
{
|
||||
bzero (myaddr, i);
|
||||
returnval = 1;
|
||||
}
|
||||
|
||||
memaddr += i;
|
||||
myaddr += i;
|
||||
len -= i;
|
||||
}
|
||||
return returnval;
|
||||
}
|
||||
|
||||
/* My replacement for the read system call.
|
||||
Used like `read' but keeps going if `read' returns too soon. */
|
||||
|
||||
int
|
||||
myread (desc, addr, len)
|
||||
int desc;
|
||||
char *addr;
|
||||
int len;
|
||||
{
|
||||
register int val;
|
||||
int orglen = len;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
val = read (desc, addr, len);
|
||||
if (val < 0)
|
||||
return val;
|
||||
if (val == 0)
|
||||
return orglen - len;
|
||||
len -= val;
|
||||
addr += val;
|
||||
}
|
||||
return orglen;
|
||||
}
|
||||
|
||||
#ifdef REGISTER_U_ADDR
|
||||
|
||||
/* Return the address in the core dump or inferior of register REGNO.
|
||||
BLOCKEND is the address of the end of the user structure. */
|
||||
|
||||
unsigned int
|
||||
register_addr (regno, blockend)
|
||||
int regno;
|
||||
int blockend;
|
||||
{
|
||||
int addr;
|
||||
|
||||
if (regno < 0 || regno >= NUM_REGS)
|
||||
error ("Invalid register number %d.", regno);
|
||||
|
||||
REGISTER_U_ADDR (addr, blockend, regno);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#endif /* REGISTER_U_ADDR */
|
||||
|
||||
void
|
||||
_initialize_core()
|
||||
{
|
||||
corechan = -1;
|
||||
execchan = -1;
|
||||
corefile = 0;
|
||||
execfile = 0;
|
||||
exec_file_display_hook = 0;
|
||||
|
||||
text_start = 0;
|
||||
text_end = 0;
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
exec_data_start = 0;
|
||||
exec_data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
add_com ("core-file", class_files, core_file_command,
|
||||
"Use FILE as core dump for examining memory and registers.\n\
|
||||
No arg means have no core file.");
|
||||
add_com ("exec-file", class_files, exec_file_command,
|
||||
"Use FILE as program for getting contents of pure memory.\n\
|
||||
If FILE cannot be found as specified, your execution directory path\n\
|
||||
is searched for a command of that name.\n\
|
||||
No arg means have no executable file.");
|
||||
add_info ("files", files_info, "Names of files being debugged.");
|
||||
}
|
||||
|
||||
@
|
||||
|
||||
|
||||
1.3
|
||||
log
|
||||
@Fix up "info files" some more, to give more information.
|
||||
Rearrange the tests in xfer_core_file to avoid dependencies
|
||||
between data_start and exec_data_start, and for efficiency
|
||||
and add an abort() to test correctness. (If you take out
|
||||
never mind...)
|
||||
@
|
||||
text
|
||||
@d27 1
|
||||
a27 1
|
||||
#include <sys/fcntl.h>
|
||||
d50 10
|
||||
@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Create gdbcore.h for externally visible variables;
|
||||
spiff up the "info files" output to make it easier to read and more
|
||||
informative.
|
||||
@
|
||||
text
|
||||
@d250 4
|
||||
d257 4
|
||||
a260 7
|
||||
printf ("Data segment in core file from 0x%x to 0x%x.\nStack segment in core file from 0x%x to 0x%x.\n",
|
||||
data_start, data_end, stack_start, stack_end);
|
||||
}
|
||||
else if (execfile)
|
||||
{
|
||||
printf ("Data segment in executable from 0x%x to 0x%x.\n",
|
||||
exec_data_start, exec_data_end);
|
||||
d297 3
|
||||
a299 1
|
||||
/* Return 0 if address could be read, 1 if not. */
|
||||
d301 4
|
||||
d327 1
|
||||
d329 1
|
||||
d331 3
|
||||
a333 1
|
||||
along with the next address. */
|
||||
a334 17
|
||||
if (memaddr < text_start)
|
||||
{
|
||||
i = min (len, text_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= text_end && memaddr < data_start)
|
||||
{
|
||||
i = min (len, data_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end)
|
||||
&& memaddr < stack_start)
|
||||
{
|
||||
i = min (len, stack_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= stack_end && stack_end != 0)
|
||||
{
|
||||
i = min (len, - memaddr);
|
||||
}
|
||||
d337 1
|
||||
a337 1
|
||||
else if (memaddr >= data_start && memaddr < data_end)
|
||||
d368 25
|
||||
d411 2
|
||||
a412 1
|
||||
read zeros if reading, or do nothing if writing. */
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d2 1
|
||||
a2 1
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
d23 1
|
||||
d35 1
|
||||
d43 1
|
||||
d231 4
|
||||
a234 1
|
||||
if (corefile == 0)
|
||||
a235 2
|
||||
else
|
||||
printf ("Core dump file \"%s\".\n", corefile);
|
||||
d242 1
|
||||
a242 1
|
||||
printf ("Symbols loaded from \"%s\".\n", symfile);
|
||||
d248 1
|
||||
a248 1
|
||||
printf ("Text segment from 0x%x to 0x%x.\n",
|
||||
d253 1
|
||||
a253 1
|
||||
printf ("Data segment from 0x%x to 0x%x.\nStack segment from 0x%x to 0x%x.\n",
|
||||
d256 1
|
||||
a256 1
|
||||
else
|
||||
@
|
4610
gdb/RCS/dbxread.c,v
Normal file
4610
gdb/RCS/dbxread.c,v
Normal file
File diff suppressed because it is too large
Load Diff
731
gdb/RCS/default-dep.c,v
Normal file
731
gdb/RCS/default-dep.c,v
Normal file
@ -0,0 +1,731 @@
|
||||
head 1.4;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.4
|
||||
date 89.03.27.20.08.50; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.3;
|
||||
|
||||
1.3
|
||||
date 89.03.27.20.07.47; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.2;
|
||||
|
||||
1.2
|
||||
date 89.03.27.18.49.06; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.20.19.47.11; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.4
|
||||
log
|
||||
@Restore A/UX-specific changes.
|
||||
@
|
||||
text
|
||||
@/* Low level interface to ptrace, for GDB when running under Unix.
|
||||
Copyright (C) 1988 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
#define PMMU
|
||||
#define NEW_PMMU
|
||||
#define mc68881 /* Needed to get float in user.h!!! */
|
||||
#include <sys/seg.h> /* For user.h */
|
||||
#include <sys/mmu.h>
|
||||
#include <sys/time.h>
|
||||
/* Things Unisoft defined differently from every other Unix system */
|
||||
#define NBPG PAGESIZE
|
||||
#define UPAGES USIZE
|
||||
#define KERNEL_U_ADDR UDOT
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef COFF_ENCAPSULATE
|
||||
#include "a.out.encap.h"
|
||||
#else
|
||||
#include <a.out.h>
|
||||
#endif
|
||||
#ifndef N_SET_MAGIC
|
||||
#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
|
||||
#endif
|
||||
|
||||
#include <sys/user.h> /* After a.out.h */
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
/* This function simply calls ptrace with the given arguments.
|
||||
It exists so that all calls to ptrace are isolated in this
|
||||
machine-dependent file.
|
||||
|
||||
If you are having trouble debugging ptrace calls, turn on DEBUG
|
||||
and every call to ptrace, in this module or elsewhere, will be
|
||||
logged to stderr. */
|
||||
int
|
||||
call_ptrace (request, pid, arg3, arg4)
|
||||
int request, pid, arg3, arg4;
|
||||
{
|
||||
#ifdef DEBUG
|
||||
int result;
|
||||
|
||||
fprintf(stderr, "ptrace(%x,,%x, %x) = ", request, arg3, arg4);
|
||||
result=ptrace (request, pid, arg3, arg4);
|
||||
fprintf(stderr, "%x\n", result);
|
||||
return result;
|
||||
|
||||
#define ptrace call_ptrace
|
||||
|
||||
#else
|
||||
return ptrace (request, pid, arg3, arg4);
|
||||
#endif
|
||||
}
|
||||
|
||||
kill_inferior ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
inferior_died ();
|
||||
}
|
||||
|
||||
/* This is used when GDB is exiting. It gives less chance of error.*/
|
||||
|
||||
kill_inferior_fast ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
}
|
||||
|
||||
/* Resume execution of the inferior process.
|
||||
If STEP is nonzero, single-step it.
|
||||
If SIGNAL is nonzero, give it that signal. */
|
||||
|
||||
void
|
||||
resume (step, signal)
|
||||
int step;
|
||||
int signal;
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_resume (step, signal);
|
||||
else
|
||||
{
|
||||
ptrace (step ? 9 : 7, inferior_pid, 1, signal);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers ()
|
||||
{
|
||||
register int regno;
|
||||
register unsigned int regaddr;
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
*(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
If REGNO is -1, do this for all registers.
|
||||
Otherwise, REGNO specifies which register (so we can save time). */
|
||||
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[80];
|
||||
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
|
||||
|
||||
if (regno >= 0)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
errno = 0;
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
/* You can't write the PC with ptrace 6, only with ptrace 11! */
|
||||
if (regno == PC_REGNUM)
|
||||
ptrace(11, inferior_pid, 16, read_register(regno));
|
||||
else
|
||||
#endif
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
else for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
errno = 0;
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
if (regno == PC_REGNUM)
|
||||
ptrace(11, inferior_pid, 16, read_register(regno));
|
||||
else
|
||||
#endif
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing all regs, number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy LEN bytes from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR.
|
||||
On failure (cannot read from inferior, usually because address is out
|
||||
of bounds) returns the value of errno. */
|
||||
|
||||
int
|
||||
read_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
buffer[i] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[i] = ptrace (1, inferior_pid, addr, 0);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy LEN bytes of data from debugger memory at MYADDR
|
||||
to inferior's memory at MEMADDR.
|
||||
On failure (cannot write the inferior)
|
||||
returns the value of errno. */
|
||||
|
||||
int
|
||||
write_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Fill start and end extra bytes of buffer with existing memory data. */
|
||||
|
||||
if (remote_debugging)
|
||||
buffer[0] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[0] = ptrace (1, inferior_pid, addr, 0);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
if (remote_debugging)
|
||||
buffer[count - 1]
|
||||
= remote_fetch_word (addr + (count - 1) * sizeof (int));
|
||||
else
|
||||
buffer[count - 1]
|
||||
= ptrace (1, inferior_pid,
|
||||
addr + (count - 1) * sizeof (int), 0);
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_store_word (addr, buffer[i]);
|
||||
else
|
||||
ptrace (4, inferior_pid, addr, buffer[i]);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
This code would be in core.c if it weren't machine-dependent. */
|
||||
|
||||
/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
|
||||
#ifdef AOUTHDR
|
||||
#define COFF_FORMAT
|
||||
#endif
|
||||
|
||||
#ifndef N_TXTADDR
|
||||
#define N_TXTADDR(hdr) 0
|
||||
#endif /* no N_TXTADDR */
|
||||
|
||||
#ifndef N_DATADDR
|
||||
#define N_DATADDR(hdr) hdr.a_text
|
||||
#endif /* no N_DATADDR */
|
||||
|
||||
/* Make COFF and non-COFF names for things a little more compatible
|
||||
to reduce conditionals later. */
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
#define a_magic magic
|
||||
#endif
|
||||
|
||||
#ifndef COFF_FORMAT
|
||||
#define AOUTHDR struct exec
|
||||
#endif
|
||||
|
||||
extern char *sys_siglist[];
|
||||
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
extern void (*exec_file_display_hook) ();
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
extern char *corefile;
|
||||
extern char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
extern int corechan;
|
||||
extern int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
|
||||
extern int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
extern CORE_ADDR data_start;
|
||||
extern CORE_ADDR data_end;
|
||||
extern CORE_ADDR stack_start;
|
||||
extern CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
|
||||
extern CORE_ADDR text_start;
|
||||
extern CORE_ADDR text_end;
|
||||
|
||||
extern CORE_ADDR exec_data_start;
|
||||
extern CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
extern int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
extern int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
extern int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
extern int stack_offset;
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
/* various coff data structures */
|
||||
|
||||
extern FILHDR file_hdr;
|
||||
extern SCNHDR text_hdr;
|
||||
extern SCNHDR data_hdr;
|
||||
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
/* a.out header saved in core file. */
|
||||
|
||||
extern AOUTHDR core_aouthdr;
|
||||
|
||||
/* a.out header of exec file. */
|
||||
|
||||
extern AOUTHDR exec_aouthdr;
|
||||
|
||||
extern void validate_files ();
|
||||
|
||||
core_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
if (corefile)
|
||||
free (corefile);
|
||||
corefile = 0;
|
||||
|
||||
if (corechan >= 0)
|
||||
close (corechan);
|
||||
corechan = -1;
|
||||
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
/* Now, if a new core file was specified, open it and digest it. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
error ("To look at a core file, you must kill the inferior with \"kill\".");
|
||||
corechan = open (filename, O_RDONLY, 0);
|
||||
if (corechan < 0)
|
||||
perror_with_name (filename);
|
||||
/* 4.2-style (and perhaps also sysV-style) core dump file. */
|
||||
{
|
||||
struct user u;
|
||||
|
||||
int reg_offset;
|
||||
|
||||
val = myread (corechan, &u, sizeof u);
|
||||
if (val < 0)
|
||||
perror_with_name ("Not a core file: reading upage");
|
||||
if (val != sizeof u)
|
||||
error ("Not a core file: could only read %d bytes", val);
|
||||
data_start = exec_data_start;
|
||||
|
||||
data_end = data_start + NBPG * u.u_dsize;
|
||||
stack_start = stack_end - NBPG * u.u_ssize;
|
||||
data_offset = NBPG * UPAGES;
|
||||
stack_offset = NBPG * (UPAGES + u.u_dsize);
|
||||
|
||||
/* Some machines put an absolute address in here; Unisoft
|
||||
seems to put the offset in the upage of the regs. Sigh. */
|
||||
reg_offset = (int) u.u_ar0;
|
||||
if (reg_offset > NBPG * UPAGES)
|
||||
reg_offset -= KERNEL_U_ADDR;
|
||||
|
||||
/* I don't know where to find this info.
|
||||
So, for now, mark it as not available. */
|
||||
N_SET_MAGIC (core_aouthdr, 0);
|
||||
|
||||
/* Read the register values out of the core file and store
|
||||
them where `read_register' will find them. */
|
||||
|
||||
{
|
||||
register int regno;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
val = lseek (corechan, register_addr (regno, reg_offset), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (reg_names[regno]);
|
||||
|
||||
val = myread (corechan, buf, sizeof buf);
|
||||
if (val < 0)
|
||||
perror_with_name (reg_names[regno]);
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filename[0] == '/')
|
||||
corefile = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
corefile = concat (current_directory, "/", filename);
|
||||
}
|
||||
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
|
||||
read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No core file now.\n");
|
||||
}
|
||||
|
||||
exec_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
|
||||
/* Eliminate all traces of old exec file.
|
||||
Mark text segment as empty. */
|
||||
|
||||
if (execfile)
|
||||
free (execfile);
|
||||
execfile = 0;
|
||||
data_start = 0;
|
||||
data_end -= exec_data_start;
|
||||
text_start = 0;
|
||||
text_end = 0;
|
||||
exec_data_start = 0;
|
||||
exec_data_end = 0;
|
||||
if (execchan >= 0)
|
||||
close (execchan);
|
||||
execchan = -1;
|
||||
|
||||
/* Now open and digest the file the user requested, if any. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
|
||||
&execfile);
|
||||
if (execchan < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
{
|
||||
int aout_hdrsize;
|
||||
int num_sections;
|
||||
|
||||
if (read_file_hdr (execchan, &file_hdr) < 0)
|
||||
error ("\"%s\": not in executable format.", execfile);
|
||||
|
||||
aout_hdrsize = file_hdr.f_opthdr;
|
||||
num_sections = file_hdr.f_nscns;
|
||||
|
||||
if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
|
||||
error ("\"%s\": can't read optional aouthdr", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read text section header", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read data section header", execfile);
|
||||
|
||||
text_start = exec_aouthdr.text_start;
|
||||
text_end = text_start + exec_aouthdr.tsize;
|
||||
text_offset = text_hdr.s_scnptr;
|
||||
exec_data_start = exec_aouthdr.data_start;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.dsize;
|
||||
exec_data_offset = data_hdr.s_scnptr;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
exec_mtime = file_hdr.f_timdat;
|
||||
}
|
||||
#else /* not COFF_FORMAT */
|
||||
{
|
||||
struct stat st_exec;
|
||||
|
||||
#ifdef HEADER_SEEK_FD
|
||||
HEADER_SEEK_FD (execchan);
|
||||
#endif
|
||||
|
||||
val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
|
||||
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
text_start = N_TXTADDR (exec_aouthdr);
|
||||
exec_data_start = N_DATADDR (exec_aouthdr);
|
||||
|
||||
text_offset = N_TXTOFF (exec_aouthdr);
|
||||
exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
|
||||
|
||||
text_end = text_start + exec_aouthdr.a_text;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.a_data;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
|
||||
fstat (execchan, &st_exec);
|
||||
exec_mtime = st_exec.st_mtime;
|
||||
}
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No exec file now.\n");
|
||||
|
||||
/* Tell display code (if any) about the changed file name. */
|
||||
if (exec_file_display_hook)
|
||||
(*exec_file_display_hook) (filename);
|
||||
}
|
||||
@
|
||||
|
||||
|
||||
1.3
|
||||
log
|
||||
@Remove A/UX-specific changes for shipping to FSF.
|
||||
@
|
||||
text
|
||||
@d30 13
|
||||
d176 7
|
||||
a182 1
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
d193 6
|
||||
a198 1
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@A/UX and USG changes, and a little better error reporting.
|
||||
@
|
||||
text
|
||||
@a29 13
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
#define PMMU
|
||||
#define NEW_PMMU
|
||||
#define mc68881 /* Needed to get float in user.h!!! */
|
||||
#include <sys/seg.h> /* For user.h */
|
||||
#include <sys/mmu.h>
|
||||
#include <sys/time.h>
|
||||
/* Things Unisoft defined differently from every other Unix system */
|
||||
#define NBPG PAGESIZE
|
||||
#define UPAGES USIZE
|
||||
#define KERNEL_U_ADDR UDOT
|
||||
#endif
|
||||
|
||||
d163 1
|
||||
a163 7
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
/* You can't write the PC with ptrace 6, only with ptrace 11! */
|
||||
if (regno == PC_REGNUM)
|
||||
ptrace(11, inferior_pid, 16, read_register(regno));
|
||||
else
|
||||
#endif
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
d174 1
|
||||
a174 6
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
if (regno == PC_REGNUM)
|
||||
ptrace(11, inferior_pid, 16, read_register(regno));
|
||||
else
|
||||
#endif
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d30 13
|
||||
a46 1
|
||||
#include <sys/user.h>
|
||||
d58 2
|
||||
d67 5
|
||||
a71 1
|
||||
machine-dependent file. */
|
||||
d76 11
|
||||
d88 1
|
||||
d176 7
|
||||
a182 1
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
d193 6
|
||||
a198 1
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
d201 1
|
||||
a201 1
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
d446 3
|
||||
a448 1
|
||||
perror_with_name (filename);
|
||||
d455 6
|
||||
a460 1
|
||||
reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
|
||||
d478 1
|
||||
a478 1
|
||||
perror_with_name (filename);
|
||||
d482 1
|
||||
a482 1
|
||||
perror_with_name (filename);
|
||||
@
|
584
gdb/RCS/findvar.c,v
Normal file
584
gdb/RCS/findvar.c,v
Normal file
@ -0,0 +1,584 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.04.26.01.06.46; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.04.25.15.38.48; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@use XXX_BIG_ENDIAN macros rather than runtime tests.
|
||||
@
|
||||
text
|
||||
@/* Find a variable's value in memory, for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
#include "value.h"
|
||||
|
||||
CORE_ADDR read_register ();
|
||||
|
||||
/* Return the address in which frame FRAME's value of register REGNUM
|
||||
has been saved in memory. Or return zero if it has not been saved.
|
||||
If REGNUM specifies the SP, the value we return is actually
|
||||
the SP value, not an address where it was saved. */
|
||||
|
||||
CORE_ADDR
|
||||
find_saved_register (frame, regnum)
|
||||
FRAME frame;
|
||||
int regnum;
|
||||
{
|
||||
struct frame_info *fi;
|
||||
struct frame_saved_regs saved_regs;
|
||||
|
||||
register FRAME frame1 = 0;
|
||||
register CORE_ADDR addr = 0;
|
||||
|
||||
#ifdef HAVE_REGISTER_WINDOWS
|
||||
/* We assume that a register in a register window will only be saved
|
||||
in one place (since the name changes and dissapears as you go
|
||||
towards inner frames), so we only call get_frame_saved_regs on
|
||||
the current frame. This is directly in contradiction to the
|
||||
usage below, which assumes that registers used in a frame must be
|
||||
saved in a lower (more interior) frame. This change is a result
|
||||
of working on a register window machine; get_frame_saved_regs
|
||||
always returns the registers saved within a frame, within the
|
||||
context (register namespace) of that frame. */
|
||||
|
||||
if (REGISTER_IN_WINDOW_P(regnum))
|
||||
{
|
||||
fi = get_frame_info (frame);
|
||||
get_frame_saved_regs (fi, &saved_regs);
|
||||
return (saved_regs.regs[regnum] ?
|
||||
saved_regs.regs[regnum] : 0);
|
||||
}
|
||||
#endif /* HAVE_REGISTER_WINDOWS */
|
||||
|
||||
/* Note that this next routine assumes that registers used in
|
||||
frame x will be saved only in the frame that x calls and
|
||||
frames interior to it. This is not true on the sparc, but the
|
||||
above macro takes care of it, so we should be all right. */
|
||||
while (1)
|
||||
{
|
||||
QUIT;
|
||||
frame1 = get_prev_frame (frame1);
|
||||
if (frame1 == 0 || frame1 == frame)
|
||||
break;
|
||||
fi = get_frame_info (frame1);
|
||||
get_frame_saved_regs (fi, &saved_regs);
|
||||
if (saved_regs.regs[regnum])
|
||||
addr = saved_regs.regs[regnum];
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* Copy the bytes of register REGNUM, relative to the current stack frame,
|
||||
into our memory at MYADDR.
|
||||
The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). */
|
||||
|
||||
void
|
||||
read_relative_register_raw_bytes (regnum, myaddr)
|
||||
int regnum;
|
||||
char *myaddr;
|
||||
{
|
||||
register CORE_ADDR addr;
|
||||
|
||||
if (regnum == FP_REGNUM)
|
||||
{
|
||||
bcopy (&FRAME_FP(selected_frame), myaddr, sizeof (CORE_ADDR));
|
||||
return;
|
||||
}
|
||||
|
||||
addr = find_saved_register (selected_frame, regnum);
|
||||
|
||||
if (addr)
|
||||
{
|
||||
if (regnum == SP_REGNUM)
|
||||
{
|
||||
CORE_ADDR buffer = addr;
|
||||
bcopy (&buffer, myaddr, sizeof (CORE_ADDR));
|
||||
}
|
||||
else
|
||||
read_memory (addr, myaddr, REGISTER_RAW_SIZE (regnum));
|
||||
return;
|
||||
}
|
||||
read_register_bytes (REGISTER_BYTE (regnum),
|
||||
myaddr, REGISTER_RAW_SIZE (regnum));
|
||||
}
|
||||
|
||||
/* Return a `value' with the contents of register REGNUM
|
||||
in its virtual format, with the type specified by
|
||||
REGISTER_VIRTUAL_TYPE. */
|
||||
|
||||
value
|
||||
value_of_register (regnum)
|
||||
int regnum;
|
||||
{
|
||||
register CORE_ADDR addr;
|
||||
register value val;
|
||||
char raw_buffer[MAX_REGISTER_RAW_SIZE];
|
||||
char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
|
||||
|
||||
if (! (have_inferior_p () || have_core_file_p ()))
|
||||
error ("Can't get value of register without inferior or core file");
|
||||
|
||||
addr = find_saved_register (selected_frame, regnum);
|
||||
if (addr)
|
||||
{
|
||||
if (regnum == SP_REGNUM)
|
||||
return value_from_long (builtin_type_int, (LONGEST) addr);
|
||||
read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
|
||||
}
|
||||
else
|
||||
read_register_bytes (REGISTER_BYTE (regnum), raw_buffer,
|
||||
REGISTER_RAW_SIZE (regnum));
|
||||
|
||||
REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
|
||||
val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
|
||||
bcopy (virtual_buffer, VALUE_CONTENTS (val), REGISTER_VIRTUAL_SIZE (regnum));
|
||||
VALUE_LVAL (val) = addr ? lval_memory : lval_register;
|
||||
VALUE_ADDRESS (val) = addr ? addr : REGISTER_BYTE (regnum);
|
||||
VALUE_REGNO (val) = regnum;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Low level examining and depositing of registers.
|
||||
|
||||
Note that you must call `fetch_registers' once
|
||||
before examining or depositing any registers. */
|
||||
|
||||
char registers[REGISTER_BYTES];
|
||||
|
||||
/* Copy LEN bytes of consecutive data from registers
|
||||
starting with the REGBYTE'th byte of register data
|
||||
into memory at MYADDR. */
|
||||
|
||||
void
|
||||
read_register_bytes (regbyte, myaddr, len)
|
||||
int regbyte;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
bcopy (®isters[regbyte], myaddr, len);
|
||||
}
|
||||
|
||||
/* Copy LEN bytes of consecutive data from memory at MYADDR
|
||||
into registers starting with the REGBYTE'th byte of register data. */
|
||||
|
||||
void
|
||||
write_register_bytes (regbyte, myaddr, len)
|
||||
int regbyte;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
bcopy (myaddr, ®isters[regbyte], len);
|
||||
if (have_inferior_p ())
|
||||
store_inferior_registers (-1);
|
||||
}
|
||||
|
||||
/* Return the contents of register REGNO,
|
||||
regarding it as an integer. */
|
||||
|
||||
CORE_ADDR
|
||||
read_register (regno)
|
||||
int regno;
|
||||
{
|
||||
/* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
|
||||
return *(int *) ®isters[REGISTER_BYTE (regno)];
|
||||
}
|
||||
|
||||
/* Store VALUE in the register number REGNO, regarded as an integer. */
|
||||
|
||||
void
|
||||
write_register (regno, val)
|
||||
int regno, val;
|
||||
{
|
||||
/* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
|
||||
#if defined(sun4)
|
||||
/* This is a no-op on a Sun 4. */
|
||||
if (regno == 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
*(int *) ®isters[REGISTER_BYTE (regno)] = val;
|
||||
|
||||
if (have_inferior_p ())
|
||||
store_inferior_registers (regno);
|
||||
}
|
||||
|
||||
/* Record that register REGNO contains VAL.
|
||||
This is used when the value is obtained from the inferior or core dump,
|
||||
so there is no need to store the value there. */
|
||||
|
||||
void
|
||||
supply_register (regno, val)
|
||||
int regno;
|
||||
char *val;
|
||||
{
|
||||
bcopy (val, ®isters[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno));
|
||||
}
|
||||
|
||||
/* Given a struct symbol for a variable,
|
||||
and a stack frame address, read the value of the variable
|
||||
and return a (pointer to a) struct value containing the value. */
|
||||
|
||||
value
|
||||
read_var_value (var, frame)
|
||||
register struct symbol *var;
|
||||
FRAME frame;
|
||||
{
|
||||
register value v;
|
||||
|
||||
struct frame_info *fi;
|
||||
|
||||
struct type *type = SYMBOL_TYPE (var);
|
||||
register CORE_ADDR addr = 0;
|
||||
int val = SYMBOL_VALUE (var);
|
||||
register int len;
|
||||
|
||||
v = allocate_value (type);
|
||||
VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */
|
||||
len = TYPE_LENGTH (type);
|
||||
|
||||
if (frame == 0) frame = selected_frame;
|
||||
|
||||
switch (SYMBOL_CLASS (var))
|
||||
{
|
||||
case LOC_CONST:
|
||||
case LOC_LABEL:
|
||||
bcopy (&val, VALUE_CONTENTS (v), len);
|
||||
VALUE_LVAL (v) = not_lval;
|
||||
return v;
|
||||
|
||||
case LOC_CONST_BYTES:
|
||||
bcopy (val, VALUE_CONTENTS (v), len);
|
||||
VALUE_LVAL (v) = not_lval;
|
||||
return v;
|
||||
|
||||
case LOC_STATIC:
|
||||
addr = val;
|
||||
break;
|
||||
|
||||
case LOC_ARG:
|
||||
fi = get_frame_info (frame);
|
||||
addr = val + FRAME_ARGS_ADDRESS (fi);
|
||||
break;
|
||||
|
||||
case LOC_LOCAL:
|
||||
fi = get_frame_info (frame);
|
||||
addr = val + FRAME_LOCALS_ADDRESS (fi);
|
||||
break;
|
||||
|
||||
case LOC_TYPEDEF:
|
||||
error ("Cannot look up value of a typedef");
|
||||
|
||||
case LOC_BLOCK:
|
||||
VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
|
||||
return v;
|
||||
|
||||
case LOC_REGISTER:
|
||||
case LOC_REGPARM:
|
||||
v = value_from_register (type, val, frame);
|
||||
return v;
|
||||
}
|
||||
|
||||
read_memory (addr, VALUE_CONTENTS (v), len);
|
||||
VALUE_ADDRESS (v) = addr;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Return a value of type TYPE, stored in register REGNUM, in frame
|
||||
FRAME. */
|
||||
|
||||
value
|
||||
value_from_register (type, regnum, frame)
|
||||
struct type *type;
|
||||
int regnum;
|
||||
FRAME frame;
|
||||
{
|
||||
char raw_buffer [MAX_REGISTER_RAW_SIZE];
|
||||
char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
|
||||
CORE_ADDR addr;
|
||||
value v = allocate_value (type);
|
||||
int len = TYPE_LENGTH (type);
|
||||
char *value_bytes = 0;
|
||||
int value_bytes_copied = 0;
|
||||
int num_storage_locs;
|
||||
|
||||
VALUE_REGNO (v) = regnum;
|
||||
|
||||
num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ?
|
||||
((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 :
|
||||
1);
|
||||
|
||||
if (num_storage_locs > 1)
|
||||
{
|
||||
/* Value spread across multiple storage locations. */
|
||||
|
||||
int local_regnum;
|
||||
int mem_stor = 0, reg_stor = 0;
|
||||
int mem_tracking = 1;
|
||||
CORE_ADDR last_addr = 0;
|
||||
|
||||
value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE);
|
||||
|
||||
/* Copy all of the data out, whereever it may be. */
|
||||
|
||||
for (local_regnum = regnum;
|
||||
value_bytes_copied < len;
|
||||
(value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
|
||||
++local_regnum))
|
||||
{
|
||||
int register_index = local_regnum - regnum;
|
||||
addr = find_saved_register (frame, local_regnum);
|
||||
if (addr == 0)
|
||||
{
|
||||
read_register_bytes (REGISTER_BYTE (local_regnum),
|
||||
value_bytes + value_bytes_copied,
|
||||
REGISTER_RAW_SIZE (local_regnum));
|
||||
reg_stor++;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_memory (addr, value_bytes + value_bytes_copied,
|
||||
REGISTER_RAW_SIZE (local_regnum));
|
||||
mem_stor++;
|
||||
mem_tracking =
|
||||
(mem_tracking
|
||||
&& (regnum == local_regnum
|
||||
|| addr == last_addr));
|
||||
}
|
||||
last_addr = addr;
|
||||
}
|
||||
|
||||
if ((reg_stor && mem_stor)
|
||||
|| (mem_stor && !mem_tracking))
|
||||
/* Mixed storage; all of the hassle we just went through was
|
||||
for some good purpose. */
|
||||
{
|
||||
VALUE_LVAL (v) = lval_reg_frame_relative;
|
||||
VALUE_FRAME (v) = FRAME_FP (frame);
|
||||
VALUE_FRAME_REGNUM (v) = regnum;
|
||||
}
|
||||
else if (mem_stor)
|
||||
{
|
||||
VALUE_LVAL (v) = lval_memory;
|
||||
VALUE_ADDRESS (v) = find_saved_register (frame, regnum);
|
||||
}
|
||||
else if (reg_stor)
|
||||
{
|
||||
VALUE_LVAL (v) = lval_register;
|
||||
VALUE_ADDRESS (v) = REGISTER_BYTE (regnum);
|
||||
}
|
||||
else
|
||||
fatal ("value_from_register: Value not stored anywhere!");
|
||||
|
||||
/* Any structure stored in more than one register will always be
|
||||
an inegral number of registers. Otherwise, you'd need to do
|
||||
some fiddling with the last register copied here for little
|
||||
endian machines. */
|
||||
|
||||
/* Copy into the contents section of the value. */
|
||||
bcopy (value_bytes, VALUE_CONTENTS (v), len);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Data is completely contained within a single register. Locate the
|
||||
register's contents in a real register or in core;
|
||||
read the data in raw format. */
|
||||
|
||||
addr = find_saved_register (frame, regnum);
|
||||
if (addr == 0)
|
||||
{
|
||||
/* Value is really in a register. */
|
||||
|
||||
VALUE_LVAL (v) = lval_register;
|
||||
VALUE_ADDRESS (v) = REGISTER_BYTE (regnum);
|
||||
|
||||
read_register_bytes (REGISTER_BYTE (regnum),
|
||||
raw_buffer, REGISTER_RAW_SIZE (regnum));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Value was in a register that has been saved in memory. */
|
||||
|
||||
read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
|
||||
VALUE_LVAL (v) = lval_memory;
|
||||
VALUE_ADDRESS (v) = addr;
|
||||
}
|
||||
|
||||
/* Convert the raw contents to virtual contents.
|
||||
(Just copy them if the formats are the same.) */
|
||||
|
||||
REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
|
||||
|
||||
if (REGISTER_CONVERTIBLE (regnum))
|
||||
{
|
||||
/* When the raw and virtual formats differ, the virtual format
|
||||
corresponds to a specific data type. If we want that type,
|
||||
copy the data into the value.
|
||||
Otherwise, do a type-conversion. */
|
||||
|
||||
if (type != REGISTER_VIRTUAL_TYPE (regnum))
|
||||
{
|
||||
/* eg a variable of type `float' in a 68881 register
|
||||
with raw type `extended' and virtual type `double'.
|
||||
Fetch it as a `double' and then convert to `float'. */
|
||||
v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
|
||||
bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
|
||||
v = value_cast (type, v);
|
||||
}
|
||||
else
|
||||
bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raw and virtual formats are the same for this register. */
|
||||
|
||||
#ifdef BYTES_BIG_ENDIAN
|
||||
if (len < REGISTER_RAW_SIZE (regnum))
|
||||
{
|
||||
/* Big-endian, and we want less than full size. */
|
||||
VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len;
|
||||
}
|
||||
#endif
|
||||
|
||||
bcopy (virtual_buffer + VALUE_OFFSET (v),
|
||||
VALUE_CONTENTS (v), len);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Given a struct symbol for a variable,
|
||||
and a stack frame address,
|
||||
return a (pointer to a) struct value containing the variable's address. */
|
||||
|
||||
value
|
||||
locate_var_value (var, frame)
|
||||
register struct symbol *var;
|
||||
FRAME frame;
|
||||
{
|
||||
register CORE_ADDR addr = 0;
|
||||
int val = SYMBOL_VALUE (var);
|
||||
struct frame_info *fi;
|
||||
struct type *type = SYMBOL_TYPE (var);
|
||||
|
||||
if (frame == 0) frame = selected_frame;
|
||||
|
||||
switch (SYMBOL_CLASS (var))
|
||||
{
|
||||
case LOC_CONST:
|
||||
case LOC_CONST_BYTES:
|
||||
error ("Address requested for identifier \"%s\" which is a constant.",
|
||||
SYMBOL_NAME (var));
|
||||
|
||||
case LOC_REGISTER:
|
||||
case LOC_REGPARM:
|
||||
addr = find_saved_register (frame, val);
|
||||
if (addr != 0)
|
||||
{
|
||||
int len = TYPE_LENGTH (type);
|
||||
#ifdef BYTES_BIG_ENDIAN
|
||||
if (len < REGISTER_RAW_SIZE (val))
|
||||
/* Big-endian, and we want less than full size. */
|
||||
addr += REGISTER_RAW_SIZE (val) - len;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
error ("Address requested for identifier \"%s\" which is in a register.",
|
||||
SYMBOL_NAME (var));
|
||||
|
||||
case LOC_STATIC:
|
||||
case LOC_LABEL:
|
||||
addr = val;
|
||||
break;
|
||||
|
||||
case LOC_ARG:
|
||||
fi = get_frame_info (frame);
|
||||
addr = val + FRAME_ARGS_ADDRESS (fi);
|
||||
break;
|
||||
|
||||
case LOC_LOCAL:
|
||||
fi = get_frame_info (frame);
|
||||
addr = val + FRAME_LOCALS_ADDRESS (fi);
|
||||
break;
|
||||
|
||||
case LOC_TYPEDEF:
|
||||
error ("Address requested for identifier \"%s\" which is a typedef.",
|
||||
SYMBOL_NAME (var));
|
||||
|
||||
case LOC_BLOCK:
|
||||
addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
|
||||
break;
|
||||
}
|
||||
|
||||
return value_cast (lookup_pointer_type (type),
|
||||
value_from_long (builtin_type_long, (LONGEST) addr));
|
||||
}
|
||||
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d448 2
|
||||
a449 5
|
||||
union { int i; char c; } test;
|
||||
/* If we want less than the full size, we need to
|
||||
test for a big-endian or little-endian machine. */
|
||||
test.i = 1;
|
||||
if (test.c != 1 && len < REGISTER_RAW_SIZE (regnum))
|
||||
d454 2
|
||||
a455 1
|
||||
|
||||
a490 1
|
||||
union { int i; char c; } test;
|
||||
d492 2
|
||||
a493 4
|
||||
/* If var is less than the full size of register, we need to
|
||||
test for a big-endian or little-endian machine. */
|
||||
test.i = 1;
|
||||
if (test.c != 1 && len < REGISTER_RAW_SIZE (val))
|
||||
d496 1
|
||||
@
|
3009
gdb/RCS/gdb.texinfo,v
Normal file
3009
gdb/RCS/gdb.texinfo,v
Normal file
File diff suppressed because it is too large
Load Diff
105
gdb/RCS/gdbcore.h,v
Normal file
105
gdb/RCS/gdbcore.h,v
Normal file
@ -0,0 +1,105 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.02.09.23.23.12; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.02.09.22.43.14; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Create gdbcore.h with external variables that relate to core files.
|
||||
@
|
||||
text
|
||||
@/* Machine independent variables that describe the core file under GDB.
|
||||
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
extern char *corefile;
|
||||
extern char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
extern int corechan;
|
||||
extern int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
|
||||
extern int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
extern CORE_ADDR data_start;
|
||||
extern CORE_ADDR data_end;
|
||||
extern CORE_ADDR stack_start;
|
||||
extern CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
|
||||
extern CORE_ADDR text_start;
|
||||
extern CORE_ADDR text_end;
|
||||
|
||||
extern CORE_ADDR exec_data_start;
|
||||
extern CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
extern int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
extern int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
extern int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
extern int stack_offset;
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d1 68
|
||||
@
|
636
gdb/RCS/inflow.c,v
Normal file
636
gdb/RCS/inflow.c,v
Normal file
@ -0,0 +1,636 @@
|
||||
head 1.3;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.3
|
||||
date 89.03.27.20.12.35; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.2;
|
||||
|
||||
1.2
|
||||
date 89.02.09.23.23.40; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.02.09.22.28.04; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.3
|
||||
log
|
||||
@General portability changes. Make various local terminal control
|
||||
parameter processing #ifdef the particular IOCTL used to get them.
|
||||
This handles various Sys V/Berkeley merges. Also avoid vfork
|
||||
and <sys/fcntl.h>.
|
||||
@
|
||||
text
|
||||
@/* Low level interface to ptrace, for GDB when running under Unix.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
#include <termio.h>
|
||||
#undef TIOCGETP
|
||||
#define TIOCGETP TCGETA
|
||||
#undef TIOCSETN
|
||||
#define TIOCSETN TCSETA
|
||||
#undef TIOCSETP
|
||||
#define TIOCSETP TCSETAF
|
||||
#define TERMINAL struct termio
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <sgtty.h>
|
||||
#define TERMINAL struct sgttyb
|
||||
#endif
|
||||
|
||||
#ifdef SET_STACK_LIMIT_HUGE
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
extern int original_stack_limit;
|
||||
#endif /* SET_STACK_LIMIT_HUGE */
|
||||
|
||||
extern int errno;
|
||||
|
||||
/* Nonzero if we are debugging an attached outside process
|
||||
rather than an inferior. */
|
||||
|
||||
int attach_flag;
|
||||
|
||||
|
||||
/* Record terminal status separately for debugger and inferior. */
|
||||
|
||||
static TERMINAL sg_inferior;
|
||||
static TERMINAL sg_ours;
|
||||
|
||||
static int tflags_inferior;
|
||||
static int tflags_ours;
|
||||
|
||||
#ifdef TIOCGETC
|
||||
static struct tchars tc_inferior;
|
||||
static struct tchars tc_ours;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
static struct ltchars ltc_inferior;
|
||||
static struct ltchars ltc_ours;
|
||||
#endif /* TIOCGLTC */
|
||||
|
||||
#ifdef TIOCLGET
|
||||
static int lmode_inferior;
|
||||
static int lmode_ours;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
static int pgrp_inferior;
|
||||
static int pgrp_ours;
|
||||
#else
|
||||
static int (*sigint_ours) ();
|
||||
static int (*sigquit_ours) ();
|
||||
#endif /* TIOCGPGRP */
|
||||
|
||||
/* Copy of inferior_io_terminal when inferior was last started. */
|
||||
static char *inferior_thisrun_terminal;
|
||||
|
||||
static void terminal_ours_1 ();
|
||||
|
||||
/* Nonzero if our terminal settings are in effect.
|
||||
Zero if the inferior's settings are in effect. */
|
||||
static int terminal_is_ours;
|
||||
|
||||
/* Initialize the terminal settings we record for the inferior,
|
||||
before we actually run the inferior. */
|
||||
|
||||
void
|
||||
terminal_init_inferior ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
|
||||
sg_inferior = sg_ours;
|
||||
tflags_inferior = tflags_ours;
|
||||
|
||||
#ifdef TIOCGETC
|
||||
tc_inferior = tc_ours;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
ltc_inferior = ltc_ours;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCLGET
|
||||
lmode_inferior = lmode_ours;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
pgrp_inferior = inferior_pid;
|
||||
#endif /* TIOCGPGRP */
|
||||
|
||||
terminal_is_ours = 1;
|
||||
}
|
||||
|
||||
/* Put the inferior's terminal settings into effect.
|
||||
This is preparation for starting or resuming the inferior. */
|
||||
|
||||
void
|
||||
terminal_inferior ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
|
||||
if (terminal_is_ours) /* && inferior_thisrun_terminal == 0) */
|
||||
{
|
||||
fcntl (0, F_SETFL, tflags_inferior);
|
||||
fcntl (0, F_SETFL, tflags_inferior);
|
||||
ioctl (0, TIOCSETN, &sg_inferior);
|
||||
#ifdef TIOCGETC
|
||||
ioctl (0, TIOCSETC, &tc_inferior);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCSLTC, <c_inferior);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLSET, &lmode_inferior);
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
ioctl (0, TIOCSPGRP, &pgrp_inferior);
|
||||
#else
|
||||
sigint_ours = (int (*) ()) signal (SIGINT, SIG_IGN);
|
||||
sigquit_ours = (int (*) ()) signal (SIGQUIT, SIG_IGN);
|
||||
#endif /* TIOCGPGRP */
|
||||
}
|
||||
terminal_is_ours = 0;
|
||||
}
|
||||
|
||||
/* Put some of our terminal settings into effect,
|
||||
enough to get proper results from our output,
|
||||
but do not change into or out of RAW mode
|
||||
so that no input is discarded.
|
||||
|
||||
After doing this, either terminal_ours or terminal_inferior
|
||||
should be called to get back to a normal state of affairs. */
|
||||
|
||||
void
|
||||
terminal_ours_for_output ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
|
||||
terminal_ours_1 (1);
|
||||
}
|
||||
|
||||
/* Put our terminal settings into effect.
|
||||
First record the inferior's terminal settings
|
||||
so they can be restored properly later. */
|
||||
|
||||
void
|
||||
terminal_ours ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
|
||||
terminal_ours_1 (0);
|
||||
}
|
||||
|
||||
static void
|
||||
terminal_ours_1 (output_only)
|
||||
int output_only;
|
||||
{
|
||||
#ifdef TIOCGPGRP
|
||||
/* Ignore this signal since it will happen when we try to set the pgrp. */
|
||||
int (*osigttou) ();
|
||||
#endif /* TIOCGPGRP */
|
||||
|
||||
if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */
|
||||
{
|
||||
terminal_is_ours = 1;
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
osigttou = signal (SIGTTOU, SIG_IGN);
|
||||
|
||||
ioctl (0, TIOCGPGRP, &pgrp_inferior);
|
||||
ioctl (0, TIOCSPGRP, &pgrp_ours);
|
||||
|
||||
signal (SIGTTOU, osigttou);
|
||||
#else
|
||||
signal (SIGINT, sigint_ours);
|
||||
signal (SIGQUIT, sigquit_ours);
|
||||
#endif /* TIOCGPGRP */
|
||||
|
||||
tflags_inferior = fcntl (0, F_GETFL, 0);
|
||||
ioctl (0, TIOCGETP, &sg_inferior);
|
||||
|
||||
#ifdef TIOCGETC
|
||||
ioctl (0, TIOCGETC, &tc_inferior);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCGLTC, <c_inferior);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLGET, &lmode_inferior);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
sg_ours.c_lflag |= ICANON;
|
||||
if (output_only && !(sg_inferior.c_lflag & ICANON))
|
||||
sg_ours.c_lflag &= ~ICANON;
|
||||
#else /* not HAVE_TERMIO */
|
||||
sg_ours.sg_flags &= ~RAW & ~CBREAK;
|
||||
if (output_only)
|
||||
sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags;
|
||||
#endif /* not HAVE_TERMIO */
|
||||
|
||||
fcntl (0, F_SETFL, tflags_ours);
|
||||
fcntl (0, F_SETFL, tflags_ours);
|
||||
ioctl (0, TIOCSETN, &sg_ours);
|
||||
|
||||
#ifdef TIOCGETC
|
||||
ioctl (0, TIOCSETC, &tc_ours);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCSLTC, <c_ours);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLSET, &lmode_ours);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
sg_ours.c_lflag |= ICANON;
|
||||
#else /* not HAVE_TERMIO */
|
||||
sg_ours.sg_flags &= ~RAW & ~CBREAK;
|
||||
#endif /* not HAVE_TERMIO */
|
||||
}
|
||||
|
||||
static void
|
||||
term_status_command ()
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (remote_debugging)
|
||||
{
|
||||
printf ("No terminal status when remote debugging.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("Inferior's terminal status (currently saved by GDB):\n");
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
|
||||
printf ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n",
|
||||
tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag);
|
||||
printf ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n",
|
||||
sg_inferior.c_cflag, sg_inferior.c_lflag, sg_inferior.c_line);
|
||||
printf ("c_cc: ");
|
||||
for (i = 0; (i < NCC); i += 1)
|
||||
printf ("0x%x ", sg_inferior.c_cc[i]);
|
||||
printf ("\n");
|
||||
|
||||
#else /* not HAVE_TERMIO */
|
||||
|
||||
printf ("fcntl flags = 0x%x, sgttyb.sg_flags = 0x%x, owner pid = %d.\n",
|
||||
tflags_inferior, sg_inferior.sg_flags, pgrp_inferior);
|
||||
|
||||
#endif /* not HAVE_TERMIO */
|
||||
|
||||
#ifdef TIOCGETC
|
||||
printf ("tchars: ");
|
||||
for (i = 0; i < sizeof (struct tchars); i++)
|
||||
printf ("0x%x ", ((char *)&tc_inferior)[i]);
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
printf ("ltchars: ");
|
||||
for (i = 0; i < sizeof (struct ltchars); i++)
|
||||
printf ("0x%x ", ((char *)<c_inferior)[i]);
|
||||
printf ("\n");
|
||||
ioctl (0, TIOCSLTC, <c_ours);
|
||||
#endif
|
||||
|
||||
#ifdef TIOCLGET
|
||||
printf ("lmode: %x\n", lmode_inferior);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
new_tty (ttyname)
|
||||
char *ttyname;
|
||||
{
|
||||
register int tty;
|
||||
register int fd;
|
||||
|
||||
#ifdef TIOCNOTTY
|
||||
/* Disconnect the child process from our controlling terminal. */
|
||||
tty = open("/dev/tty", O_RDWR);
|
||||
if (tty > 0)
|
||||
{
|
||||
ioctl(tty, TIOCNOTTY, 0);
|
||||
close(tty);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now open the specified new terminal. */
|
||||
|
||||
tty = open(ttyname, O_RDWR);
|
||||
if (tty == -1)
|
||||
_exit(1);
|
||||
|
||||
dup2(tty, 0);
|
||||
dup2(tty, 1);
|
||||
dup2(tty, 2);
|
||||
close(tty);
|
||||
}
|
||||
|
||||
/* Start an inferior process and returns its pid.
|
||||
ALLARGS is a string containing shell command to run the program.
|
||||
ENV is the environment vector to pass. */
|
||||
|
||||
#ifndef SHELL_FILE
|
||||
#define SHELL_FILE "/bin/sh"
|
||||
#endif
|
||||
|
||||
int
|
||||
create_inferior (allargs, env)
|
||||
char *allargs;
|
||||
char **env;
|
||||
{
|
||||
int pid;
|
||||
char *shell_command;
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
extern int errno;
|
||||
|
||||
/* If desired, concat something onto the front of ALLARGS.
|
||||
SHELL_COMMAND is the result. */
|
||||
#ifdef SHELL_COMMAND_CONCAT
|
||||
shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + strlen (allargs) + 1);
|
||||
strcpy (shell_command, SHELL_COMMAND_CONCAT);
|
||||
strcat (shell_command, allargs);
|
||||
#else
|
||||
shell_command = allargs;
|
||||
#endif
|
||||
|
||||
/* exec is said to fail if the executable is open. */
|
||||
close_exec_file ();
|
||||
|
||||
pid = fork ();
|
||||
if (pid < 0)
|
||||
perror_with_name ("fork");
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
#ifdef TIOCGPGRP
|
||||
/* Run inferior in a separate process group. */
|
||||
setpgrp (getpid (), getpid ());
|
||||
#endif /* TIOCGPGRP */
|
||||
|
||||
#ifdef SET_STACK_LIMIT_HUGE
|
||||
/* Reset the stack limit back to what it was. */
|
||||
{
|
||||
struct rlimit rlim;
|
||||
|
||||
getrlimit (RLIMIT_STACK, &rlim);
|
||||
rlim.rlim_cur = original_stack_limit;
|
||||
setrlimit (RLIMIT_STACK, &rlim);
|
||||
}
|
||||
#endif /* SET_STACK_LIMIT_HUGE */
|
||||
|
||||
|
||||
inferior_thisrun_terminal = inferior_io_terminal;
|
||||
if (inferior_io_terminal != 0)
|
||||
new_tty (inferior_io_terminal);
|
||||
|
||||
/* Not needed on Sun, at least, and loses there
|
||||
because it clobbers the superior. */
|
||||
/*??? signal (SIGQUIT, SIG_DFL);
|
||||
signal (SIGINT, SIG_DFL); */
|
||||
|
||||
call_ptrace (0);
|
||||
execle (SHELL_FILE, "sh", "-c", shell_command, 0, env);
|
||||
|
||||
fprintf (stderr, "Cannot exec %s: %s.\n", SHELL_FILE,
|
||||
errno < sys_nerr ? sys_errlist[errno] : "unknown error");
|
||||
fflush (stderr);
|
||||
_exit (0177);
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* Kill the inferior process. Make us have no inferior. */
|
||||
|
||||
static void
|
||||
kill_command ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
error ("The program is not being run.");
|
||||
if (!query ("Kill the inferior process? "))
|
||||
error ("Not confirmed.");
|
||||
kill_inferior ();
|
||||
}
|
||||
|
||||
void
|
||||
inferior_died ()
|
||||
{
|
||||
inferior_pid = 0;
|
||||
attach_flag = 0;
|
||||
mark_breakpoints_out ();
|
||||
select_frame ( (FRAME) 0, -1);
|
||||
reopen_exec_file ();
|
||||
if (have_core_file_p ())
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
|
||||
read_pc ()));
|
||||
}
|
||||
|
||||
static void
|
||||
try_writing_regs_command ()
|
||||
{
|
||||
register int i;
|
||||
register int value;
|
||||
extern int errno;
|
||||
|
||||
if (inferior_pid == 0)
|
||||
error ("There is no inferior process now.");
|
||||
|
||||
for (i = 0; ; i += 2)
|
||||
{
|
||||
QUIT;
|
||||
errno = 0;
|
||||
value = call_ptrace (3, inferior_pid, i, 0);
|
||||
call_ptrace (6, inferior_pid, i, value);
|
||||
if (errno == 0)
|
||||
{
|
||||
printf (" Succeeded with address 0x%x; value 0x%x (%d).\n",
|
||||
i, value, value);
|
||||
}
|
||||
else if ((i & 0377) == 0)
|
||||
printf (" Failed at 0x%x.\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_inflow ()
|
||||
{
|
||||
add_com ("term-status", class_obscure, term_status_command,
|
||||
"Print info on inferior's saved terminal status.");
|
||||
|
||||
add_com ("try-writing-regs", class_obscure, try_writing_regs_command,
|
||||
"Try writing all locations in inferior's system block.\n\
|
||||
Report which ones can be written.");
|
||||
|
||||
add_com ("kill", class_run, kill_command,
|
||||
"Kill execution of program being debugged.");
|
||||
|
||||
inferior_pid = 0;
|
||||
|
||||
ioctl (0, TIOCGETP, &sg_ours);
|
||||
fcntl (0, F_GETFL, tflags_ours);
|
||||
|
||||
#ifdef TIOCGETC
|
||||
ioctl (0, TIOCGETC, &tc_ours);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCGLTC, <c_ours);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLGET, &lmode_ours);
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
ioctl (0, TIOCGPGRP, &pgrp_ours);
|
||||
#endif /* TIOCGPGRP */
|
||||
|
||||
terminal_is_ours = 1;
|
||||
}
|
||||
|
||||
@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@When the inferior process dies, deselect the current frame so that
|
||||
the "where" ("backtrace") command will not think there's a stack.
|
||||
@
|
||||
text
|
||||
@d27 1
|
||||
a27 1
|
||||
#include <sys/fcntl.h>
|
||||
a34 6
|
||||
/* May be unnecessary since many parts of inflow.c
|
||||
have migrated to *-infdep.c */
|
||||
#ifdef USG
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
|
||||
d73 1
|
||||
a73 1
|
||||
#ifdef TIOCGLTC
|
||||
d76 3
|
||||
d81 3
|
||||
d86 1
|
||||
a86 1
|
||||
#endif /* TIOCGLTC */
|
||||
d117 4
|
||||
a121 1
|
||||
tc_inferior = tc_ours;
|
||||
d123 3
|
||||
d127 1
|
||||
a127 1
|
||||
#endif /* TIOCGLTC */
|
||||
d150 3
|
||||
a153 1
|
||||
ioctl (0, TIOCSETC, &tc_inferior);
|
||||
d155 2
|
||||
d158 1
|
||||
a158 1
|
||||
#endif /* TIOCGLTC */
|
||||
d228 3
|
||||
a231 1
|
||||
ioctl (0, TIOCGETC, &tc_inferior);
|
||||
d233 2
|
||||
d236 1
|
||||
a236 1
|
||||
#endif /* TIOCGLTC */
|
||||
d253 3
|
||||
a256 1
|
||||
ioctl (0, TIOCSETC, &tc_ours);
|
||||
d258 2
|
||||
d261 1
|
||||
a261 1
|
||||
#endif /* TIOCGLTC */
|
||||
d297 6
|
||||
a302 3
|
||||
printf ("fcntl flags = 0x%x, lmode = 0x%x,\nsgttyb.sg_flags = 0x%x, owner pid = %d.\n",
|
||||
tflags_inferior, lmode_inferior,
|
||||
sg_inferior.sg_flags, pgrp_inferior);
|
||||
d307 3
|
||||
d314 2
|
||||
d317 3
|
||||
a319 1
|
||||
#endif /* not HAVE_TERMIO */
|
||||
d383 1
|
||||
a383 1
|
||||
pid = vfork ();
|
||||
d385 1
|
||||
a385 1
|
||||
perror_with_name ("vfork");
|
||||
d497 3
|
||||
a500 1
|
||||
ioctl (0, TIOCGETC, &tc_ours);
|
||||
d502 2
|
||||
d505 1
|
||||
a505 1
|
||||
#endif /* TIOCGLTC */
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d418 1
|
||||
@
|
1855
gdb/RCS/infrun.c,v
Normal file
1855
gdb/RCS/infrun.c,v
Normal file
File diff suppressed because it is too large
Load Diff
591
gdb/RCS/m-aux.h,v
Normal file
591
gdb/RCS/m-aux.h,v
Normal file
@ -0,0 +1,591 @@
|
||||
head 1.4;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.4
|
||||
date 89.04.26.00.51.42; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.3;
|
||||
|
||||
1.3
|
||||
date 89.03.27.20.16.05; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.2;
|
||||
|
||||
1.2
|
||||
date 89.03.26.20.13.28; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.13.19.16.52; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.4
|
||||
log
|
||||
@(1) Defined the big-endianness of the target machine.
|
||||
(2) Define float to be IEEE compatible.
|
||||
(3) Define invalid floats to be NaNs.
|
||||
@
|
||||
text
|
||||
@/* Parameters for execution on A/UX, for GDB, the GNU debugger.
|
||||
Copyright (C) 1989 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#ifndef aux
|
||||
#define aux
|
||||
#endif
|
||||
|
||||
/* It's a USG system */
|
||||
#define USG
|
||||
|
||||
/* Assembler instructions in USG "SGS" (sw generation system) format */
|
||||
#define USG_SGS_ASM
|
||||
|
||||
/* Debugger information will be in COFF format. */
|
||||
#define COFF_FORMAT
|
||||
#define COFF_NO_LONG_FILE_NAMES
|
||||
|
||||
/* Terminal interface via termio */
|
||||
#define HAVE_TERMIO
|
||||
|
||||
/* Unisoft fucked up the include files */
|
||||
#define UNISOFT_ASSHOLES
|
||||
|
||||
/* Big or Little-Endian target machine
|
||||
BITS: defined if bit #0 is the high-order bit of a byte.
|
||||
BYTES:defined if byte#0 is the high-order byte of an int.
|
||||
WORDS:defined if word#0 is the high-order word of a double. */
|
||||
#define BITS_BIG_ENDIAN
|
||||
#define BYTES_BIG_ENDIAN
|
||||
#define WORDS_BIG_ENDIAN
|
||||
|
||||
/* Floating point is IEEE compatible */
|
||||
#define IEEE_FLOAT
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
Zero on most machines. */
|
||||
|
||||
#define FUNCTION_START_OFFSET 0
|
||||
|
||||
/* Advance PC across any function entry prologue instructions
|
||||
to reach some "real" code. */
|
||||
|
||||
#define SKIP_PROLOGUE(pc) \
|
||||
{ register int op = read_memory_integer (pc, 2); \
|
||||
if (op == 0047126) \
|
||||
pc += 4; /* Skip link #word */ \
|
||||
else if (op == 0044016) \
|
||||
pc += 6; /* Skip link #long */ \
|
||||
}
|
||||
|
||||
/* Immediately after a function call, return the saved pc.
|
||||
Can't go through the frames for this because on some machines
|
||||
the new frame is not set up until the new function executes
|
||||
some instructions. */
|
||||
|
||||
#define SAVED_PC_AFTER_CALL(frame) \
|
||||
read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
/* Address of end of stack space. */
|
||||
|
||||
#define STACK_END_ADDR 0x20000000
|
||||
|
||||
/* Stack grows downward. */
|
||||
|
||||
#define INNER_THAN <
|
||||
|
||||
/* Sequence of bytes for breakpoint instruction. */
|
||||
/* A/UX uses "trap &1" */
|
||||
|
||||
#define BREAKPOINT {0x4e, 0x41}
|
||||
|
||||
/* Amount PC must be decremented by after a breakpoint.
|
||||
This is often the number of bytes in BREAKPOINT
|
||||
but not always. */
|
||||
|
||||
#define DECR_PC_AFTER_BREAK 0
|
||||
|
||||
/* Nonzero if instruction at PC is a return instruction. */
|
||||
|
||||
#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75)
|
||||
|
||||
/* Return 1 if P points to an invalid floating point value. */
|
||||
/* FIXME, it's not clear what "invalid" means here. I take it to mean
|
||||
"something that coredumps gdb if gdb tries to manipulate it" */
|
||||
|
||||
#define INVALID_FLOAT(p, len) is_nan(p, len)
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
|
||||
/* Number of machine registers */
|
||||
|
||||
#define NUM_REGS 29
|
||||
|
||||
/* Initializer for an array of names of registers.
|
||||
There should be NUM_REGS strings in this initializer. */
|
||||
|
||||
#define REGISTER_NAMES \
|
||||
{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \
|
||||
"a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \
|
||||
"ps", "pc", \
|
||||
"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \
|
||||
"fpcontrol", "fpstatus", "fpiaddr" }
|
||||
|
||||
/* Register numbers of various important registers.
|
||||
Note that some of these values are "real" register numbers,
|
||||
and correspond to the general registers of the machine,
|
||||
and some are "phony" register numbers which are too large
|
||||
to be actual register numbers as far as the user is concerned
|
||||
but do serve to get the desired values when passed to read_register. */
|
||||
|
||||
#define FP_REGNUM 14 /* Contains address of executing stack frame */
|
||||
#define SP_REGNUM 15 /* Contains address of top of stack */
|
||||
#define PS_REGNUM 16 /* Contains processor status */
|
||||
#define PC_REGNUM 17 /* Contains program counter */
|
||||
#define FP0_REGNUM 18 /* Floating point register 0 */
|
||||
#define FPC_REGNUM 26 /* 68881 control register */
|
||||
|
||||
/* This is a piece of magic that is given a register number REGNO
|
||||
and as BLOCKEND the address in the system of the end of the user structure
|
||||
and stores in ADDR the address in the kernel or core dump
|
||||
of that register. */
|
||||
|
||||
#define REGISTER_U_ADDR(addr, blockend, regno) { \
|
||||
struct user u; \
|
||||
if (regno <= SP_REGNUM) \
|
||||
addr = blockend + regno * 4; \
|
||||
else if (regno == PS_REGNUM) \
|
||||
addr = blockend + RPS * 4; /* From reg.h */ \
|
||||
else if (regno == PC_REGNUM) \
|
||||
addr = blockend + PC * 4; /* From reg.h */ \
|
||||
else if (regno < FPC_REGNUM) \
|
||||
addr = (char *) u.u_fpdreg [regno-FP0_REGNUM] - (char *)&u; \
|
||||
else \
|
||||
addr = (char *)&u.u_fpsysreg[regno-FPC_REGNUM] - (char *)&u; \
|
||||
}
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
/* Total amount of space needed to store our copies of the machine's
|
||||
register state, the array `registers'. */
|
||||
#define REGISTER_BYTES (16*4+8*12+8+20)
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
|
||||
#define REGISTER_BYTE(N) \
|
||||
((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \
|
||||
: (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \
|
||||
: (N) * 4)
|
||||
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. On the 68000, all regs are 4 bytes
|
||||
except the floating point regs which are 12 bytes. */
|
||||
/* Note that the unsigned cast here forces the result of the
|
||||
subtractiion to very high positive values if N < FP0_REGNUM */
|
||||
|
||||
#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4)
|
||||
|
||||
/* Number of bytes of storage in the program's representation
|
||||
for register N. On the 68000, all regs are 4 bytes
|
||||
except the floating point regs which are 8-byte doubles. */
|
||||
|
||||
#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4)
|
||||
|
||||
/* Largest value REGISTER_RAW_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_RAW_SIZE 12
|
||||
|
||||
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_VIRTUAL_SIZE 8
|
||||
|
||||
/* Nonzero if register N requires conversion
|
||||
from raw format to virtual format. */
|
||||
|
||||
#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8)
|
||||
|
||||
/* Convert data from raw format for register REGNUM
|
||||
to virtual format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
|
||||
{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
|
||||
convert_from_68881 ((FROM), (TO)); \
|
||||
else \
|
||||
bcopy ((FROM), (TO), 4); }
|
||||
|
||||
/* Convert data from virtual format for register REGNUM
|
||||
to raw format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
|
||||
{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
|
||||
convert_to_68881 ((FROM), (TO)); \
|
||||
else \
|
||||
bcopy ((FROM), (TO), 4); }
|
||||
|
||||
/* Return the GDB type object for the "standard" data type
|
||||
of data in register N. */
|
||||
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
(((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (9, (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Write into appropriate registers a function return value
|
||||
of type TYPE, given in virtual format. */
|
||||
|
||||
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
|
||||
write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
the address in which a function should return its structure value,
|
||||
as a CORE_ADDR (or an expression that can be used as one). */
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
|
||||
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
|
||||
/* FRAME_CHAIN takes a frame's nominal address
|
||||
and produces the frame's chain-pointer.
|
||||
|
||||
FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
|
||||
and produces the nominal address of the caller frame.
|
||||
|
||||
However, if FRAME_CHAIN_VALID returns zero,
|
||||
it means the given frame is the outermost one and has no caller.
|
||||
In that case, FRAME_CHAIN_COMBINE is not used. */
|
||||
|
||||
/* In the case of the 68k, the frame's nominal address
|
||||
is the address of a 4-byte word containing the calling frame's address. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
|
||||
/* We can't tell how many args there are
|
||||
now that the C compiler delays popping them. */
|
||||
#define FRAME_NUM_ARGS(val,fi) (val = -1)
|
||||
|
||||
#if 0
|
||||
#define FRAME_NUM_ARGS(val, fi) \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
|
||||
register int insn = 0177777 & read_memory_integer (pc, 2); \
|
||||
val = 0; \
|
||||
if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
|
||||
val = read_memory_integer (pc + 2, 2); \
|
||||
else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \
|
||||
|| (insn & 0170777) == 0050117) /* addqw */ \
|
||||
{ val = (insn >> 9) & 7; if (val == 0) val = 8; } \
|
||||
else if (insn == 0157774) /* addal #WW, sp */ \
|
||||
val = read_memory_integer (pc + 2, 4); \
|
||||
val >>= 2; }
|
||||
#endif
|
||||
|
||||
/* Return number of bytes at start of arglist that are not really args. */
|
||||
|
||||
#define FRAME_ARGS_SKIP 8
|
||||
|
||||
/* Put here the code to store, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame. */
|
||||
|
||||
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
|
||||
{ register int regnum; \
|
||||
register int regmask; \
|
||||
register CORE_ADDR next_addr; \
|
||||
register CORE_ADDR pc; \
|
||||
int nextinsn; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info)->pc <= (frame_info)->frame) \
|
||||
{ next_addr = (frame_info)->frame; \
|
||||
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
else \
|
||||
{ pc = get_pc_function_start ((frame_info)->pc); \
|
||||
/* Verify we have a link a6 instruction next; \
|
||||
if not we lose. If we win, find the address above the saved \
|
||||
regs using the amount of storage from the link instruction. */\
|
||||
if (044016 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
else if (047126 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
else goto lose; \
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */ \
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
|
||||
next_addr += read_memory_integer (pc += 2, 4), pc += 4; \
|
||||
} \
|
||||
/* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \
|
||||
regmask = read_memory_integer (pc + 2, 2); \
|
||||
/* But before that can come an fmovem. Check for it. */ \
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2); \
|
||||
if (0xf227 == nextinsn \
|
||||
&& (regmask & 0xff00) == 0xe000) \
|
||||
{ pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 12); \
|
||||
regmask = read_memory_integer (pc + 2, 2); } \
|
||||
if (0044327 == read_memory_integer (pc, 2)) \
|
||||
{ pc += 4; /* Regmask's low bit is for register 0, the first written */ \
|
||||
for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \
|
||||
else if (0044347 == read_memory_integer (pc, 2)) \
|
||||
{ pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \
|
||||
for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) \
|
||||
{ regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
/* fmovemx to index of sp may follow. */ \
|
||||
regmask = read_memory_integer (pc + 2, 2); \
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2); \
|
||||
if (0xf236 == nextinsn \
|
||||
&& (regmask & 0xff00) == 0xf000) \
|
||||
{ pc += 10; /* Regmask's low bit is for register fp0, the first written */ \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \
|
||||
regmask = read_memory_integer (pc + 2, 2); } \
|
||||
/* clrw -(sp); movw ccr,-(sp) may follow. */ \
|
||||
if (0x426742e7 == read_memory_integer (pc, 4)) \
|
||||
(frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
|
||||
lose: ; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
#define PUSH_DUMMY_FRAME \
|
||||
{ register CORE_ADDR sp = read_register (SP_REGNUM); \
|
||||
register int regnum; \
|
||||
char raw_buffer[12]; \
|
||||
sp = push_word (sp, read_register (PC_REGNUM)); \
|
||||
sp = push_word (sp, read_register (FP_REGNUM)); \
|
||||
write_register (FP_REGNUM, sp); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
{ read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \
|
||||
sp = push_bytes (sp, raw_buffer, 12); } \
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
sp = push_word (sp, read_register (regnum)); \
|
||||
sp = push_word (sp, read_register (PS_REGNUM)); \
|
||||
write_register (SP_REGNUM, sp); }
|
||||
|
||||
/* Discard from the stack the innermost frame,
|
||||
restoring all saved registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[12]; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
{ read_memory (fsr.regs[regnum], raw_buffer, 12); \
|
||||
write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
if (fsr.regs[PS_REGNUM]) \
|
||||
write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
fmovem 0xff,-(sp)
|
||||
moveml 0xfffc,-(sp)
|
||||
clrw -(sp)
|
||||
movew ccr,-(sp)
|
||||
/..* The arguments are pushed at this point by GDB;
|
||||
no code is needed in the dummy for this.
|
||||
The CALL_DUMMY_START_OFFSET gives the position of
|
||||
the following jsr instruction. *../
|
||||
jsr @@#32323232
|
||||
addl #69696969,sp
|
||||
trap #15
|
||||
nop
|
||||
Note this is 28 bytes.
|
||||
We actually start executing at the jsr, since the pushing of the
|
||||
registers is done by PUSH_DUMMY_FRAME. If this were real code,
|
||||
the arguments for the function called by the jsr would be pushed
|
||||
between the moveml and the jsr, and we could allow it to execute through.
|
||||
But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done,
|
||||
and we cannot allow the moveml to push the registers again lest they be
|
||||
taken for the arguments. */
|
||||
|
||||
#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71}
|
||||
|
||||
#define CALL_DUMMY_LENGTH 28
|
||||
|
||||
#define CALL_DUMMY_START_OFFSET 12
|
||||
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
||||
/* Interface definitions for kernel debugger KDB. */
|
||||
|
||||
/* Map machine fault codes into signal numbers.
|
||||
First subtract 0, divide by 4, then index in a table.
|
||||
Faults for which the entry in this table is 0
|
||||
are not handled by KDB; the program's own trap handler
|
||||
gets to handle then. */
|
||||
|
||||
#define FAULT_CODE_ORIGIN 0
|
||||
#define FAULT_CODE_UNITS 4
|
||||
#define FAULT_TABLE \
|
||||
{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \
|
||||
0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
SIGILL }
|
||||
|
||||
/* Start running with a stack stretching from BEG to END.
|
||||
BEG and END should be symbols meaningful to the assembler.
|
||||
This is used only for kdb. */
|
||||
|
||||
#define INIT_STACK(beg, end) \
|
||||
{ asm (".globl end"); \
|
||||
asm ("movel #end, sp"); \
|
||||
asm ("movel #0,a6"); }
|
||||
|
||||
/* Push the frame pointer register on the stack. */
|
||||
#define PUSH_FRAME_PTR \
|
||||
asm ("movel a6,sp@@-");
|
||||
|
||||
/* Copy the top-of-stack to the frame pointer register. */
|
||||
#define POP_FRAME_PTR \
|
||||
asm ("movl sp@@,a6");
|
||||
|
||||
/* After KDB is entered by a fault, push all registers
|
||||
that GDB thinks about (all NUM_REGS of them),
|
||||
so that they appear in order of ascending GDB register number.
|
||||
The fault code will be on the stack beyond the last register. */
|
||||
|
||||
#define PUSH_REGISTERS \
|
||||
{ asm ("clrw -(sp)"); \
|
||||
asm ("pea sp@@(10)"); \
|
||||
asm ("movem #0xfffe,sp@@-"); }
|
||||
|
||||
/* Assuming the registers (including processor status) have been
|
||||
pushed on the stack in order of ascending GDB register number,
|
||||
restore them and return to the address in the saved PC register. */
|
||||
|
||||
#define POP_REGISTERS \
|
||||
{ asm ("subil #8,sp@@(28)"); \
|
||||
asm ("movem sp@@,#0xffff"); \
|
||||
asm ("rte"); }
|
||||
@
|
||||
|
||||
|
||||
1.3
|
||||
log
|
||||
@Fix DECR_PC_AFTER_BREAK; A/UX reports breaks at the breakpoint addr,
|
||||
not there+2.
|
||||
@
|
||||
text
|
||||
@d41 11
|
||||
d100 2
|
||||
d103 1
|
||||
a103 1
|
||||
#define INVALID_FLOAT(p, len) 1 /* FIXME! Just a first guess; not checked */
|
||||
@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Mostly works!
|
||||
@
|
||||
text
|
||||
@d82 1
|
||||
a82 1
|
||||
#define DECR_PC_AFTER_BREAK 2
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d1 504
|
||||
@
|
607
gdb/RCS/m-hp9k320.h,v
Normal file
607
gdb/RCS/m-hp9k320.h,v
Normal file
@ -0,0 +1,607 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.03.27.20.17.11; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.20.19.29.58; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Change "HPUX_ASM" define to "USG_SGS_ASM", since it's really the USG
|
||||
Software Generation System assembler that we're fighting here.
|
||||
.,
|
||||
@
|
||||
text
|
||||
@/* Parameters for execution on an HP 9000 model 320, for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#ifndef HP9K320
|
||||
#define HP9K320
|
||||
#endif
|
||||
|
||||
/* Set flag to indicate whether HP's assembler is in use. */
|
||||
#ifdef __GNU__
|
||||
#ifdef __HPUX_ASM__
|
||||
#define USG_SGS_ASM
|
||||
#endif
|
||||
#else
|
||||
#define USG_SGS_ASM
|
||||
#endif
|
||||
|
||||
/* Define this for versions of hp-ux older than 6.0 */
|
||||
/* #define HPUX_VERSION_5 */
|
||||
|
||||
/* define USG if you are using sys5 /usr/include's */
|
||||
#define USG
|
||||
|
||||
#define HAVE_TERMIO
|
||||
|
||||
/* Get rid of any system-imposed stack limit if possible. */
|
||||
|
||||
/* #define SET_STACK_LIMIT_HUGE */
|
||||
|
||||
/* Define this if the C compiler puts an underscore at the front
|
||||
of external names before giving them to the linker. */
|
||||
|
||||
#define NAMES_HAVE_UNDERSCORE
|
||||
|
||||
/* Debugger information will be in DBX format. */
|
||||
|
||||
#define READ_DBX_FORMAT
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
Zero on most machines. */
|
||||
|
||||
#define FUNCTION_START_OFFSET 0
|
||||
|
||||
/* Advance PC across any function entry prologue instructions
|
||||
to reach some "real" code. */
|
||||
|
||||
#define SKIP_PROLOGUE(pc) \
|
||||
{ register int op = read_memory_integer (pc, 2); \
|
||||
if (op == 0047126) \
|
||||
pc += 4; /* Skip link #word */ \
|
||||
else if (op == 0044016) \
|
||||
pc += 6; /* Skip link #long */ \
|
||||
}
|
||||
|
||||
/* Immediately after a function call, return the saved pc.
|
||||
Can't go through the frames for this because on some machines
|
||||
the new frame is not set up until the new function executes
|
||||
some instructions. */
|
||||
|
||||
#define SAVED_PC_AFTER_CALL(frame) \
|
||||
read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
/* This is the amount to subtract from u.u_ar0
|
||||
to get the offset in the core file of the register values. */
|
||||
|
||||
#ifdef HPUX_VERSION_5
|
||||
#define KERNEL_U_ADDR 0x00979000
|
||||
#else
|
||||
#define KERNEL_U_ADDR 0x00C01000
|
||||
#endif
|
||||
|
||||
/* Address of end of stack space. */
|
||||
|
||||
#define STACK_END_ADDR 0xFFF00000
|
||||
|
||||
/* Stack grows downward. */
|
||||
|
||||
#define INNER_THAN <
|
||||
|
||||
/* Sequence of bytes for breakpoint instruction. */
|
||||
|
||||
#define BREAKPOINT {0x4e, 0x41}
|
||||
|
||||
/* Amount PC must be decremented by after a breakpoint.
|
||||
This is often the number of bytes in BREAKPOINT
|
||||
but not always. */
|
||||
|
||||
#define DECR_PC_AFTER_BREAK 2
|
||||
|
||||
/* Nonzero if instruction at PC is a return instruction. */
|
||||
|
||||
#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75)
|
||||
|
||||
/* Return 1 if P points to an invalid floating point value. */
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
|
||||
/* Number of machine registers */
|
||||
|
||||
#define NUM_REGS 29
|
||||
|
||||
/* Initializer for an array of names of registers.
|
||||
There should be NUM_REGS strings in this initializer. */
|
||||
|
||||
#define REGISTER_NAMES \
|
||||
{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \
|
||||
"a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \
|
||||
"ps", "pc", \
|
||||
"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \
|
||||
"fpcontrol", "fpstatus", "fpiaddr" }
|
||||
|
||||
/* Register numbers of various important registers.
|
||||
Note that some of these values are "real" register numbers,
|
||||
and correspond to the general registers of the machine,
|
||||
and some are "phony" register numbers which are too large
|
||||
to be actual register numbers as far as the user is concerned
|
||||
but do serve to get the desired values when passed to read_register. */
|
||||
|
||||
#define FP_REGNUM 14 /* Contains address of executing stack frame */
|
||||
#define SP_REGNUM 15 /* Contains address of top of stack */
|
||||
#define PS_REGNUM 16 /* Contains processor status */
|
||||
#define PC_REGNUM 17 /* Contains program counter */
|
||||
#define FP0_REGNUM 18 /* Floating point register 0 */
|
||||
#define FPC_REGNUM 26 /* 68881 control register */
|
||||
|
||||
/* Total amount of space needed to store our copies of the machine's
|
||||
register state, the array `registers'. */
|
||||
#define REGISTER_BYTES (16*4+8*12+8+12)
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
|
||||
#define REGISTER_BYTE(N) \
|
||||
((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \
|
||||
: (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \
|
||||
: (N) * 4)
|
||||
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. On the 68000, all regs are 4 bytes
|
||||
except the floating point regs which are 12 bytes. */
|
||||
|
||||
#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4)
|
||||
|
||||
/* Number of bytes of storage in the program's representation
|
||||
for register N. On the 68000, all regs are 4 bytes
|
||||
except the floating point regs which are 8-byte doubles. */
|
||||
|
||||
#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4)
|
||||
|
||||
/* Largest value REGISTER_RAW_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_RAW_SIZE 12
|
||||
|
||||
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_VIRTUAL_SIZE 8
|
||||
|
||||
/* Nonzero if register N requires conversion
|
||||
from raw format to virtual format. */
|
||||
|
||||
#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8)
|
||||
|
||||
/* Convert data from raw format for register REGNUM
|
||||
to virtual format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
|
||||
{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
|
||||
convert_from_68881 ((FROM), (TO)); \
|
||||
else \
|
||||
bcopy ((FROM), (TO), 4); }
|
||||
|
||||
/* Convert data from virtual format for register REGNUM
|
||||
to raw format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
|
||||
{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
|
||||
convert_to_68881 ((FROM), (TO)); \
|
||||
else \
|
||||
bcopy ((FROM), (TO), 4); }
|
||||
|
||||
/* Return the GDB type object for the "standard" data type
|
||||
of data in register N. */
|
||||
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
(((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (9, (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Write into appropriate registers a function return value
|
||||
of type TYPE, given in virtual format. */
|
||||
|
||||
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
|
||||
write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
the address in which a function should return its structure value,
|
||||
as a CORE_ADDR (or an expression that can be used as one). */
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
|
||||
|
||||
#define REGISTER_ADDR(u_ar0, regno) \
|
||||
(((regno) < PS_REGNUM) \
|
||||
? (&((struct exception_stack *) (u_ar0))->e_regs[(regno + R0)]) \
|
||||
: (((regno) == PS_REGNUM) \
|
||||
? ((int *) (&((struct exception_stack *) (u_ar0))->e_PS)) \
|
||||
: (&((struct exception_stack *) (u_ar0))->e_PC)))
|
||||
|
||||
#define FP_REGISTER_ADDR(u, regno) \
|
||||
(((char *) \
|
||||
(((regno) < FPC_REGNUM) \
|
||||
? (&u.u_pcb.pcb_mc68881[FMC68881_R0 + (((regno) - FP0_REGNUM) * 3)]) \
|
||||
: (&u.u_pcb.pcb_mc68881[FMC68881_C + ((regno) - FPC_REGNUM)]))) \
|
||||
- ((char *) (& u)))
|
||||
|
||||
/* It is safe to look for symsegs on a Sun, because Sun's ld
|
||||
does not screw up with random garbage at end of file. */
|
||||
|
||||
#define READ_GDB_SYMSEGS
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
|
||||
/* FRAME_CHAIN takes a frame's nominal address
|
||||
and produces the frame's chain-pointer.
|
||||
|
||||
FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
|
||||
and produces the nominal address of the caller frame.
|
||||
|
||||
However, if FRAME_CHAIN_VALID returns zero,
|
||||
it means the given frame is the outermost one and has no caller.
|
||||
In that case, FRAME_CHAIN_COMBINE is not used. */
|
||||
|
||||
/* In the case of the Sun, the frame's nominal address
|
||||
is the address of a 4-byte word containing the calling frame's address. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
|
||||
/* We can't tell how many args there are
|
||||
now that the C compiler delays popping them. */
|
||||
#define FRAME_NUM_ARGS(val,fi) (val = -1)
|
||||
|
||||
#if 0
|
||||
#define FRAME_NUM_ARGS(val, fi) \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
|
||||
register int insn = 0177777 & read_memory_integer (pc, 2); \
|
||||
val = 0; \
|
||||
if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
|
||||
val = read_memory_integer (pc + 2, 2); \
|
||||
else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \
|
||||
|| (insn & 0170777) == 0050117) /* addqw */ \
|
||||
{ val = (insn >> 9) & 7; if (val == 0) val = 8; } \
|
||||
else if (insn == 0157774) /* addal #WW, sp */ \
|
||||
val = read_memory_integer (pc + 2, 4); \
|
||||
val >>= 2; }
|
||||
#endif
|
||||
|
||||
/* Return number of bytes at start of arglist that are not really args. */
|
||||
|
||||
#define FRAME_ARGS_SKIP 8
|
||||
|
||||
/* Put here the code to store, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame. */
|
||||
|
||||
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
|
||||
{ register int regnum; \
|
||||
register int regmask; \
|
||||
register CORE_ADDR next_addr; \
|
||||
register CORE_ADDR pc; \
|
||||
int nextinsn; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info)->pc <= (frame_info)->frame) \
|
||||
{ next_addr = (frame_info)->frame; \
|
||||
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
else \
|
||||
{ pc = get_pc_function_start ((frame_info)->pc); \
|
||||
/* Verify we have a link a6 instruction next; \
|
||||
if not we lose. If we win, find the address above the saved \
|
||||
regs using the amount of storage from the link instruction. */\
|
||||
if (044016 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
else if (047126 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
else goto lose; \
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */ \
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
|
||||
next_addr += read_memory_integer (pc += 2, 4), pc += 4; \
|
||||
} \
|
||||
/* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \
|
||||
regmask = read_memory_integer (pc + 2, 2); \
|
||||
/* But before that can come an fmovem. Check for it. */ \
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2); \
|
||||
if (0xf227 == nextinsn \
|
||||
&& (regmask & 0xff00) == 0xe000) \
|
||||
{ pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 12); \
|
||||
regmask = read_memory_integer (pc + 2, 2); } \
|
||||
if (0044327 == read_memory_integer (pc, 2)) \
|
||||
{ pc += 4; /* Regmask's low bit is for register 0, the first written */ \
|
||||
for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \
|
||||
else if (0044347 == read_memory_integer (pc, 2)) \
|
||||
{ pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \
|
||||
for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \
|
||||
{ regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
/* fmovemx to index of sp may follow. */ \
|
||||
regmask = read_memory_integer (pc + 2, 2); \
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2); \
|
||||
if (0xf236 == nextinsn \
|
||||
&& (regmask & 0xff00) == 0xf000) \
|
||||
{ pc += 10; /* Regmask's low bit is for register fp0, the first written */ \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \
|
||||
regmask = read_memory_integer (pc + 2, 2); } \
|
||||
/* clrw -(sp); movw ccr,-(sp) may follow. */ \
|
||||
if (0x426742e7 == read_memory_integer (pc, 4)) \
|
||||
(frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
|
||||
lose: ; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
#define PUSH_DUMMY_FRAME \
|
||||
{ register CORE_ADDR sp = read_register (SP_REGNUM); \
|
||||
register int regnum; \
|
||||
char raw_buffer[12]; \
|
||||
sp = push_word (sp, read_register (PC_REGNUM)); \
|
||||
sp = push_word (sp, read_register (FP_REGNUM)); \
|
||||
write_register (FP_REGNUM, sp); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
{ read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \
|
||||
sp = push_bytes (sp, raw_buffer, 12); } \
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
sp = push_word (sp, read_register (regnum)); \
|
||||
sp = push_word (sp, read_register (PS_REGNUM)); \
|
||||
write_register (SP_REGNUM, sp); }
|
||||
|
||||
/* Discard from the stack the innermost frame,
|
||||
restoring all saved registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[12]; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
{ read_memory (fsr.regs[regnum], raw_buffer, 12); \
|
||||
write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
if (fsr.regs[PS_REGNUM]) \
|
||||
write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ()));}
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
fmovem 0xff,-(sp)
|
||||
moveml 0xfffc,-(sp)
|
||||
clrw -(sp)
|
||||
movew ccr,-(sp)
|
||||
/..* The arguments are pushed at this point by GDB;
|
||||
no code is needed in the dummy for this.
|
||||
The CALL_DUMMY_START_OFFSET gives the position of
|
||||
the following jsr instruction. *../
|
||||
jsr @@#32323232
|
||||
addl #69696969,sp
|
||||
bpt
|
||||
nop
|
||||
Note this is 28 bytes.
|
||||
We actually start executing at the jsr, since the pushing of the
|
||||
registers is done by PUSH_DUMMY_FRAME. If this were real code,
|
||||
the arguments for the function called by the jsr would be pushed
|
||||
between the moveml and the jsr, and we could allow it to execute through.
|
||||
But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done,
|
||||
and we cannot allow the moveml to push the registers again lest they be
|
||||
taken for the arguments. */
|
||||
|
||||
#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e414e71}
|
||||
|
||||
#define CALL_DUMMY_LENGTH 28
|
||||
|
||||
#define CALL_DUMMY_START_OFFSET 12
|
||||
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
||||
/* Interface definitions for kernel debugger KDB. */
|
||||
|
||||
/* Map machine fault codes into signal numbers.
|
||||
First subtract 0, divide by 4, then index in a table.
|
||||
Faults for which the entry in this table is 0
|
||||
are not handled by KDB; the program's own trap handler
|
||||
gets to handle then. */
|
||||
|
||||
#define FAULT_CODE_ORIGIN 0
|
||||
#define FAULT_CODE_UNITS 4
|
||||
#define FAULT_TABLE \
|
||||
{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \
|
||||
0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
SIGILL }
|
||||
|
||||
#ifndef HPUX_ASM
|
||||
|
||||
/* Start running with a stack stretching from BEG to END.
|
||||
BEG and END should be symbols meaningful to the assembler.
|
||||
This is used only for kdb. */
|
||||
|
||||
#define INIT_STACK(beg, end) \
|
||||
{ asm (".globl end"); \
|
||||
asm ("movel $ end, sp"); \
|
||||
asm ("clrl fp"); }
|
||||
|
||||
/* Push the frame pointer register on the stack. */
|
||||
#define PUSH_FRAME_PTR \
|
||||
asm ("movel fp, -(sp)");
|
||||
|
||||
/* Copy the top-of-stack to the frame pointer register. */
|
||||
#define POP_FRAME_PTR \
|
||||
asm ("movl (sp), fp");
|
||||
|
||||
/* After KDB is entered by a fault, push all registers
|
||||
that GDB thinks about (all NUM_REGS of them),
|
||||
so that they appear in order of ascending GDB register number.
|
||||
The fault code will be on the stack beyond the last register. */
|
||||
|
||||
#define PUSH_REGISTERS \
|
||||
{ asm ("clrw -(sp)"); \
|
||||
asm ("pea 10(sp)"); \
|
||||
asm ("movem $ 0xfffe,-(sp)"); }
|
||||
|
||||
/* Assuming the registers (including processor status) have been
|
||||
pushed on the stack in order of ascending GDB register number,
|
||||
restore them and return to the address in the saved PC register. */
|
||||
|
||||
#define POP_REGISTERS \
|
||||
{ asm ("subil $8,28(sp)"); \
|
||||
asm ("movem (sp),$ 0xffff"); \
|
||||
asm ("rte"); }
|
||||
|
||||
#else /* HPUX_ASM */
|
||||
|
||||
/* Start running with a stack stretching from BEG to END.
|
||||
BEG and END should be symbols meaningful to the assembler.
|
||||
This is used only for kdb. */
|
||||
|
||||
#define INIT_STACK(beg, end) \
|
||||
{ asm ("global end"); \
|
||||
asm ("mov.l &end,%sp"); \
|
||||
asm ("clr.l %a6"); }
|
||||
|
||||
/* Push the frame pointer register on the stack. */
|
||||
#define PUSH_FRAME_PTR \
|
||||
asm ("mov.l %fp,-(%sp)");
|
||||
|
||||
/* Copy the top-of-stack to the frame pointer register. */
|
||||
#define POP_FRAME_PTR \
|
||||
asm ("mov.l (%sp),%fp");
|
||||
|
||||
/* After KDB is entered by a fault, push all registers
|
||||
that GDB thinks about (all NUM_REGS of them),
|
||||
so that they appear in order of ascending GDB register number.
|
||||
The fault code will be on the stack beyond the last register. */
|
||||
|
||||
#define PUSH_REGISTERS \
|
||||
{ asm ("clr.w -(%sp)"); \
|
||||
asm ("pea 10(%sp)"); \
|
||||
asm ("movm.l &0xfffe,-(%sp)"); }
|
||||
|
||||
/* Assuming the registers (including processor status) have been
|
||||
pushed on the stack in order of ascending GDB register number,
|
||||
restore them and return to the address in the saved PC register. */
|
||||
|
||||
#define POP_REGISTERS \
|
||||
{ asm ("subi.l &8,28(%sp)"); \
|
||||
asm ("mov.m (%sp),&0xffff"); \
|
||||
asm ("rte"); }
|
||||
|
||||
#endif /* HPUX_ASM */
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d28 1
|
||||
a28 1
|
||||
#define HPUX_ASM
|
||||
d31 1
|
||||
a31 1
|
||||
#define HPUX_ASM
|
||||
@
|
747
gdb/RCS/m-sparc.h,v
Normal file
747
gdb/RCS/m-sparc.h,v
Normal file
@ -0,0 +1,747 @@
|
||||
head 1.3;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.3
|
||||
date 89.04.26.00.52.29; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.2;
|
||||
|
||||
1.2
|
||||
date 89.03.16.21.10.29; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.14.15.28.32; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.3
|
||||
log
|
||||
@(1) Define big-endianness of SPARC.
|
||||
(2) Define IEEE compatible float.
|
||||
@
|
||||
text
|
||||
@/* Parameters for execution on a Sun 4, for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
Contributed by Michael Tiemann (tiemann@@mcc.com)
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#ifndef sun4
|
||||
#define sun4
|
||||
#endif
|
||||
|
||||
/* Get rid of any system-imposed stack limit if possible. */
|
||||
|
||||
#define SET_STACK_LIMIT_HUGE
|
||||
|
||||
/* Define this if the C compiler puts an underscore at the front
|
||||
of external names before giving them to the linker. */
|
||||
|
||||
#define NAMES_HAVE_UNDERSCORE
|
||||
|
||||
/* Debugger information will be in DBX format. */
|
||||
|
||||
#define READ_DBX_FORMAT
|
||||
|
||||
/* Big or Little-Endian target machine
|
||||
BITS: defined if bit #0 is the high-order bit of a byte.
|
||||
BYTES:defined if byte#0 is the high-order byte of an int.
|
||||
WORDS:defined if word#0 is the high-order word of a double. */
|
||||
#define BITS_BIG_ENDIAN
|
||||
#define BYTES_BIG_ENDIAN
|
||||
#define WORDS_BIG_ENDIAN
|
||||
|
||||
/* Floating point is IEEE compatible. */
|
||||
#define IEEE_FLOAT
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
Zero on most machines. */
|
||||
|
||||
#define FUNCTION_START_OFFSET 0
|
||||
|
||||
/* Advance PC across any function entry prologue instructions
|
||||
to reach some "real" code. */
|
||||
|
||||
#define SKIP_PROLOGUE(pc) \
|
||||
{ pc = skip_prologue (pc); }
|
||||
|
||||
/* Immediately after a function call, return the saved pc.
|
||||
Can't go through the frames for this because on some machines
|
||||
the new frame is not set up until the new function executes
|
||||
some instructions. */
|
||||
|
||||
/* On the Sun 4 under SunOS, the compile will leave a fake insn which
|
||||
encodes the structure size being returned. If we detect such
|
||||
a fake insn, step past it. */
|
||||
|
||||
#define PC_ADJUST(pc) ((read_memory_integer (pc + 8, 4) & 0xfffffe00) == 0 ? \
|
||||
pc+12 : pc+8)
|
||||
|
||||
#define SAVED_PC_AFTER_CALL(frame) PC_ADJUST (read_register (RP_REGNUM))
|
||||
|
||||
/* Address of end of stack space. */
|
||||
|
||||
#define STACK_END_ADDR 0xf8000000
|
||||
|
||||
/* Stack grows downward. */
|
||||
|
||||
#define INNER_THAN <
|
||||
|
||||
/* Stack has strict alignment. */
|
||||
|
||||
#define STACK_ALIGN(ADDR) (((ADDR)+7)&-8)
|
||||
|
||||
/* Sequence of bytes for breakpoint instruction. */
|
||||
|
||||
#define BREAKPOINT {0x91, 0xd0, 0x20, 0x01}
|
||||
|
||||
/* Amount PC must be decremented by after a breakpoint.
|
||||
This is often the number of bytes in BREAKPOINT
|
||||
but not always. */
|
||||
|
||||
#define DECR_PC_AFTER_BREAK 0
|
||||
|
||||
/* Nonzero if instruction at PC is a return instruction. */
|
||||
/* For SPARC, this is either a "jmpl %o7+8,%g0" or "jmpl %i7+8,%g0".
|
||||
|
||||
Note: this does not work for functions returning structures under SunOS. */
|
||||
#define ABOUT_TO_RETURN(pc) \
|
||||
((read_memory_integer (pc, 4)|0x00040000) == 0x81c7e008)
|
||||
|
||||
/* Return 1 if P points to an invalid floating point value. */
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
|
||||
/* Number of machine registers */
|
||||
|
||||
#define NUM_REGS 72
|
||||
|
||||
/* Initializer for an array of names of registers.
|
||||
There should be NUM_REGS strings in this initializer. */
|
||||
|
||||
#define REGISTER_NAMES \
|
||||
{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", \
|
||||
"o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", \
|
||||
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", \
|
||||
"i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", \
|
||||
\
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
|
||||
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
|
||||
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
|
||||
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
|
||||
\
|
||||
"y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" };
|
||||
|
||||
/* Register numbers of various important registers.
|
||||
Note that some of these values are "real" register numbers,
|
||||
and correspond to the general registers of the machine,
|
||||
and some are "phony" register numbers which are too large
|
||||
to be actual register numbers as far as the user is concerned
|
||||
but do serve to get the desired values when passed to read_register. */
|
||||
|
||||
#define FP_REGNUM 30 /* Contains address of executing stack frame */
|
||||
#define RP_REGNUM 15 /* Contains return address value, *before* \
|
||||
any windows get switched. */
|
||||
#define SP_REGNUM 14 /* Contains address of top of stack, \
|
||||
which is also the bottom of the frame. */
|
||||
#define Y_REGNUM 64 /* Temp register for multiplication, etc. */
|
||||
#define PS_REGNUM 65 /* Contains processor status */
|
||||
#define PC_REGNUM 68 /* Contains program counter */
|
||||
#define NPC_REGNUM 69 /* Contains next PC */
|
||||
#define FP0_REGNUM 32 /* Floating point register 0 */
|
||||
#define FPS_REGNUM 70 /* Floating point status register */
|
||||
#define CPS_REGNUM 71 /* Coprocessor status register */
|
||||
|
||||
/* Total amount of space needed to store our copies of the machine's
|
||||
register state, the array `registers'. */
|
||||
#define REGISTER_BYTES (32*4+32*4+8*4)
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
/* ?? */
|
||||
#define REGISTER_BYTE(N) ((N)*4)
|
||||
|
||||
/* The SPARC processor has register windows. */
|
||||
|
||||
#define HAVE_REGISTER_WINDOWS
|
||||
|
||||
/* Is this register part of the register window system? A yes answer
|
||||
implies that 1) The name of this register will not be the same in
|
||||
other frames, and 2) This register is automatically "saved" (out
|
||||
registers shifting into ins counts) upon subroutine calls and thus
|
||||
there is no need to search more than one stack frame for it. */
|
||||
|
||||
#define REGISTER_IN_WINDOW_P(regnum) \
|
||||
((regnum) >= 8 && (regnum) < 32)
|
||||
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. */
|
||||
|
||||
/* On the SPARC, all regs are 4 bytes. */
|
||||
|
||||
#define REGISTER_RAW_SIZE(N) (4)
|
||||
|
||||
/* Number of bytes of storage in the program's representation
|
||||
for register N. */
|
||||
|
||||
/* On the SPARC, all regs are 4 bytes. */
|
||||
|
||||
#define REGISTER_VIRTUAL_SIZE(N) (4)
|
||||
|
||||
/* Largest value REGISTER_RAW_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_RAW_SIZE 8
|
||||
|
||||
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_VIRTUAL_SIZE 8
|
||||
|
||||
/* Nonzero if register N requires conversion
|
||||
from raw format to virtual format. */
|
||||
|
||||
#define REGISTER_CONVERTIBLE(N) (0)
|
||||
|
||||
/* Convert data from raw format for register REGNUM
|
||||
to virtual format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
|
||||
{ bcopy ((FROM), (TO), 4); }
|
||||
|
||||
/* Convert data from virtual format for register REGNUM
|
||||
to raw format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
|
||||
{ bcopy ((FROM), (TO), 4); }
|
||||
|
||||
/* Return the GDB type object for the "standard" data type
|
||||
of data in register N. */
|
||||
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
((N) < 32 ? builtin_type_int : (N) < 64 ? builtin_type_float : \
|
||||
builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_memory ((SP)+(16*4), &(ADDR), 4); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
bcopy (((int *)(REGBUF))+8, (VALBUF), TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Write into appropriate registers a function return value
|
||||
of type TYPE, given in virtual format. */
|
||||
/* On sparc, values are returned in register %o0. */
|
||||
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
|
||||
write_register_bytes (REGISTER_BYTE (8), VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
the address in which a function should return its structure value,
|
||||
as a CORE_ADDR (or an expression that can be used as one). */
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \
|
||||
(read_memory_integer (((int *)(REGBUF))[SP_REGNUM]+(16*4), 4))
|
||||
|
||||
/* Enable use of alternate code to read and write registers. */
|
||||
|
||||
#define NEW_SUN_PTRACE
|
||||
|
||||
/* Enable use of alternate code for Sun's format of core dump file. */
|
||||
|
||||
#define NEW_SUN_CORE
|
||||
|
||||
/* Do implement the attach and detach commands. */
|
||||
|
||||
#define ATTACH_DETACH
|
||||
|
||||
/* It is safe to look for symsegs on a Sun, because Sun's ld
|
||||
does not screw up with random garbage at end of file. */
|
||||
|
||||
#define READ_GDB_SYMSEGS
|
||||
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
#include <machine/reg.h>
|
||||
|
||||
#define GET_RWINDOW_REG(FRAME, REG) \
|
||||
(read_memory_integer (&((struct rwindow *)FRAME)->REG, 4))
|
||||
|
||||
/* FRAME_CHAIN takes a frame's nominal address
|
||||
and produces the frame's chain-pointer.
|
||||
|
||||
FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
|
||||
and produces the nominal address of the caller frame.
|
||||
|
||||
However, if FRAME_CHAIN_VALID returns zero,
|
||||
it means the given frame is the outermost one and has no caller.
|
||||
In that case, FRAME_CHAIN_COMBINE is not used. */
|
||||
|
||||
/* In the case of the Sun 4, the frame-chain's nominal address
|
||||
is held in the frame pointer register.
|
||||
|
||||
On the Sun4, the frame (in %fp) is %sp for the previous frame.
|
||||
From the previous frame's %sp, we can find the previous frame's
|
||||
%fp: it is in the save area just above the previous frame's %sp.
|
||||
|
||||
If we are setting up an arbitrary frame, we'll need to know where
|
||||
it ends. Hence the following. This part of the frame cache
|
||||
structure should be checked before it is assumed that this frame's
|
||||
bottom is in the stack pointer.
|
||||
|
||||
If there isn't a frame below this one, the bottom of this frame is
|
||||
in the stack pointer.
|
||||
|
||||
If there is a frame below this one, and the frame pointers are
|
||||
identical, it's a leaf frame and the bottoms are the same also.
|
||||
|
||||
Otherwise the bottom of this frame is the top of the next frame. */
|
||||
|
||||
#define EXTRA_FRAME_INFO FRAME_ADDR bottom;
|
||||
#define INIT_EXTRA_FRAME_INFO(fci) \
|
||||
(fci)->bottom = \
|
||||
((fci)->next ? \
|
||||
((fci)->frame == (fci)->next_frame ? \
|
||||
(fci)->next->bottom : (fci)->next->frame) : \
|
||||
read_register (SP_REGNUM));
|
||||
|
||||
#define FRAME_CHAIN(thisframe) \
|
||||
GET_RWINDOW_REG ((thisframe)->frame, rw_in[6])
|
||||
|
||||
/* Avoid checking FRAME_SAVED_PC since that screws us due to
|
||||
improperly set up saved PC on a signal trampoline call */
|
||||
#if 0
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
#else
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0)
|
||||
#endif
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
/* Where is the PC for a specific frame */
|
||||
|
||||
#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME)
|
||||
|
||||
/* If the argument is on the stack, it will be here. */
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_STRUCT_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
|
||||
/* We can't tell how many args there are
|
||||
now that the C compiler delays popping them. */
|
||||
#define FRAME_NUM_ARGS(val,fi) (val = -1)
|
||||
|
||||
/* Return number of bytes at start of arglist that are not really args. */
|
||||
|
||||
#define FRAME_ARGS_SKIP 68
|
||||
|
||||
/* Put here the code to store, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame.
|
||||
|
||||
Note that on register window machines, we are currently making the
|
||||
assumption that window registers are being saved somewhere in the
|
||||
frame in which they are being used. If they are stored in an
|
||||
inferior frame, find_saved_register will break.
|
||||
|
||||
On the Sun 4, the only time all registers are saved is when
|
||||
a dummy frame is involved. Otherwise, the only saved registers
|
||||
are the LOCAL and IN registers which are saved as a result
|
||||
of the "save/restore" opcodes. This condition is determined
|
||||
by address rather than by value. */
|
||||
|
||||
#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \
|
||||
{ register int regnum; \
|
||||
register CORE_ADDR pc; \
|
||||
FRAME_ADDR frame = read_register (FP_REGNUM); \
|
||||
FRAME fid = FRAME_INFO_ID (fi); \
|
||||
if (!fid) fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS"); \
|
||||
bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \
|
||||
if ((fi)->pc >= frame - CALL_DUMMY_LENGTH - 0x140 \
|
||||
&& (fi)->pc <= frame) \
|
||||
{ \
|
||||
for (regnum = 1; regnum < 8; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = \
|
||||
frame + regnum * 4 - 0xa0; \
|
||||
for (regnum = 24; regnum < 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = \
|
||||
frame + (regnum - 24) * 4 - 0xc0; \
|
||||
for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = \
|
||||
frame + (regnum - FP0_REGNUM) * 4 - 0x80; \
|
||||
for (regnum = 64; regnum < NUM_REGS; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = \
|
||||
frame + (regnum - 64) * 4 - 0xe0; \
|
||||
frame = (fi)->bottom ? \
|
||||
(fi)->bottom : read_register (SP_REGNUM); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
frame = (fi)->bottom ? \
|
||||
(fi)->bottom : read_register (SP_REGNUM); \
|
||||
for (regnum = 16; regnum < 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \
|
||||
} \
|
||||
if ((fi)->next) \
|
||||
{ \
|
||||
/* Pull off either the next frame pointer or \
|
||||
the stack pointer */ \
|
||||
FRAME_ADDR next_next_frame = \
|
||||
((fi)->next->bottom ? \
|
||||
(fi)->next->bottom : \
|
||||
read_register (SP_REGNUM)); \
|
||||
for (regnum = 8; regnum < 16; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = next_next_frame + regnum * 4; \
|
||||
} \
|
||||
/* Otherwise, whatever we would get from ptrace(GETREGS) */ \
|
||||
/* is accurate */ \
|
||||
for (regnum = 30; regnum < 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = frame + 15*4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
/*
|
||||
* First of all, let me give my opinion of what the DUMMY_FRAME
|
||||
* actually looks like.
|
||||
*
|
||||
* | |
|
||||
* | |
|
||||
* + - - - - - - - - - - - - - - - - +<-- fp (level 0)
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | Frame of innermost program |
|
||||
* | function |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* |---------------------------------|<-- sp (level 0), fp (c)
|
||||
* | |
|
||||
* DUMMY | fp0-31 |
|
||||
* | |
|
||||
* | ------ |<-- fp - 0x80
|
||||
* FRAME | g0-7 |<-- fp - 0xa0
|
||||
* | i0-7 |<-- fp - 0xc0
|
||||
* | other |<-- fp - 0xe0
|
||||
* | ? |
|
||||
* | ? |
|
||||
* |---------------------------------|<-- sp' = fp - 0x140
|
||||
* | |
|
||||
* xcution start | |
|
||||
* sp' + 0x94 -->| CALL_DUMMY (x code) |
|
||||
* | |
|
||||
* | |
|
||||
* |---------------------------------|<-- sp'' = fp - 0x200
|
||||
* | align sp to 8 byte boundary |
|
||||
* | ==> args to fn <== |
|
||||
* Room for | |
|
||||
* i & l's + agg | CALL_DUMMY_STACK_ADJUST = 0x0x44|
|
||||
* |---------------------------------|<-- final sp (variable)
|
||||
* | |
|
||||
* | Where function called will |
|
||||
* | build frame. |
|
||||
* | |
|
||||
* | |
|
||||
*
|
||||
* I understand everything in this picture except what the space
|
||||
* between fp - 0xe0 and fp - 0x140 is used for. Oh, and I don't
|
||||
* understand why there's a large chunk of CALL_DUMMY that never gets
|
||||
* executed (its function is superceeded by PUSH_DUMMY_FRAME; they
|
||||
* are designed to do the same thing).
|
||||
*
|
||||
* PUSH_DUMMY_FRAME saves the registers above sp' and pushes the
|
||||
* register file stack down one.
|
||||
*
|
||||
* call_function then writes CALL_DUMMY, pushes the args onto the
|
||||
* stack, and adjusts the stack pointer.
|
||||
*
|
||||
* run_stack_dummy then starts execution (in the middle of
|
||||
* CALL_DUMMY, as directed by call_function).
|
||||
*/
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
/* Note: to be perfectly correct, we have to restore the
|
||||
IN registers (which were the OUT registers of the calling frame). */
|
||||
/* Note that the write's are of registers in the context of the newly
|
||||
pushed frame. Thus the the fp*'s, the g*'s, the i*'s, and
|
||||
the others, of the new frame, are being saved.
|
||||
The locals are new; they don't need to be saved. The i's and l's of
|
||||
the last frame were saved by the do_save_insn in the register
|
||||
file (ie. on the stack, since a context switch happended imm after) */
|
||||
/* We note that the return pointer register does not *need* to have
|
||||
the pc saved into it (return from this frame will be accomplished
|
||||
by a POP_FRAME), however, just in case it might be needed, we will
|
||||
leave it. However, we will write the original value of RP into the
|
||||
location on the stack for saving i7 (what rp turns into upon call);
|
||||
this way we don't loose the value with our function call. */
|
||||
/* Note that the pc saved must be 8 less than the actual pc, since
|
||||
both POP_FRAME and the normal return sequence on the sparc return
|
||||
to 8 more than the value of RP_REGNUM */
|
||||
|
||||
#define PUSH_DUMMY_FRAME \
|
||||
{ extern char registers[]; \
|
||||
register int regnum; \
|
||||
CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
CORE_ADDR pc = read_register (PC_REGNUM) - 8; \
|
||||
CORE_ADDR rp = read_register (RP_REGNUM); \
|
||||
void do_save_insn (); \
|
||||
supply_register (RP_REGNUM, &pc); \
|
||||
do_save_insn (0x140); \
|
||||
fp = read_register (FP_REGNUM); \
|
||||
write_memory (fp - 0x80, ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * 4);\
|
||||
write_memory (fp - 0xa0, ®isters[REGISTER_BYTE (0)], 8 * 4); \
|
||||
write_memory (fp - 0xc0, ®isters[REGISTER_BYTE (24)], 7 * 4); \
|
||||
write_memory (fp - 0xa4, &rp, 4); \
|
||||
write_memory (fp - 0xe0, ®isters[REGISTER_BYTE (64)], 8 * 4); \
|
||||
}
|
||||
|
||||
/* Discard from the stack the innermost frame,
|
||||
restoring all saved registers.
|
||||
Note that the values stored in fsr by get_frame_saved_regs are *in
|
||||
the context of the inferior frame*. What this means is that the i
|
||||
regs of fsr must be restored into the o regs of the frame popped
|
||||
into. We don't care about the output regs of the inferior frame.
|
||||
|
||||
This is true for dummy frames. Is it true for normal frames? It
|
||||
really does appear so. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register CORE_ADDR pc; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[REGISTER_BYTES]; \
|
||||
void do_restore_insn (); \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
pc = read_memory_integer (fsr.regs[PC_REGNUM], 4); \
|
||||
do_restore_insn (PC_ADJUST (pc)); \
|
||||
if (fsr.regs[FP0_REGNUM]) \
|
||||
{ \
|
||||
read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4); \
|
||||
write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer, 32 * 4); \
|
||||
} \
|
||||
if (fsr.regs[1]) \
|
||||
{ \
|
||||
read_memory (fsr.regs[1], raw_buffer, 7 * 4); \
|
||||
write_register_bytes (REGISTER_BYTE (1), raw_buffer, 7 * 4); \
|
||||
} \
|
||||
if (fsr.regs[24]) \
|
||||
{ \
|
||||
read_memory (fsr.regs[24], raw_buffer, 8 * 4); \
|
||||
write_register_bytes (REGISTER_BYTE (8), raw_buffer, 8 * 4); \
|
||||
} \
|
||||
if (fsr.regs[PS_REGNUM]) \
|
||||
write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
|
||||
if (fsr.regs[Y_REGNUM]) \
|
||||
write_register (Y_REGNUM, read_memory_integer (fsr.regs[Y_REGNUM], 4)); \
|
||||
if (fsr.regs[NPC_REGNUM]) \
|
||||
write_register (NPC_REGNUM, read_memory_integer (fsr.regs[NPC_REGNUM], 4)); \
|
||||
flush_cached_frames (); \
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM), \
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
|
||||
save %sp,-0x140,%sp
|
||||
std %f30,[%fp-0x08]
|
||||
std %f28,[%fp-0x10]
|
||||
std %f26,[%fp-0x18]
|
||||
std %f24,[%fp-0x20]
|
||||
std %f22,[%fp-0x28]
|
||||
std %f20,[%fp-0x30]
|
||||
std %f18,[%fp-0x38]
|
||||
std %f16,[%fp-0x40]
|
||||
std %f14,[%fp-0x48]
|
||||
std %f12,[%fp-0x50]
|
||||
std %f10,[%fp-0x58]
|
||||
std %f8,[%fp-0x60]
|
||||
std %f6,[%fp-0x68]
|
||||
std %f4,[%fp-0x70]
|
||||
std %f2,[%fp-0x78]
|
||||
std %f0,[%fp-0x80]
|
||||
std %g6,[%fp-0x88]
|
||||
std %g4,[%fp-0x90]
|
||||
std %g2,[%fp-0x98]
|
||||
std %g0,[%fp-0xa0]
|
||||
std %i6,[%fp-0xa8]
|
||||
std %i4,[%fp-0xb0]
|
||||
std %i2,[%fp-0xb8]
|
||||
std %i0,[%fp-0xc0]
|
||||
nop ! stcsr [%fp-0xc4]
|
||||
nop ! stfsr [%fp-0xc8]
|
||||
nop ! wr %npc,[%fp-0xcc]
|
||||
nop ! wr %pc,[%fp-0xd0]
|
||||
rd %tbr,%o0
|
||||
st %o0,[%fp-0xd4]
|
||||
rd %wim,%o1
|
||||
st %o0,[%fp-0xd8]
|
||||
rd %psr,%o0
|
||||
st %o0,[%fp-0xdc]
|
||||
rd %y,%o0
|
||||
st %o0,[%fp-0xe0]
|
||||
|
||||
/..* The arguments are pushed at this point by GDB;
|
||||
no code is needed in the dummy for this.
|
||||
The CALL_DUMMY_START_OFFSET gives the position of
|
||||
the following ld instruction. *../
|
||||
|
||||
ld [%sp+0x58],%o5
|
||||
ld [%sp+0x54],%o4
|
||||
ld [%sp+0x50],%o3
|
||||
ld [%sp+0x4c],%o2
|
||||
ld [%sp+0x48],%o1
|
||||
call 0x00000000
|
||||
ld [%sp+0x44],%o0
|
||||
nop
|
||||
ta 1
|
||||
nop
|
||||
|
||||
note that this is 192 bytes, which is a multiple of 8 (not only 4) bytes.
|
||||
note that the `call' insn is a relative, not an absolute call.
|
||||
note that the `nop' at the end is needed to keep the trap from
|
||||
clobbering things (if NPC pointed to garbage instead).
|
||||
|
||||
We actually start executing at the `sethi', since the pushing of the
|
||||
registers (as arguments) is done by PUSH_DUMMY_FRAME. If this were
|
||||
real code, the arguments for the function called by the CALL would be
|
||||
pushed between the list of ST insns and the CALL, and we could allow
|
||||
it to execute through. But the arguments have to be pushed by GDB
|
||||
after the PUSH_DUMMY_FRAME is done, and we cannot allow these ST
|
||||
insns to be performed again, lest the registers saved be taken for
|
||||
arguments. */
|
||||
|
||||
#define CALL_DUMMY { 0x9de3bee0, 0xfd3fbff8, 0xf93fbff0, 0xf53fbfe8, \
|
||||
0xf13fbfe0, 0xed3fbfd8, 0xe93fbfd0, 0xe53fbfc8, \
|
||||
0xe13fbfc0, 0xdd3fbfb8, 0xd93fbfb0, 0xd53fbfa8, \
|
||||
0xd13fbfa0, 0xcd3fbf98, 0xc93fbf90, 0xc53fbf88, \
|
||||
0xc13fbf80, 0xcc3fbf78, 0xc83fbf70, 0xc43fbf68, \
|
||||
0xc03fbf60, 0xfc3fbf58, 0xf83fbf50, 0xf43fbf48, \
|
||||
0xf03fbf40, 0x01000000, 0x01000000, 0x01000000, \
|
||||
0x01000000, 0x91580000, 0xd027bf50, 0x93500000, \
|
||||
0xd027bf4c, 0x91480000, 0xd027bf48, 0x91400000, \
|
||||
0xd027bf44, 0xda03a058, 0xd803a054, 0xd603a050, \
|
||||
0xd403a04c, 0xd203a048, 0x40000000, 0xd003a044, \
|
||||
0x01000000, 0x91d02001, 0x01000000, 0x01000000}
|
||||
|
||||
#define CALL_DUMMY_LENGTH 192
|
||||
|
||||
#define CALL_DUMMY_START_OFFSET 148
|
||||
|
||||
#define CALL_DUMMY_STACK_ADJUST 68
|
||||
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ \
|
||||
*(int *)((char *) dummyname+168) = (0x40000000|((fun-(pc+168))>>2)); \
|
||||
if (TYPE_CODE (type) == TYPE_CODE_STRUCT \
|
||||
|| TYPE_CODE (type) == TYPE_CODE_UNION) \
|
||||
*(int *)((char *) dummyname+176) = (TYPE_LENGTH (type) & 0x1fff); \
|
||||
}
|
||||
|
||||
|
||||
/* Sparc has no reliable single step ptrace call */
|
||||
|
||||
#define NO_SINGLE_STEP 1
|
||||
|
||||
/* It does have a wait structure, and it might help things out . . . */
|
||||
|
||||
#define HAVE_WAIT_STRUCT
|
||||
|
||||
/* Handle a feature in the sun4 compiler ("call .stret4" at the end of
|
||||
functions returning structures). */
|
||||
|
||||
#define SUN4_COMPILER_FEATURE
|
||||
|
||||
/* We need two arguments (in general) to the "info frame" command.
|
||||
Note that the definition of this macro implies that there exists a
|
||||
function "setup_arbitrary_frame" in mach-dep.c */
|
||||
|
||||
#define FRAME_SPECIFICATION_DYADIC
|
||||
|
||||
/* KDB stuff flushed for now. */
|
||||
@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Don't stop the stack trace until the "next frame pointer" is zero.
|
||||
@
|
||||
text
|
||||
@d39 11
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d66 1
|
||||
a66 1
|
||||
#define STACK_END_ADDR 0xff000000
|
||||
d307 3
|
||||
d312 4
|
||||
@
|
824
gdb/RCS/m68k-pinsn.c,v
Normal file
824
gdb/RCS/m68k-pinsn.c,v
Normal file
@ -0,0 +1,824 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.03.27.20.19.34; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.20.19.29.33; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Change HPUX_ASM to USG_SGS_ASM since it's really the Sys V
|
||||
"Software Generation System" that we are fighting here.
|
||||
@
|
||||
text
|
||||
@/* Print m68k instructions for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "opcode.h"
|
||||
|
||||
/* 68k instructions are never longer than this many bytes. */
|
||||
#define MAXLEN 22
|
||||
|
||||
/* Number of elements in the opcode table. */
|
||||
#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
|
||||
|
||||
extern char *reg_names[];
|
||||
char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
|
||||
"fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
|
||||
|
||||
static unsigned char *print_insn_arg ();
|
||||
static unsigned char *print_indexed ();
|
||||
static void print_base ();
|
||||
static int fetch_arg ();
|
||||
|
||||
#define NEXTBYTE(p) (p += 2, ((char *)p)[-1])
|
||||
|
||||
#define NEXTWORD(p) \
|
||||
(p += 2, ((((char *)p)[-2]) << 8) + p[-1])
|
||||
|
||||
#define NEXTLONG(p) \
|
||||
(p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
|
||||
|
||||
#define NEXTSINGLE(p) \
|
||||
(p += 4, *((float *)(p - 4)))
|
||||
|
||||
#define NEXTDOUBLE(p) \
|
||||
(p += 8, *((double *)(p - 8)))
|
||||
|
||||
#define NEXTEXTEND(p) \
|
||||
(p += 12, 0.0) /* Need a function to convert from extended to double
|
||||
precision... */
|
||||
|
||||
#define NEXTPACKED(p) \
|
||||
(p += 12, 0.0) /* Need a function to convert from packed to double
|
||||
precision. Actually, it's easier to print a
|
||||
packed number than a double anyway, so maybe
|
||||
there should be a special case to handle this... */
|
||||
|
||||
/* Print the m68k instruction at address MEMADDR in debugged memory,
|
||||
on STREAM. Returns length of the instruction, in bytes. */
|
||||
|
||||
int
|
||||
print_insn (memaddr, stream)
|
||||
CORE_ADDR memaddr;
|
||||
FILE *stream;
|
||||
{
|
||||
unsigned char buffer[MAXLEN];
|
||||
register int i;
|
||||
register unsigned char *p;
|
||||
register char *d;
|
||||
register int bestmask;
|
||||
int best;
|
||||
|
||||
read_memory (memaddr, buffer, MAXLEN);
|
||||
|
||||
bestmask = 0;
|
||||
best = -1;
|
||||
for (i = 0; i < NOPCODES; i++)
|
||||
{
|
||||
register unsigned int opcode = m68k_opcodes[i].opcode;
|
||||
register unsigned int match = m68k_opcodes[i].match;
|
||||
if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
|
||||
&& ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
|
||||
&& ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
|
||||
&& ((0xff & buffer[3] & match) == (0xff & opcode)))
|
||||
{
|
||||
/* Don't use for printout the variants of divul and divsl
|
||||
that have the same register number in two places.
|
||||
The more general variants will match instead. */
|
||||
for (d = m68k_opcodes[i].args; *d; d += 2)
|
||||
if (d[1] == 'D')
|
||||
break;
|
||||
|
||||
/* Don't use for printout the variants of most floating
|
||||
point coprocessor instructions which use the same
|
||||
register number in two places, as above. */
|
||||
if (*d == 0)
|
||||
for (d = m68k_opcodes[i].args; *d; d += 2)
|
||||
if (d[1] == 't')
|
||||
break;
|
||||
|
||||
if (*d == 0 && match > bestmask)
|
||||
{
|
||||
best = i;
|
||||
bestmask = match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle undefined instructions. */
|
||||
if (best < 0)
|
||||
{
|
||||
fprintf (stream, "0%o", (buffer[0] << 8) + buffer[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
fprintf (stream, "%s", m68k_opcodes[best].name);
|
||||
|
||||
/* Point at first word of argument data,
|
||||
and at descriptor for first argument. */
|
||||
p = buffer + 2;
|
||||
|
||||
/* Why do this this way? -MelloN */
|
||||
for (d = m68k_opcodes[best].args; *d; d += 2)
|
||||
{
|
||||
if (d[0] == '#')
|
||||
{
|
||||
if (d[1] == 'l' && p - buffer < 6)
|
||||
p = buffer + 6;
|
||||
else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
|
||||
p = buffer + 4;
|
||||
}
|
||||
if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
|
||||
p = buffer + 4;
|
||||
if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
|
||||
p = buffer + 6;
|
||||
}
|
||||
|
||||
d = m68k_opcodes[best].args;
|
||||
|
||||
if (*d)
|
||||
fputc (' ', stream);
|
||||
|
||||
while (*d)
|
||||
{
|
||||
p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream);
|
||||
d += 2;
|
||||
if (*d && *(d - 2) != 'I' && *d != 'k')
|
||||
fprintf (stream, ",");
|
||||
}
|
||||
return p - buffer;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
print_insn_arg (d, buffer, p, addr, stream)
|
||||
char *d;
|
||||
unsigned char *buffer;
|
||||
register unsigned char *p;
|
||||
CORE_ADDR addr; /* PC for this arg to be relative to */
|
||||
FILE *stream;
|
||||
{
|
||||
register int val;
|
||||
register int place = d[1];
|
||||
int regno;
|
||||
register char *regname;
|
||||
register unsigned char *p1;
|
||||
register double flval;
|
||||
int flt_p;
|
||||
|
||||
switch (*d)
|
||||
{
|
||||
case 'C':
|
||||
fprintf (stream, "ccr");
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
fprintf (stream, "sr");
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
fprintf (stream, "usp");
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
{
|
||||
static struct { char *name; int value; } names[]
|
||||
= {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
|
||||
{"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
|
||||
{"msp", 0x803}, {"isp", 0x804}};
|
||||
|
||||
val = fetch_arg (buffer, place, 12);
|
||||
for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
|
||||
if (names[regno].value == val)
|
||||
{
|
||||
fprintf (stream, names[regno].name);
|
||||
break;
|
||||
}
|
||||
if (regno < 0)
|
||||
fprintf (stream, "%d", val);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
val = fetch_arg (buffer, place, 3);
|
||||
if (val == 0) val = 8;
|
||||
fprintf (stream, "#%d", val);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
val = fetch_arg (buffer, place, 8);
|
||||
if (val & 0x80)
|
||||
val = val - 0x100;
|
||||
fprintf (stream, "#%d", val);
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
val = fetch_arg (buffer, place, 4);
|
||||
fprintf (stream, "#%d", val);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3) + 010]);
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
fprintf (stream, "fp%d", fetch_arg (buffer, place, 3));
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
val = fetch_arg (buffer, place, 6);
|
||||
if (val & 0x20)
|
||||
fprintf (stream, "%s", reg_names [val & 7]);
|
||||
else
|
||||
fprintf (stream, "%d", val);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
fprintf (stream, "(%s)+", reg_names[fetch_arg (buffer, place, 3) + 8]);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
fprintf (stream, "-(%s)", reg_names[fetch_arg (buffer, place, 3) + 8]);
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
if (place == 'k')
|
||||
fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
|
||||
else if (place == 'C')
|
||||
{
|
||||
val = fetch_arg (buffer, place, 7);
|
||||
if ( val > 63 ) /* This is a signed constant. */
|
||||
val -= 128;
|
||||
fprintf (stream, "{#%d}", val);
|
||||
}
|
||||
else
|
||||
error ("Invalid arg format in opcode table: \"%c%c\".",
|
||||
*d, place);
|
||||
break;
|
||||
|
||||
case '#':
|
||||
p1 = buffer + 2;
|
||||
if (place == 's')
|
||||
val = fetch_arg (buffer, place, 4);
|
||||
else if (place == 'C')
|
||||
val = fetch_arg (buffer, place, 7);
|
||||
else if (place == '8')
|
||||
val = fetch_arg (buffer, place, 3);
|
||||
else if (place == '3')
|
||||
val = fetch_arg (buffer, place, 8);
|
||||
else if (place == 'b')
|
||||
val = NEXTBYTE (p1);
|
||||
else if (place == 'w')
|
||||
val = NEXTWORD (p1);
|
||||
else if (place == 'l')
|
||||
val = NEXTLONG (p1);
|
||||
else
|
||||
error ("Invalid arg format in opcode table: \"%c%c\".",
|
||||
*d, place);
|
||||
fprintf (stream, "#%d", val);
|
||||
break;
|
||||
|
||||
case '^':
|
||||
if (place == 's')
|
||||
val = fetch_arg (buffer, place, 4);
|
||||
else if (place == 'C')
|
||||
val = fetch_arg (buffer, place, 7);
|
||||
else if (place == '8')
|
||||
val = fetch_arg (buffer, place, 3);
|
||||
else if (place == 'b')
|
||||
val = NEXTBYTE (p);
|
||||
else if (place == 'w')
|
||||
val = NEXTWORD (p);
|
||||
else if (place == 'l')
|
||||
val = NEXTLONG (p);
|
||||
else
|
||||
error ("Invalid arg format in opcode table: \"%c%c\".",
|
||||
*d, place);
|
||||
fprintf (stream, "#%d", val);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
if (place == 'b')
|
||||
val = NEXTBYTE (p);
|
||||
else if (place == 'w')
|
||||
val = NEXTWORD (p);
|
||||
else if (place == 'l')
|
||||
val = NEXTLONG (p);
|
||||
else if (place == 'g')
|
||||
{
|
||||
val = ((char *)buffer)[1];
|
||||
if (val == 0)
|
||||
val = NEXTWORD (p);
|
||||
else if (val == -1)
|
||||
val = NEXTLONG (p);
|
||||
}
|
||||
else if (place == 'c')
|
||||
{
|
||||
if (buffer[1] & 0x40) /* If bit six is one, long offset */
|
||||
val = NEXTLONG (p);
|
||||
else
|
||||
val = NEXTWORD (p);
|
||||
}
|
||||
else
|
||||
error ("Invalid arg format in opcode table: \"%c%c\".",
|
||||
*d, place);
|
||||
|
||||
print_address (addr + val, stream);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
val = NEXTWORD (p);
|
||||
fprintf (stream, "%d(%s)", val, reg_names[fetch_arg (buffer, place, 3)]);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
fprintf (stream, "%s", fpcr_names[fetch_arg (buffer, place, 3)]);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */
|
||||
if (val != 1) /* Unusual coprocessor ID? */
|
||||
fprintf (stream, "(cpid=%d) ", val);
|
||||
if (place == 'i')
|
||||
p += 2; /* Skip coprocessor extended operands */
|
||||
break;
|
||||
|
||||
case '*':
|
||||
case '~':
|
||||
case '%':
|
||||
case ';':
|
||||
case '@@':
|
||||
case '!':
|
||||
case '$':
|
||||
case '?':
|
||||
case '/':
|
||||
case '&':
|
||||
|
||||
if (place == 'd')
|
||||
{
|
||||
val = fetch_arg (buffer, 'x', 6);
|
||||
val = ((val & 7) << 3) + ((val >> 3) & 7);
|
||||
}
|
||||
else
|
||||
val = fetch_arg (buffer, 's', 6);
|
||||
|
||||
/* Get register number assuming address register. */
|
||||
regno = (val & 7) + 8;
|
||||
regname = reg_names[regno];
|
||||
switch (val >> 3)
|
||||
{
|
||||
case 0:
|
||||
fprintf (stream, "%s", reg_names[val]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
fprintf (stream, "%s", regname);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
fprintf (stream, "(%s)", regname);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
fprintf (stream, "(%s)+", regname);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
fprintf (stream, "-(%s)", regname);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
val = NEXTWORD (p);
|
||||
fprintf (stream, "%d(%s)", val, regname);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
p = print_indexed (regno, p, addr, stream);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
switch (val & 7)
|
||||
{
|
||||
case 0:
|
||||
val = NEXTWORD (p);
|
||||
fprintf (stream, "@@#");
|
||||
print_address (val, stream);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
val = NEXTLONG (p);
|
||||
fprintf (stream, "@@#");
|
||||
print_address (val, stream);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
val = NEXTWORD (p);
|
||||
print_address (addr + val, stream);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
p = print_indexed (-1, p, addr, stream);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
flt_p = 1; /* Assume it's a float... */
|
||||
switch( place )
|
||||
{
|
||||
case 'b':
|
||||
val = NEXTBYTE (p);
|
||||
flt_p = 0;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
val = NEXTWORD (p);
|
||||
flt_p = 0;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
val = NEXTLONG (p);
|
||||
flt_p = 0;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
flval = NEXTSINGLE(p);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
flval = NEXTDOUBLE(p);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
flval = NEXTEXTEND(p);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
flval = NEXTPACKED(p);
|
||||
break;
|
||||
|
||||
default:
|
||||
error ("Invalid arg format in opcode table: \"%c%c\".",
|
||||
*d, place);
|
||||
}
|
||||
if ( flt_p ) /* Print a float? */
|
||||
fprintf (stream, "#%g", flval);
|
||||
else
|
||||
fprintf (stream, "#%d", val);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stream, "<invalid address mode 0%o>", val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
error ("Invalid arg format in opcode table: \"%c\".", *d);
|
||||
}
|
||||
|
||||
return (unsigned char *) p;
|
||||
}
|
||||
|
||||
/* Fetch BITS bits from a position in the instruction specified by CODE.
|
||||
CODE is a "place to put an argument", or 'x' for a destination
|
||||
that is a general address (mode and register).
|
||||
BUFFER contains the instruction. */
|
||||
|
||||
static int
|
||||
fetch_arg (buffer, code, bits)
|
||||
unsigned char *buffer;
|
||||
char code;
|
||||
int bits;
|
||||
{
|
||||
register int val;
|
||||
switch (code)
|
||||
{
|
||||
case 's':
|
||||
val = buffer[1];
|
||||
break;
|
||||
|
||||
case 'd': /* Destination, for register or quick. */
|
||||
val = (buffer[0] << 8) + buffer[1];
|
||||
val >>= 9;
|
||||
break;
|
||||
|
||||
case 'x': /* Destination, for general arg */
|
||||
val = (buffer[0] << 8) + buffer[1];
|
||||
val >>= 6;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
val = (buffer[3] >> 4);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
val = buffer[3];
|
||||
break;
|
||||
|
||||
case '1':
|
||||
val = (buffer[2] << 8) + buffer[3];
|
||||
val >>= 12;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
val = (buffer[2] << 8) + buffer[3];
|
||||
val >>= 6;
|
||||
break;
|
||||
|
||||
case '3':
|
||||
case 'j':
|
||||
val = (buffer[2] << 8) + buffer[3];
|
||||
break;
|
||||
|
||||
case '4':
|
||||
val = (buffer[4] << 8) + buffer[5];
|
||||
val >>= 12;
|
||||
break;
|
||||
|
||||
case '5':
|
||||
val = (buffer[4] << 8) + buffer[5];
|
||||
val >>= 6;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
val = (buffer[4] << 8) + buffer[5];
|
||||
break;
|
||||
|
||||
case '7':
|
||||
val = (buffer[2] << 8) + buffer[3];
|
||||
val >>= 7;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
val = (buffer[2] << 8) + buffer[3];
|
||||
val >>= 10;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
switch (bits)
|
||||
{
|
||||
case 3:
|
||||
return val & 7;
|
||||
case 4:
|
||||
return val & 017;
|
||||
case 5:
|
||||
return val & 037;
|
||||
case 6:
|
||||
return val & 077;
|
||||
case 7:
|
||||
return val & 0177;
|
||||
case 8:
|
||||
return val & 0377;
|
||||
case 12:
|
||||
return val & 07777;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Print an indexed argument. The base register is BASEREG (-1 for pc).
|
||||
P points to extension word, in buffer.
|
||||
ADDR is the nominal core address of that extension word. */
|
||||
|
||||
static unsigned char *
|
||||
print_indexed (basereg, p, addr, stream)
|
||||
int basereg;
|
||||
unsigned char *p;
|
||||
FILE *stream;
|
||||
CORE_ADDR addr;
|
||||
{
|
||||
register int word;
|
||||
static char *scales[] = {"", "*2", "*4", "*8"};
|
||||
register int base_disp;
|
||||
register int outer_disp;
|
||||
char buf[40];
|
||||
|
||||
word = NEXTWORD (p);
|
||||
|
||||
/* Generate the text for the index register.
|
||||
Where this will be output is not yet determined. */
|
||||
sprintf (buf, "[%s.%c%s]",
|
||||
reg_names[(word >> 12) & 0xf],
|
||||
(word & 0x800) ? 'l' : 'w',
|
||||
scales[(word >> 9) & 3]);
|
||||
|
||||
/* Handle the 68000 style of indexing. */
|
||||
|
||||
if ((word & 0x100) == 0)
|
||||
{
|
||||
print_base (basereg,
|
||||
((word & 0x80) ? word | 0xff00 : word & 0xff)
|
||||
+ ((basereg == -1) ? addr : 0),
|
||||
stream);
|
||||
fprintf (stream, "%s", buf);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Handle the generalized kind. */
|
||||
/* First, compute the displacement to add to the base register. */
|
||||
|
||||
if (word & 0200)
|
||||
basereg = -2;
|
||||
if (word & 0100)
|
||||
buf[0] = 0;
|
||||
base_disp = 0;
|
||||
switch ((word >> 4) & 3)
|
||||
{
|
||||
case 2:
|
||||
base_disp = NEXTWORD (p);
|
||||
break;
|
||||
case 3:
|
||||
base_disp = NEXTLONG (p);
|
||||
}
|
||||
if (basereg == -1)
|
||||
base_disp += addr;
|
||||
|
||||
/* Handle single-level case (not indirect) */
|
||||
|
||||
if ((word & 7) == 0)
|
||||
{
|
||||
print_base (basereg, base_disp, stream);
|
||||
fprintf (stream, "%s", buf);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Two level. Compute displacement to add after indirection. */
|
||||
|
||||
outer_disp = 0;
|
||||
switch (word & 3)
|
||||
{
|
||||
case 2:
|
||||
outer_disp = NEXTWORD (p);
|
||||
break;
|
||||
case 3:
|
||||
outer_disp = NEXTLONG (p);
|
||||
}
|
||||
|
||||
fprintf (stream, "%d(", outer_disp);
|
||||
print_base (basereg, base_disp, stream);
|
||||
|
||||
/* If postindexed, print the closeparen before the index. */
|
||||
if (word & 4)
|
||||
fprintf (stream, ")%s", buf);
|
||||
/* If preindexed, print the closeparen after the index. */
|
||||
else
|
||||
fprintf (stream, "%s)", buf);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Print a base register REGNO and displacement DISP, on STREAM.
|
||||
REGNO = -1 for pc, -2 for none (suppressed). */
|
||||
|
||||
static void
|
||||
print_base (regno, disp, stream)
|
||||
int regno;
|
||||
int disp;
|
||||
FILE *stream;
|
||||
{
|
||||
if (regno == -2)
|
||||
fprintf (stream, "%d", disp);
|
||||
else if (regno == -1)
|
||||
fprintf (stream, "0x%x", disp);
|
||||
else
|
||||
fprintf (stream, "%d(%s)", disp, reg_names[regno]);
|
||||
}
|
||||
|
||||
/* This is not part of insn printing, but it is machine-specific,
|
||||
so this is a convenient place to put it.
|
||||
|
||||
Convert a 68881 extended float to a double.
|
||||
FROM is the address of the extended float.
|
||||
Store the double in *TO. */
|
||||
|
||||
convert_from_68881 (from, to)
|
||||
char *from;
|
||||
double *to;
|
||||
{
|
||||
#ifdef USG_SGS_ASM
|
||||
asm ("mov.l 8(%a6),%a0");
|
||||
asm ("mov.l 12(%a6),%a1");
|
||||
asm ("fmove.x (%a0),%fp0");
|
||||
asm ("fmove.d %fp0,(%a1)");
|
||||
#else /* not USG_SGS_ASM */
|
||||
#if 0
|
||||
asm ("movl a6@@(8),a0");
|
||||
asm ("movl a6@@(12),a1");
|
||||
asm ("fmovex a0@@,fp0");
|
||||
asm ("fmoved fp0,a1@@");
|
||||
#else
|
||||
/* Hand-assemble those insns since some assemblers lose
|
||||
and some have different syntax. */
|
||||
asm (".word 020156");
|
||||
asm (".word 8");
|
||||
asm (".word 021156");
|
||||
asm (".word 12");
|
||||
asm (".long 0xf2104800");
|
||||
asm (".long 0xf2117400");
|
||||
#endif
|
||||
#endif /* not USG_SGS_ASM */
|
||||
}
|
||||
|
||||
/* The converse: convert the double *FROM to an extended float
|
||||
and store where TO points. */
|
||||
|
||||
convert_to_68881 (from, to)
|
||||
double *from;
|
||||
char *to;
|
||||
{
|
||||
#ifdef USG_SGS_ASM
|
||||
asm ("mov.l 8(%a6),%a0");
|
||||
asm ("mov.l 12(%a6),%a1");
|
||||
asm ("fmove.d (%a0),%fp0");
|
||||
asm ("fmove.x %fp0,(%a1)");
|
||||
#else /* not USG_SGS_ASM */
|
||||
#if 0
|
||||
asm ("movl a6@@(8),a0");
|
||||
asm ("movl a6@@(12),a1");
|
||||
asm ("fmoved a0@@,fp0");
|
||||
asm ("fmovex fp0,a1@@");
|
||||
#else
|
||||
/* Hand-assemble those insns since some assemblers lose. */
|
||||
asm (".word 020156");
|
||||
asm (".word 8");
|
||||
asm (".word 021156");
|
||||
asm (".word 12");
|
||||
asm (".long 0xf2105400");
|
||||
asm (".long 0xf2116800");
|
||||
#endif
|
||||
#endif /* not USG_SGS_ASM */
|
||||
}
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d717 1
|
||||
a717 1
|
||||
#ifdef HPUX_ASM
|
||||
d722 1
|
||||
a722 1
|
||||
#else /* not HPUX_ASM */
|
||||
d738 1
|
||||
a738 1
|
||||
#endif /* not HPUX_ASM */
|
||||
d748 1
|
||||
a748 1
|
||||
#ifdef HPUX_ASM
|
||||
d753 1
|
||||
a753 1
|
||||
#else /* not HPUX_ASM */
|
||||
d768 1
|
||||
a768 1
|
||||
#endif /* not HPUX_ASM */
|
||||
@
|
1348
gdb/RCS/main.c,v
Normal file
1348
gdb/RCS/main.c,v
Normal file
File diff suppressed because it is too large
Load Diff
75
gdb/RCS/munch,v
Executable file
75
gdb/RCS/munch,v
Executable file
@ -0,0 +1,75 @@
|
||||
head 1.3;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @# @;
|
||||
|
||||
|
||||
1.3
|
||||
date 89.03.27.21.15.45; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.2;
|
||||
|
||||
1.2
|
||||
date 89.03.27.20.18.28; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.20.18.58.17; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.3
|
||||
log
|
||||
@Fix up "munch" so it generates a name that doesn't match its own
|
||||
"grep" conventions. Change main so that it calls the new name,
|
||||
and also doesn't use the conventions for functions that should NOT
|
||||
be called by init.c.
|
||||
@
|
||||
text
|
||||
@#! /bin/sh
|
||||
|
||||
# create an initialization procedure from a list of .o files
|
||||
# Look in object files, find symbols including the string _initialize_,
|
||||
# and call each one as a function.
|
||||
|
||||
echo '/* Do not modify this file. It is created automatically by "munch". */'
|
||||
echo 'void init_all_files () {'
|
||||
|
||||
nm $* | egrep '_initialize_' | \
|
||||
sed -e 's/^.*\(initialize_[a-zA-Z_0-9]*\).*$/ _\1 ();/' | \
|
||||
sort -u
|
||||
|
||||
echo '}'
|
||||
@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Generic change: make it not care much about the output format of "nm".
|
||||
Now as long as _initialize_foo is not touching any other
|
||||
symbol or alphanumeric, we'll find it and use it.
|
||||
@
|
||||
text
|
||||
@d8 1
|
||||
a8 1
|
||||
echo 'void initialize_all_files () {'
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d4 2
|
||||
d10 3
|
||||
a12 1
|
||||
nm -p $* | egrep 'T *__?initialize_' | sed -e 's/^.*T *_*\(.*\)/ _\1 ();/'
|
||||
@
|
1707
gdb/RCS/printcmd.c,v
Normal file
1707
gdb/RCS/printcmd.c,v
Normal file
File diff suppressed because it is too large
Load Diff
662
gdb/RCS/remote.c,v
Normal file
662
gdb/RCS/remote.c,v
Normal file
@ -0,0 +1,662 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.03.27.20.21.22; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.20.18.45.46; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Avoid <sys/fcntl.h>.
|
||||
@
|
||||
text
|
||||
@/* Memory-access and commands for inferior process, for GDB.
|
||||
Copyright (C) 1988 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
/* Remote communication protocol.
|
||||
All values are encoded in ascii hex digits.
|
||||
|
||||
Request Packet
|
||||
|
||||
read registers g
|
||||
reply XX....X Each byte of register data
|
||||
is described by two hex digits.
|
||||
Registers are in the internal order
|
||||
for GDB, and the bytes in a register
|
||||
are in the same order the machine uses.
|
||||
or ENN for an error.
|
||||
|
||||
write regs GXX..XX Each byte of register data
|
||||
is described by two hex digits.
|
||||
reply OK for success
|
||||
ENN for an error
|
||||
|
||||
read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
|
||||
reply XX..XX XX..XX is mem contents
|
||||
or ENN NN is errno
|
||||
|
||||
write mem MAA..AA,LLLL:XX..XX
|
||||
AA..AA is address,
|
||||
LLLL is number of bytes,
|
||||
XX..XX is data
|
||||
reply OK for success
|
||||
ENN for an error
|
||||
|
||||
cont cAA..AA AA..AA is address to resume
|
||||
If AA..AA is omitted,
|
||||
resume at same address.
|
||||
|
||||
step sAA..AA AA..AA is address to resume
|
||||
If AA..AA is omitted,
|
||||
resume at same address.
|
||||
|
||||
There is no immediate reply to step or cont.
|
||||
The reply comes when the machine stops.
|
||||
It is SAA AA is the "signal number"
|
||||
|
||||
kill req k
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include "wait.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
#include <termio.h>
|
||||
#undef TIOCGETP
|
||||
#define TIOCGETP TCGETA
|
||||
#undef TIOCSETN
|
||||
#define TIOCSETN TCSETA
|
||||
#undef TIOCSETP
|
||||
#define TIOCSETP TCSETAF
|
||||
#define TERMINAL struct termio
|
||||
#else
|
||||
#include <sgtty.h>
|
||||
#define TERMINAL struct sgttyb
|
||||
#endif
|
||||
|
||||
int kiodebug;
|
||||
|
||||
int icache;
|
||||
|
||||
/* Descriptor for I/O to remote machine. */
|
||||
int remote_desc;
|
||||
|
||||
#define PBUFSIZ 400
|
||||
|
||||
static void remote_send ();
|
||||
static void putpkt ();
|
||||
static void getpkt ();
|
||||
static void dcache_flush ();
|
||||
|
||||
|
||||
/* Open a connection to a remote debugger.
|
||||
NAME is the filename used for communication. */
|
||||
|
||||
void
|
||||
remote_open (name, from_tty)
|
||||
char *name;
|
||||
int from_tty;
|
||||
{
|
||||
TERMINAL sg;
|
||||
|
||||
remote_debugging = 0;
|
||||
dcache_init ();
|
||||
|
||||
remote_desc = open (name, O_RDWR);
|
||||
if (remote_desc < 0)
|
||||
perror_with_name (name);
|
||||
|
||||
ioctl (remote_desc, TIOCGETP, &sg);
|
||||
#ifdef HAVE_TERMIO
|
||||
sg.c_lflag &= ~ICANON;
|
||||
#else
|
||||
sg.sg_flags = RAW;
|
||||
#endif
|
||||
ioctl (remote_desc, TIOCSETP, &sg);
|
||||
|
||||
if (from_tty)
|
||||
printf ("Remote debugging using %s\n", name);
|
||||
remote_debugging = 1;
|
||||
}
|
||||
|
||||
/* Convert hex digit A to a number. */
|
||||
|
||||
static int
|
||||
fromhex (a)
|
||||
int a;
|
||||
{
|
||||
if (a >= '0' && a <= '9')
|
||||
return a - '0';
|
||||
else if (a >= 'a' && a <= 'f')
|
||||
return a - 'a' + 10;
|
||||
else
|
||||
error ("Reply contains invalid hex digit");
|
||||
}
|
||||
|
||||
/* Convert number NIB to a hex digit. */
|
||||
|
||||
static int
|
||||
tohex (nib)
|
||||
int nib;
|
||||
{
|
||||
if (nib < 10)
|
||||
return '0'+nib;
|
||||
else
|
||||
return 'a'+nib-10;
|
||||
}
|
||||
|
||||
/* Tell the remote machine to resume. */
|
||||
|
||||
int
|
||||
remote_resume (step, signal)
|
||||
int step, signal;
|
||||
{
|
||||
char buf[PBUFSIZ];
|
||||
|
||||
dcache_flush ();
|
||||
|
||||
strcpy (buf, step ? "s": "c");
|
||||
|
||||
putpkt (buf);
|
||||
}
|
||||
|
||||
/* Wait until the remote machine stops, then return,
|
||||
storing status in STATUS just as `wait' would. */
|
||||
|
||||
int
|
||||
remote_wait (status)
|
||||
WAITTYPE *status;
|
||||
{
|
||||
char buf[PBUFSIZ];
|
||||
|
||||
WSETEXIT ((*status), 0);
|
||||
getpkt (buf);
|
||||
if (buf[0] == 'E')
|
||||
error ("Remote failure reply: %s", buf);
|
||||
if (buf[0] != 'S')
|
||||
error ("Invalid remote reply: %s", buf);
|
||||
WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))));
|
||||
}
|
||||
|
||||
/* Read the remote registers into the block REGS. */
|
||||
|
||||
void
|
||||
remote_fetch_registers (regs)
|
||||
char *regs;
|
||||
{
|
||||
char buf[PBUFSIZ];
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
sprintf (buf, "g");
|
||||
remote_send (buf);
|
||||
|
||||
/* Reply describes registers byte by byte,
|
||||
each byte encoded as two hex characters. */
|
||||
|
||||
p = buf;
|
||||
for (i = 0; i < REGISTER_BYTES; i++)
|
||||
{
|
||||
if (p[0] == 0 || p[1] == 0)
|
||||
error ("Remote reply is too short: %s", buf);
|
||||
regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the remote registers from the contents of the block REGS. */
|
||||
|
||||
void
|
||||
remote_store_registers (regs)
|
||||
char *regs;
|
||||
{
|
||||
char buf[PBUFSIZ];
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
buf[0] = 'G';
|
||||
|
||||
/* Command describes registers byte by byte,
|
||||
each byte encoded as two hex characters. */
|
||||
|
||||
p = buf + 1;
|
||||
for (i = 0; i < REGISTER_BYTES; i++)
|
||||
{
|
||||
*p++ = tohex ((regs[i] >> 4) & 0xf);
|
||||
*p++ = tohex (regs[i] & 0xf);
|
||||
}
|
||||
|
||||
remote_send (buf);
|
||||
}
|
||||
|
||||
/* Read a word from remote address ADDR and return it.
|
||||
This goes through the data cache. */
|
||||
|
||||
int
|
||||
remote_fetch_word (addr)
|
||||
CORE_ADDR addr;
|
||||
{
|
||||
if (icache)
|
||||
{
|
||||
extern CORE_ADDR text_start, text_end;
|
||||
|
||||
if (addr >= text_start && addr < text_end)
|
||||
{
|
||||
int buffer;
|
||||
xfer_core_file (addr, &buffer, sizeof (int));
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
return dcache_fetch (addr);
|
||||
}
|
||||
|
||||
/* Write a word WORD into remote address ADDR.
|
||||
This goes through the data cache. */
|
||||
|
||||
void
|
||||
remote_store_word (addr, word)
|
||||
CORE_ADDR addr;
|
||||
int word;
|
||||
{
|
||||
dcache_poke (addr, word);
|
||||
}
|
||||
|
||||
/* Write memory data directly to the remote machine.
|
||||
This does not inform the data cache; the data cache uses this.
|
||||
MEMADDR is the address in the remote memory space.
|
||||
MYADDR is the address of the buffer in our space.
|
||||
LEN is the number of bytes. */
|
||||
|
||||
void
|
||||
remote_write_bytes (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
char buf[PBUFSIZ];
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
if (len > PBUFSIZ / 2 - 20)
|
||||
abort ();
|
||||
|
||||
sprintf (buf, "M%x,%x:", memaddr, len);
|
||||
|
||||
/* Command describes registers byte by byte,
|
||||
each byte encoded as two hex characters. */
|
||||
|
||||
p = buf + strlen (buf);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
*p++ = tohex ((myaddr[i] >> 4) & 0xf);
|
||||
*p++ = tohex (myaddr[i] & 0xf);
|
||||
}
|
||||
|
||||
remote_send (buf);
|
||||
}
|
||||
|
||||
/* Read memory data directly from the remote machine.
|
||||
This does not use the data cache; the data cache uses this.
|
||||
MEMADDR is the address in the remote memory space.
|
||||
MYADDR is the address of the buffer in our space.
|
||||
LEN is the number of bytes. */
|
||||
|
||||
void
|
||||
remote_read_bytes (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
char buf[PBUFSIZ];
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
if (len > PBUFSIZ / 2 - 1)
|
||||
abort ();
|
||||
|
||||
sprintf (buf, "m%x,%x", memaddr, len);
|
||||
remote_send (buf);
|
||||
|
||||
/* Reply describes registers byte by byte,
|
||||
each byte encoded as two hex characters. */
|
||||
|
||||
p = buf;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (p[0] == 0 || p[1] == 0)
|
||||
error ("Remote reply is too short: %s", buf);
|
||||
myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
A debug packet whose contents are <data>
|
||||
is encapsulated for transmission in the form:
|
||||
|
||||
$ <data> # CSUM1 CSUM2
|
||||
|
||||
<data> must be ASCII alphanumeric and cannot include characters
|
||||
'$' or '#'
|
||||
|
||||
CSUM1 and CSUM2 are ascii hex representation of an 8-bit
|
||||
checksum of <data>, the most significant nibble is sent first.
|
||||
the hex digits 0-9,a-f are used.
|
||||
|
||||
Receiver responds with:
|
||||
|
||||
+ - if CSUM is correct and ready for next packet
|
||||
- - if CSUM is incorrect
|
||||
|
||||
*/
|
||||
|
||||
/* Send the command in BUF to the remote machine,
|
||||
and read the reply into BUF.
|
||||
Report an error if we get an error reply. */
|
||||
|
||||
static void
|
||||
remote_send (buf)
|
||||
char *buf;
|
||||
{
|
||||
int i;
|
||||
putpkt (buf);
|
||||
getpkt (buf);
|
||||
|
||||
if (buf[0] == 'E')
|
||||
error ("Remote failure reply: %s", buf);
|
||||
}
|
||||
|
||||
/* Send a packet to the remote machine, with error checking.
|
||||
The data of the packet is in BUF. */
|
||||
|
||||
static void
|
||||
putpkt (buf)
|
||||
char *buf;
|
||||
{
|
||||
int i;
|
||||
char csum = 0;
|
||||
char buf2[500];
|
||||
char buf3[1];
|
||||
int cnt = strlen (buf);
|
||||
char *p;
|
||||
|
||||
if (kiodebug)
|
||||
fprintf (stderr, "Sending packet: %s\n", buf);
|
||||
|
||||
/* Copy the packet into buffer BUF2, encapsulating it
|
||||
and giving it a checksum. */
|
||||
|
||||
p = buf2;
|
||||
*p++ = '$';
|
||||
|
||||
for (i = 0; i < cnt; i++)
|
||||
{
|
||||
csum += buf[i];
|
||||
*p++ = buf[i];
|
||||
}
|
||||
*p++ = '#';
|
||||
*p++ = tohex ((csum >> 4) & 0xf);
|
||||
*p++ = tohex (csum & 0xf);
|
||||
|
||||
/* Send it over and over until we get a positive ack. */
|
||||
|
||||
do {
|
||||
write (remote_desc, buf2, p - buf2);
|
||||
read (remote_desc, buf3, 1);
|
||||
} while (buf3[0] != '+');
|
||||
}
|
||||
|
||||
static int
|
||||
readchar ()
|
||||
{
|
||||
char buf[1];
|
||||
while (read (remote_desc, buf, 1) != 1) ;
|
||||
return buf[0] & 0x7f;
|
||||
}
|
||||
|
||||
/* Read a packet from the remote machine, with error checking,
|
||||
and store it in BUF. */
|
||||
|
||||
static void
|
||||
getpkt (buf)
|
||||
char *buf;
|
||||
{
|
||||
char *bp;
|
||||
unsigned char csum;
|
||||
unsigned int c, c1, c2;
|
||||
extern kiodebug;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Force csum to be zero here because of possible error retry. */
|
||||
csum = 0;
|
||||
|
||||
while ((c = readchar()) != '$');
|
||||
|
||||
bp = buf;
|
||||
while (1)
|
||||
{
|
||||
c = readchar ();
|
||||
if (c == '#')
|
||||
break;
|
||||
*bp++ = c;
|
||||
csum += c;
|
||||
}
|
||||
*bp = 0;
|
||||
|
||||
c1 = fromhex (readchar ());
|
||||
c2 = fromhex (readchar ());
|
||||
if (csum == (c1 << 4) + c2)
|
||||
break;
|
||||
printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
|
||||
(c1 << 4) + c2, csum, buf);
|
||||
write (remote_desc, "-", 1);
|
||||
}
|
||||
|
||||
write (remote_desc, "+", 1);
|
||||
|
||||
if (kiodebug)
|
||||
fprintf (stderr,"Packet received :%s\n", buf);
|
||||
}
|
||||
|
||||
/* The data cache records all the data read from the remote machine
|
||||
since the last time it stopped.
|
||||
|
||||
Each cache block holds 16 bytes of data
|
||||
starting at a multiple-of-16 address. */
|
||||
|
||||
#define DCACHE_SIZE 64 /* Number of cache blocks */
|
||||
|
||||
struct dcache_block {
|
||||
struct dcache_block *next, *last;
|
||||
unsigned int addr; /* Address for which data is recorded. */
|
||||
int data[4];
|
||||
};
|
||||
|
||||
struct dcache_block dcache_free, dcache_valid;
|
||||
|
||||
/* Free all the data cache blocks, thus discarding all cached data. */
|
||||
|
||||
static void
|
||||
dcache_flush ()
|
||||
{
|
||||
register struct dcache_block *db;
|
||||
|
||||
while ((db = dcache_valid.next) != &dcache_valid)
|
||||
{
|
||||
remque (db);
|
||||
insque (db, &dcache_free);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If addr is present in the dcache, return the address of the block
|
||||
* containing it.
|
||||
*/
|
||||
|
||||
struct dcache_block *
|
||||
dcache_hit (addr)
|
||||
{
|
||||
register struct dcache_block *db;
|
||||
|
||||
if (addr & 3)
|
||||
abort ();
|
||||
|
||||
/* Search all cache blocks for one that is at this address. */
|
||||
db = dcache_valid.next;
|
||||
while (db != &dcache_valid)
|
||||
{
|
||||
if ((addr & 0xfffffff0) == db->addr)
|
||||
return db;
|
||||
db = db->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the int data at address ADDR in dcache block DC. */
|
||||
|
||||
int
|
||||
dcache_value (db, addr)
|
||||
struct dcache_block *db;
|
||||
unsigned int addr;
|
||||
{
|
||||
if (addr & 3)
|
||||
abort ();
|
||||
return (db->data[(addr>>2)&3]);
|
||||
}
|
||||
|
||||
/* Get a free cache block, put it on the valid list,
|
||||
and return its address. The caller should store into the block
|
||||
the address and data that it describes. */
|
||||
|
||||
struct dcache_block *
|
||||
dcache_alloc ()
|
||||
{
|
||||
register struct dcache_block *db;
|
||||
|
||||
if ((db = dcache_free.next) == &dcache_free)
|
||||
/* If we can't get one from the free list, take last valid */
|
||||
db = dcache_valid.last;
|
||||
|
||||
remque (db);
|
||||
insque (db, &dcache_valid);
|
||||
return (db);
|
||||
}
|
||||
|
||||
/* Return the contents of the word at address ADDR in the remote machine,
|
||||
using the data cache. */
|
||||
|
||||
int
|
||||
dcache_fetch (addr)
|
||||
CORE_ADDR addr;
|
||||
{
|
||||
register struct dcache_block *db;
|
||||
|
||||
db = dcache_hit (addr);
|
||||
if (db == 0)
|
||||
{
|
||||
db = dcache_alloc ();
|
||||
remote_read_bytes (addr & ~0xf, db->data, 16);
|
||||
db->addr = addr & ~0xf;
|
||||
}
|
||||
return (dcache_value (db, addr));
|
||||
}
|
||||
|
||||
/* Write the word at ADDR both in the data cache and in the remote machine. */
|
||||
|
||||
dcache_poke (addr, data)
|
||||
CORE_ADDR addr;
|
||||
int data;
|
||||
{
|
||||
register struct dcache_block *db;
|
||||
|
||||
/* First make sure the word is IN the cache. DB is its cache block. */
|
||||
db = dcache_hit (addr);
|
||||
if (db == 0)
|
||||
{
|
||||
db = dcache_alloc ();
|
||||
remote_read_bytes (addr & ~0xf, db->data, 16);
|
||||
db->addr = addr & ~0xf;
|
||||
}
|
||||
|
||||
/* Modify the word in the cache. */
|
||||
db->data[(addr>>2)&3] = data;
|
||||
|
||||
/* Send the changed word. */
|
||||
remote_write_bytes (addr, &data, 4);
|
||||
}
|
||||
|
||||
/* Initialize the data cache. */
|
||||
|
||||
dcache_init ()
|
||||
{
|
||||
register i;
|
||||
register struct dcache_block *db;
|
||||
|
||||
db = (struct dcache_block *) xmalloc (sizeof (struct dcache_block) *
|
||||
DCACHE_SIZE);
|
||||
dcache_free.next = dcache_free.last = &dcache_free;
|
||||
dcache_valid.next = dcache_valid.last = &dcache_valid;
|
||||
for (i=0;i<DCACHE_SIZE;i++,db++)
|
||||
insque (db, &dcache_free);
|
||||
}
|
||||
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d74 1
|
||||
a74 1
|
||||
#include <sys/fcntl.h>
|
||||
@
|
990
gdb/RCS/source.c,v
Normal file
990
gdb/RCS/source.c,v
Normal file
@ -0,0 +1,990 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.03.27.20.21.45; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.20.18.45.48; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Avoid <sys/fcntl.h>.
|
||||
@
|
||||
text
|
||||
@/* List lines of source files for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "symtab.h"
|
||||
#include "param.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
/* Path of directories to search for source files.
|
||||
Same format as the PATH environment variable's value. */
|
||||
|
||||
static char *source_path;
|
||||
|
||||
/* Symtab of default file for listing lines of. */
|
||||
|
||||
struct symtab *current_source_symtab;
|
||||
|
||||
/* Default next line to list. */
|
||||
|
||||
int current_source_line;
|
||||
|
||||
/* Line number of last line printed. Default for various commands.
|
||||
current_source_line is usually, but not always, the same as this. */
|
||||
|
||||
static int last_line_listed;
|
||||
|
||||
/* First line number listed by last listing command. */
|
||||
|
||||
static int first_line_listed;
|
||||
|
||||
|
||||
struct symtab *psymtab_to_symtab ();
|
||||
|
||||
/* Set the source file default for the "list" command,
|
||||
specifying a symtab. */
|
||||
|
||||
void
|
||||
select_source_symtab (s)
|
||||
register struct symtab *s;
|
||||
{
|
||||
struct symtabs_and_lines sals;
|
||||
struct symtab_and_line sal;
|
||||
struct partial_symtab *ps, *cs_pst;
|
||||
|
||||
/* Make the default place to list be the function `main'
|
||||
if one exists. */
|
||||
if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0))
|
||||
{
|
||||
sals = decode_line_spec ("main", 1);
|
||||
sal = sals.sals[0];
|
||||
free (sals.sals);
|
||||
current_source_symtab = sal.symtab;
|
||||
current_source_line = sal.line - 9;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is no `main', use the last symtab in the list,
|
||||
which is actually the first found in the file's symbol table.
|
||||
But ignore .h files. */
|
||||
if (s)
|
||||
{
|
||||
do
|
||||
{
|
||||
char *name = s->filename;
|
||||
int len = strlen (name);
|
||||
if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
|
||||
current_source_symtab = s;
|
||||
s = s->next;
|
||||
}
|
||||
while (s);
|
||||
current_source_line = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ps = partial_symtab_list;
|
||||
while (ps)
|
||||
{
|
||||
char *name = ps->filename;
|
||||
int len = strlen (name);
|
||||
if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
|
||||
cs_pst = ps;
|
||||
ps = ps->next;
|
||||
}
|
||||
if (cs_pst)
|
||||
current_source_symtab = psymtab_to_symtab (cs_pst);
|
||||
else
|
||||
current_source_symtab = 0;
|
||||
current_source_line = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
directories_info ()
|
||||
{
|
||||
printf ("Source directories searched: %s\n", source_path);
|
||||
}
|
||||
|
||||
void
|
||||
init_source_path ()
|
||||
{
|
||||
register struct symtab *s;
|
||||
|
||||
source_path = savestring (current_directory, strlen (current_directory));
|
||||
|
||||
/* Forget what we learned about line positions in source files;
|
||||
must check again now since files may be found in
|
||||
a different directory now. */
|
||||
for (s = symtab_list; s; s = s->next)
|
||||
if (s->line_charpos != 0)
|
||||
{
|
||||
free (s->line_charpos);
|
||||
s->line_charpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
directory_command (dirname, from_tty)
|
||||
char *dirname;
|
||||
int from_tty;
|
||||
{
|
||||
char *old = source_path;
|
||||
|
||||
if (dirname == 0)
|
||||
{
|
||||
if (query ("Reinitialize source path to %s? ", current_directory))
|
||||
{
|
||||
init_source_path ();
|
||||
free (old);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat st;
|
||||
register int len = strlen (dirname);
|
||||
register char *tem;
|
||||
extern char *index ();
|
||||
|
||||
if (index (dirname, ':'))
|
||||
error ("Please add one directory at a time to the source path.");
|
||||
if (dirname[len - 1] == '/')
|
||||
/* Sigh. "foo/" => "foo" */
|
||||
dirname[--len] == '\0';
|
||||
|
||||
while (dirname[len - 1] == '.')
|
||||
{
|
||||
if (len == 1)
|
||||
{
|
||||
/* "." => getwd () */
|
||||
dirname = current_directory;
|
||||
goto append;
|
||||
}
|
||||
else if (dirname[len - 2] == '/')
|
||||
{
|
||||
if (len == 2)
|
||||
{
|
||||
/* "/." => "/" */
|
||||
dirname[--len] = '\0';
|
||||
goto append;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* "...foo/." => "...foo" */
|
||||
dirname[len -= 2] = '\0';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dirname[0] != '/')
|
||||
dirname = concat (current_directory, "/", dirname);
|
||||
else
|
||||
dirname = savestring (dirname, len);
|
||||
make_cleanup (free, dirname);
|
||||
|
||||
if (stat (dirname, &st) < 0)
|
||||
perror_with_name (dirname);
|
||||
if ((st.st_mode & S_IFMT) != S_IFDIR)
|
||||
error ("%s is not a directory.", dirname);
|
||||
|
||||
append:
|
||||
len = strlen (dirname);
|
||||
tem = source_path;
|
||||
while (1)
|
||||
{
|
||||
if (!strncmp (tem, dirname, len)
|
||||
&& (tem[len] == '\0' || tem[len] == ':'))
|
||||
{
|
||||
printf ("\"%s\" is already in the source path.\n",
|
||||
dirname);
|
||||
break;
|
||||
}
|
||||
tem = index (tem, ':');
|
||||
if (tem)
|
||||
tem++;
|
||||
else
|
||||
{
|
||||
source_path = concat (old, ":", dirname);
|
||||
free (old);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (from_tty)
|
||||
directories_info ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Open a file named STRING, searching path PATH (dir names sep by colons)
|
||||
using mode MODE and protection bits PROT in the calls to open.
|
||||
If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
|
||||
(ie pretend the first element of PATH is ".")
|
||||
If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
|
||||
the actual file opened (this string will always start with a "/"
|
||||
|
||||
If a file is found, return the descriptor.
|
||||
Otherwise, return -1, with errno set for the last name we tried to open. */
|
||||
|
||||
/* >>>> This should only allow files of certain types,
|
||||
>>>> eg executable, non-directory */
|
||||
int
|
||||
openp (path, try_cwd_first, string, mode, prot, filename_opened)
|
||||
char *path;
|
||||
int try_cwd_first;
|
||||
char *string;
|
||||
int mode;
|
||||
int prot;
|
||||
char **filename_opened;
|
||||
{
|
||||
register int fd;
|
||||
register char *filename;
|
||||
register char *p, *p1;
|
||||
register int len;
|
||||
|
||||
/* ./foo => foo */
|
||||
while (string[0] == '.' && string[1] == '/')
|
||||
string += 2;
|
||||
|
||||
if (try_cwd_first || string[0] == '/')
|
||||
{
|
||||
filename = string;
|
||||
fd = open (filename, mode, prot);
|
||||
if (fd >= 0 || string[0] == '/')
|
||||
goto done;
|
||||
}
|
||||
|
||||
filename = (char *) alloca (strlen (path) + strlen (string) + 2);
|
||||
fd = -1;
|
||||
for (p = path; p; p = p1 ? p1 + 1 : 0)
|
||||
{
|
||||
p1 = (char *) index (p, ':');
|
||||
if (p1)
|
||||
len = p1 - p;
|
||||
else
|
||||
len = strlen (p);
|
||||
|
||||
strncpy (filename, p, len);
|
||||
filename[len] = 0;
|
||||
strcat (filename, "/");
|
||||
strcat (filename, string);
|
||||
|
||||
fd = open (filename, mode, prot);
|
||||
if (fd >= 0) break;
|
||||
}
|
||||
|
||||
done:
|
||||
if (filename_opened)
|
||||
if (fd < 0)
|
||||
*filename_opened = (char *) 0;
|
||||
else if (filename[0] == '/')
|
||||
*filename_opened = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
*filename_opened = concat (current_directory, "/", filename);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Create and initialize the table S->line_charpos that records
|
||||
the positions of the lines in the source file, which is assumed
|
||||
to be open on descriptor DESC.
|
||||
All set S->nlines to the number of such lines. */
|
||||
|
||||
static void
|
||||
find_source_lines (s, desc)
|
||||
struct symtab *s;
|
||||
int desc;
|
||||
{
|
||||
struct stat st;
|
||||
register char *data, *p, *end;
|
||||
int nlines = 0;
|
||||
int lines_allocated = 1000;
|
||||
int *line_charpos = (int *) xmalloc (lines_allocated * sizeof (int));
|
||||
extern int exec_mtime;
|
||||
|
||||
fstat (desc, &st);
|
||||
if (get_exec_file (0) != 0 && exec_mtime < st.st_mtime)
|
||||
printf ("Source file is more recent than executable.\n");
|
||||
|
||||
data = (char *) alloca (st.st_size);
|
||||
myread (desc, data, st.st_size);
|
||||
end = data + st.st_size;
|
||||
p = data;
|
||||
line_charpos[0] = 0;
|
||||
nlines = 1;
|
||||
while (p != end)
|
||||
{
|
||||
if (*p++ == '\n'
|
||||
/* A newline at the end does not start a new line. */
|
||||
&& p != end)
|
||||
{
|
||||
if (nlines == lines_allocated)
|
||||
{
|
||||
lines_allocated *= 2;
|
||||
line_charpos = (int *) xrealloc (line_charpos,
|
||||
sizeof (int) * lines_allocated);
|
||||
}
|
||||
line_charpos[nlines++] = p - data;
|
||||
}
|
||||
}
|
||||
s->nlines = nlines;
|
||||
s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int));
|
||||
}
|
||||
|
||||
/* Return the character position of a line LINE in symtab S.
|
||||
Return 0 if anything is invalid. */
|
||||
|
||||
int
|
||||
source_line_charpos (s, line)
|
||||
struct symtab *s;
|
||||
int line;
|
||||
{
|
||||
if (!s) return 0;
|
||||
if (!s->line_charpos || line <= 0) return 0;
|
||||
if (line > s->nlines)
|
||||
line = s->nlines;
|
||||
return s->line_charpos[line - 1];
|
||||
}
|
||||
|
||||
/* Return the line number of character position POS in symtab S. */
|
||||
|
||||
int
|
||||
source_charpos_line (s, chr)
|
||||
register struct symtab *s;
|
||||
register int chr;
|
||||
{
|
||||
register int line = 0;
|
||||
register int *lnp;
|
||||
|
||||
if (s == 0 || s->line_charpos == 0) return 0;
|
||||
lnp = s->line_charpos;
|
||||
/* Files are usually short, so sequential search is Ok */
|
||||
while (line < s->nlines && *lnp <= chr)
|
||||
{
|
||||
line++;
|
||||
lnp++;
|
||||
}
|
||||
if (line >= s->nlines)
|
||||
line = s->nlines;
|
||||
return line;
|
||||
}
|
||||
|
||||
/* Get full pathname and line number positions for a symtab.
|
||||
Return nonzero if line numbers may have changed.
|
||||
Set *FULLNAME to actual name of the file as found by `openp',
|
||||
or to 0 if the file is not found. */
|
||||
|
||||
int
|
||||
get_filename_and_charpos (s, line, fullname)
|
||||
struct symtab *s;
|
||||
int line;
|
||||
char **fullname;
|
||||
{
|
||||
register int desc, linenums_changed = 0;
|
||||
|
||||
desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
|
||||
if (desc < 0)
|
||||
{
|
||||
if (fullname)
|
||||
*fullname = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (fullname)
|
||||
*fullname = s->fullname;
|
||||
if (s->line_charpos == 0) linenums_changed = 1;
|
||||
if (linenums_changed) find_source_lines (s, desc);
|
||||
close (desc);
|
||||
return linenums_changed;
|
||||
}
|
||||
|
||||
/* Print text describing the full name of the source file S
|
||||
and the line number LINE and its corresponding character position.
|
||||
The text starts with two Ctrl-z so that the Emacs-GDB interface
|
||||
can easily find it.
|
||||
|
||||
MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
|
||||
|
||||
Return 1 if successful, 0 if could not find the file. */
|
||||
|
||||
int
|
||||
identify_source_line (s, line, mid_statement)
|
||||
struct symtab *s;
|
||||
int line;
|
||||
int mid_statement;
|
||||
{
|
||||
if (s->line_charpos == 0)
|
||||
get_filename_and_charpos (s, line, 0);
|
||||
if (s->fullname == 0)
|
||||
return 0;
|
||||
printf ("\032\032%s:%d:%d:%s\n", s->fullname,
|
||||
line, s->line_charpos[line - 1],
|
||||
mid_statement ? "middle" : "beg");
|
||||
current_source_line = line;
|
||||
first_line_listed = line;
|
||||
last_line_listed = line;
|
||||
current_source_symtab = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print source lines from the file of symtab S,
|
||||
starting with line number LINE and stopping before line number STOPLINE. */
|
||||
|
||||
void
|
||||
print_source_lines (s, line, stopline, noerror)
|
||||
struct symtab *s;
|
||||
int line, stopline;
|
||||
int noerror;
|
||||
{
|
||||
register int c;
|
||||
register int desc;
|
||||
register FILE *stream;
|
||||
int nlines = stopline - line;
|
||||
|
||||
desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
|
||||
if (desc < 0)
|
||||
{
|
||||
extern int errno;
|
||||
if (! noerror)
|
||||
perror_with_name (s->filename);
|
||||
print_sys_errmsg (s->filename, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->line_charpos == 0)
|
||||
find_source_lines (s, desc);
|
||||
|
||||
if (line < 1 || line > s->nlines)
|
||||
{
|
||||
close (desc);
|
||||
error ("Line number out of range; %s has %d lines.",
|
||||
s->filename, s->nlines);
|
||||
}
|
||||
|
||||
if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
|
||||
{
|
||||
close (desc);
|
||||
perror_with_name (s->filename);
|
||||
}
|
||||
|
||||
current_source_symtab = s;
|
||||
current_source_line = line;
|
||||
first_line_listed = line;
|
||||
|
||||
stream = fdopen (desc, "r");
|
||||
clearerr (stream);
|
||||
|
||||
while (nlines-- > 0)
|
||||
{
|
||||
c = fgetc (stream);
|
||||
if (c == EOF) break;
|
||||
last_line_listed = current_source_line;
|
||||
printf ("%d\t", current_source_line++);
|
||||
do
|
||||
{
|
||||
if (c < 040 && c != '\t' && c != '\n')
|
||||
{
|
||||
fputc ('^', stdout);
|
||||
fputc (c + 0100, stdout);
|
||||
}
|
||||
else if (c == 0177)
|
||||
printf ("^?");
|
||||
else
|
||||
fputc (c, stdout);
|
||||
} while (c != '\n' && (c = fgetc (stream)) >= 0);
|
||||
}
|
||||
|
||||
fclose (stream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
C++
|
||||
Print a list of files and line numbers which a user may choose from
|
||||
in order to list a function which was specified ambiguously
|
||||
(as with `list classname::overloadedfuncname', for example).
|
||||
The vector in SALS provides the filenames and line numbers.
|
||||
*/
|
||||
static void
|
||||
ambiguous_line_spec (sals)
|
||||
struct symtabs_and_lines *sals;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sals->nelts; ++i)
|
||||
printf("file: \"%s\", line number: %d\n",
|
||||
sals->sals[i].symtab->filename, sals->sals[i].line);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
list_command (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
struct symtabs_and_lines sals, sals_end;
|
||||
struct symtab_and_line sal, sal_end;
|
||||
struct symbol *sym;
|
||||
char *arg1;
|
||||
int no_end = 1;
|
||||
int dummy_end = 0;
|
||||
int dummy_beg = 0;
|
||||
int linenum_beg = 0;
|
||||
char *p;
|
||||
|
||||
if (symtab_list == 0 && partial_symtab_list == 0)
|
||||
error ("Listing source lines requires symbols.");
|
||||
|
||||
/* Pull in a current source symtab if necessary */
|
||||
if (current_source_symtab == 0 &&
|
||||
(arg == 0 || arg[0] == '+' || arg[0] == '-'))
|
||||
select_source_symtab (symtab_list);
|
||||
|
||||
/* "l" or "l +" lists next ten lines. */
|
||||
|
||||
if (arg == 0 || !strcmp (arg, "+"))
|
||||
{
|
||||
if (current_source_symtab == 0)
|
||||
error ("No default source file yet. Do \"help list\".");
|
||||
print_source_lines (current_source_symtab, current_source_line,
|
||||
current_source_line + 10, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* "l -" lists previous ten lines, the ones before the ten just listed. */
|
||||
if (!strcmp (arg, "-"))
|
||||
{
|
||||
if (current_source_symtab == 0)
|
||||
error ("No default source file yet. Do \"help list\".");
|
||||
print_source_lines (current_source_symtab,
|
||||
max (first_line_listed - 10, 1),
|
||||
first_line_listed, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now if there is only one argument, decode it in SAL
|
||||
and set NO_END.
|
||||
If there are two arguments, decode them in SAL and SAL_END
|
||||
and clear NO_END; however, if one of the arguments is blank,
|
||||
set DUMMY_BEG or DUMMY_END to record that fact. */
|
||||
|
||||
arg1 = arg;
|
||||
if (*arg1 == ',')
|
||||
dummy_beg = 1;
|
||||
else
|
||||
{
|
||||
sals = decode_line_1 (&arg1, 0, 0, 0);
|
||||
|
||||
if (! sals.nelts) return; /* C++ */
|
||||
if (sals.nelts > 1)
|
||||
{
|
||||
ambiguous_line_spec (&sals);
|
||||
free (sals.sals);
|
||||
return;
|
||||
}
|
||||
|
||||
sal = sals.sals[0];
|
||||
free (sals.sals);
|
||||
}
|
||||
|
||||
/* Record whether the BEG arg is all digits. */
|
||||
|
||||
for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
|
||||
linenum_beg = (p == arg1);
|
||||
|
||||
while (*arg1 == ' ' || *arg1 == '\t')
|
||||
arg1++;
|
||||
if (*arg1 == ',')
|
||||
{
|
||||
no_end = 0;
|
||||
arg1++;
|
||||
while (*arg1 == ' ' || *arg1 == '\t')
|
||||
arg1++;
|
||||
if (*arg1 == 0)
|
||||
dummy_end = 1;
|
||||
else
|
||||
{
|
||||
if (dummy_beg)
|
||||
sals_end = decode_line_1 (&arg1, 0, 0, 0);
|
||||
else
|
||||
sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
|
||||
if (sals_end.nelts == 0)
|
||||
return;
|
||||
if (sals_end.nelts > 1)
|
||||
{
|
||||
ambiguous_line_spec (&sals_end);
|
||||
free (sals_end.sals);
|
||||
return;
|
||||
}
|
||||
sal_end = sals_end.sals[0];
|
||||
free (sals_end.sals);
|
||||
}
|
||||
}
|
||||
|
||||
if (*arg1)
|
||||
error ("Junk at end of line specification.");
|
||||
|
||||
if (!no_end && !dummy_beg && !dummy_end
|
||||
&& sal.symtab != sal_end.symtab)
|
||||
error ("Specified start and end are in different files.");
|
||||
if (dummy_beg && dummy_end)
|
||||
error ("Two empty args do not say what lines to list.");
|
||||
|
||||
/* if line was specified by address,
|
||||
first print exactly which line, and which file.
|
||||
In this case, sal.symtab == 0 means address is outside
|
||||
of all known source files, not that user failed to give a filename. */
|
||||
if (*arg == '*')
|
||||
{
|
||||
if (sal.symtab == 0)
|
||||
error ("No source file for address 0x%x.", sal.pc);
|
||||
sym = find_pc_function (sal.pc);
|
||||
if (sym)
|
||||
printf ("0x%x is in %s (%s, line %d).\n",
|
||||
sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
|
||||
else
|
||||
printf ("0x%x is in %s, line %d.\n",
|
||||
sal.pc, sal.symtab->filename, sal.line);
|
||||
}
|
||||
|
||||
/* If line was not specified by just a line number,
|
||||
and it does not imply a symtab, it must be an undebuggable symbol
|
||||
which means no source code. */
|
||||
|
||||
if (! linenum_beg && sal.symtab == 0)
|
||||
error ("No line number known for %s.", arg);
|
||||
|
||||
/* If this command is repeated with RET,
|
||||
turn it into the no-arg variant. */
|
||||
|
||||
if (from_tty)
|
||||
*arg = 0;
|
||||
|
||||
if (dummy_beg && sal_end.symtab == 0)
|
||||
error ("No default source file yet. Do \"help list\".");
|
||||
if (dummy_beg)
|
||||
print_source_lines (sal_end.symtab, max (sal_end.line - 9, 1),
|
||||
sal_end.line + 1, 0);
|
||||
else if (sal.symtab == 0)
|
||||
error ("No default source file yet. Do \"help list\".");
|
||||
else if (no_end)
|
||||
print_source_lines (sal.symtab, max (sal.line - 5, 1), sal.line + 5, 0);
|
||||
else
|
||||
print_source_lines (sal.symtab, sal.line,
|
||||
dummy_end ? sal.line + 10 : sal_end.line + 1,
|
||||
0);
|
||||
}
|
||||
|
||||
/* Print info on range of pc's in a specified line. */
|
||||
|
||||
static void
|
||||
line_info (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
struct symtabs_and_lines sals;
|
||||
struct symtab_and_line sal;
|
||||
int start_pc, end_pc;
|
||||
int i;
|
||||
|
||||
if (arg == 0)
|
||||
{
|
||||
sal.symtab = current_source_symtab;
|
||||
sal.line = last_line_listed;
|
||||
sals.nelts = 1;
|
||||
sals.sals = (struct symtab_and_line *)
|
||||
xmalloc (sizeof (struct symtab_and_line));
|
||||
sals.sals[0] = sal;
|
||||
}
|
||||
else
|
||||
{
|
||||
sals = decode_line_spec_1 (arg, 0);
|
||||
|
||||
/* If this command is repeated with RET,
|
||||
turn it into the no-arg variant. */
|
||||
if (from_tty)
|
||||
*arg = 0;
|
||||
}
|
||||
|
||||
/* C++ More than one line may have been specified, as when the user
|
||||
specifies an overloaded function name. Print info on them all. */
|
||||
for (i = 0; i < sals.nelts; i++)
|
||||
{
|
||||
sal = sals.sals[i];
|
||||
|
||||
if (sal.symtab == 0)
|
||||
error ("No source file specified.");
|
||||
|
||||
if (sal.line > 0
|
||||
&& find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
|
||||
{
|
||||
if (start_pc == end_pc)
|
||||
printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
|
||||
sal.line, sal.symtab->filename, start_pc);
|
||||
else
|
||||
printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
|
||||
sal.line, sal.symtab->filename, start_pc, end_pc);
|
||||
/* x/i should display this line's code. */
|
||||
set_next_address (start_pc);
|
||||
/* Repeating "info line" should do the following line. */
|
||||
last_line_listed = sal.line + 1;
|
||||
}
|
||||
else
|
||||
printf ("Line number %d is out of range for \"%s\".\n",
|
||||
sal.line, sal.symtab->filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Commands to search the source file for a regexp. */
|
||||
|
||||
static void
|
||||
forward_search_command (regex, from_tty)
|
||||
char *regex;
|
||||
{
|
||||
register int c;
|
||||
register int desc;
|
||||
register FILE *stream;
|
||||
int line = last_line_listed + 1;
|
||||
char *msg;
|
||||
|
||||
msg = (char *) re_comp (regex);
|
||||
if (msg)
|
||||
error (msg);
|
||||
|
||||
if (current_source_symtab == 0)
|
||||
error ("No default source file yet. Do \"help list\".");
|
||||
|
||||
/* Search from last_line_listed+1 in current_source_symtab */
|
||||
|
||||
desc = openp (source_path, 0, current_source_symtab->filename,
|
||||
O_RDONLY, 0, ¤t_source_symtab->fullname);
|
||||
if (desc < 0)
|
||||
perror_with_name (current_source_symtab->filename);
|
||||
|
||||
if (current_source_symtab->line_charpos == 0)
|
||||
find_source_lines (current_source_symtab, desc);
|
||||
|
||||
if (line < 1 || line > current_source_symtab->nlines)
|
||||
{
|
||||
close (desc);
|
||||
error ("Expression not found");
|
||||
}
|
||||
|
||||
if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
|
||||
{
|
||||
close (desc);
|
||||
perror_with_name (current_source_symtab->filename);
|
||||
}
|
||||
|
||||
stream = fdopen (desc, "r");
|
||||
clearerr (stream);
|
||||
while (1) {
|
||||
char buf[4096]; /* Should be reasonable??? */
|
||||
register char *p = buf;
|
||||
|
||||
c = fgetc (stream);
|
||||
if (c == EOF)
|
||||
break;
|
||||
do {
|
||||
*p++ = c;
|
||||
} while (c != '\n' && (c = fgetc (stream)) >= 0);
|
||||
|
||||
/* we now have a source line in buf, null terminate and match */
|
||||
*p = 0;
|
||||
if (re_exec (buf) > 0)
|
||||
{
|
||||
/* Match! */
|
||||
fclose (stream);
|
||||
print_source_lines (current_source_symtab,
|
||||
line, line+1, 0);
|
||||
current_source_line = max (line - 5, 1);
|
||||
return;
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
||||
printf ("Expression not found\n");
|
||||
fclose (stream);
|
||||
}
|
||||
|
||||
static void
|
||||
reverse_search_command (regex, from_tty)
|
||||
char *regex;
|
||||
{
|
||||
register int c;
|
||||
register int desc;
|
||||
register FILE *stream;
|
||||
int line = last_line_listed - 1;
|
||||
char *msg;
|
||||
|
||||
msg = (char *) re_comp (regex);
|
||||
if (msg)
|
||||
error (msg);
|
||||
|
||||
if (current_source_symtab == 0)
|
||||
error ("No default source file yet. Do \"help list\".");
|
||||
|
||||
/* Search from last_line_listed-1 in current_source_symtab */
|
||||
|
||||
desc = openp (source_path, 0, current_source_symtab->filename,
|
||||
O_RDONLY, 0, ¤t_source_symtab->fullname);
|
||||
if (desc < 0)
|
||||
perror_with_name (current_source_symtab->filename);
|
||||
|
||||
if (current_source_symtab->line_charpos == 0)
|
||||
find_source_lines (current_source_symtab, desc);
|
||||
|
||||
if (line < 1 || line > current_source_symtab->nlines)
|
||||
{
|
||||
close (desc);
|
||||
error ("Expression not found");
|
||||
}
|
||||
|
||||
if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
|
||||
{
|
||||
close (desc);
|
||||
perror_with_name (current_source_symtab->filename);
|
||||
}
|
||||
|
||||
stream = fdopen (desc, "r");
|
||||
clearerr (stream);
|
||||
while (1)
|
||||
{
|
||||
char buf[4096]; /* Should be reasonable??? */
|
||||
register char *p = buf;
|
||||
|
||||
c = fgetc (stream);
|
||||
if (c == EOF)
|
||||
break;
|
||||
do {
|
||||
*p++ = c;
|
||||
} while (c != '\n' && (c = fgetc (stream)) >= 0);
|
||||
|
||||
/* We now have a source line in buf; null terminate and match. */
|
||||
*p = 0;
|
||||
if (re_exec (buf) > 0)
|
||||
{
|
||||
/* Match! */
|
||||
fclose (stream);
|
||||
print_source_lines (current_source_symtab,
|
||||
line, line+1, 0);
|
||||
current_source_line = max (line - 5, 1);
|
||||
return;
|
||||
}
|
||||
line--;
|
||||
if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
|
||||
{
|
||||
fclose (stream);
|
||||
perror_with_name (current_source_symtab->filename);
|
||||
}
|
||||
}
|
||||
|
||||
printf ("Expression not found\n");
|
||||
fclose (stream);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_source ()
|
||||
{
|
||||
current_source_symtab = 0;
|
||||
init_source_path ();
|
||||
|
||||
add_com ("directory", class_files, directory_command,
|
||||
"Add directory DIR to end of search path for source files.\n\
|
||||
With no argument, reset the search path to just the working directory\n\
|
||||
and forget cached info on line positions in source files.");
|
||||
|
||||
add_info ("directories", directories_info,
|
||||
"Current search path for finding source files.");
|
||||
|
||||
add_info ("line", line_info,
|
||||
"Core addresses of the code for a source line.\n\
|
||||
Line can be specified as\n\
|
||||
LINENUM, to list around that line in current file,\n\
|
||||
FILE:LINENUM, to list around that line in that file,\n\
|
||||
FUNCTION, to list around beginning of that function,\n\
|
||||
FILE:FUNCTION, to distinguish among like-named static functions.\n\
|
||||
Default is to describe the last source line that was listed.\n\n\
|
||||
This sets the default address for \"x\" to the line's first instruction\n\
|
||||
so that \"x/i\" suffices to start examining the machine code.\n\
|
||||
The address is also stored as the value of \"$_\".");
|
||||
|
||||
add_com ("forward-search", class_files, forward_search_command,
|
||||
"Search for regular expression (see regex(3)) from last line listed.");
|
||||
add_com_alias ("search", "forward-search", class_files, 0);
|
||||
|
||||
add_com ("reverse-search", class_files, reverse_search_command,
|
||||
"Search backward for regular expression (see regex(3)) from last line listed.");
|
||||
|
||||
add_com ("list", class_files, list_command,
|
||||
"List specified function or line.\n\
|
||||
With no argument, lists ten more lines after or around previous listing.\n\
|
||||
\"list -\" lists the ten lines before a previous ten-line listing.\n\
|
||||
One argument specifies a line, and ten lines are listed around that line.\n\
|
||||
Two arguments with comma between specify starting and ending lines to list.\n\
|
||||
Lines can be specified in these ways:\n\
|
||||
LINENUM, to list around that line in current file,\n\
|
||||
FILE:LINENUM, to list around that line in that file,\n\
|
||||
FUNCTION, to list around beginning of that function,\n\
|
||||
FILE:FUNCTION, to distinguish among like-named static functions.\n\
|
||||
*ADDRESS, to list around the line containing that address.\n\
|
||||
With two args if one is empty it stands for ten lines away from the other arg.");
|
||||
}
|
||||
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d27 1
|
||||
a27 1
|
||||
#include <sys/fcntl.h>
|
||||
@
|
1091
gdb/RCS/sparc-dep.c,v
Normal file
1091
gdb/RCS/sparc-dep.c,v
Normal file
File diff suppressed because it is too large
Load Diff
882
gdb/RCS/stack.c,v
Normal file
882
gdb/RCS/stack.c,v
Normal file
@ -0,0 +1,882 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.02.09.23.53.05; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.02.09.15.03.51; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Avoid coredumps if stack commands are used when there is no stack.
|
||||
@
|
||||
text
|
||||
@/* Print and select stack frames for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
|
||||
/* Thie "selected" stack frame is used by default for local and arg access.
|
||||
May be zero, for no selected frame. */
|
||||
|
||||
FRAME selected_frame;
|
||||
|
||||
/* Level of the selected frame:
|
||||
0 for innermost, 1 for its caller, ...
|
||||
or -1 for frame specified by address with no defined level. */
|
||||
|
||||
int selected_frame_level;
|
||||
|
||||
/* Error message when selected_frame is zero when it's needed */
|
||||
char no_sel_frame[] = "There is no current stack frame.";
|
||||
|
||||
/* Nonzero means print the full filename and linenumber
|
||||
when a frame is printed, and do so in a format programs can parse. */
|
||||
|
||||
int frame_file_full_name = 0;
|
||||
|
||||
static void select_calling_frame ();
|
||||
|
||||
void print_frame_info ();
|
||||
|
||||
/* Print a stack frame briefly. FRAME should be the frame address
|
||||
and LEVEL should be its level in the stack (or -1 for level not defined).
|
||||
This prints the level, the function executing, the arguments,
|
||||
and the file name and line number.
|
||||
If the pc is not at the beginning of the source line,
|
||||
the actual pc is printed at the beginning.
|
||||
|
||||
If SOURCE is 1, print the source line as well.
|
||||
If SOURCE is -1, print ONLY the source line. */
|
||||
|
||||
/* FIXME, the argument "frame" is always "selected_frame". This is why
|
||||
we can say "No selected frame" if it == 0. Probably shouldn't be an
|
||||
argument anymore... */
|
||||
|
||||
static void
|
||||
print_stack_frame (frame, level, source)
|
||||
FRAME frame;
|
||||
int level;
|
||||
int source;
|
||||
{
|
||||
struct frame_info *fi;
|
||||
|
||||
if (frame == 0)
|
||||
error (no_sel_frame);
|
||||
fi = get_frame_info (frame);
|
||||
|
||||
print_frame_info (fi, level, source, 1);
|
||||
}
|
||||
|
||||
void
|
||||
print_frame_info (fi, level, source, args)
|
||||
struct frame_info *fi;
|
||||
register int level;
|
||||
int source;
|
||||
int args;
|
||||
{
|
||||
struct symtab_and_line sal;
|
||||
struct symbol *func;
|
||||
register char *funname = 0;
|
||||
int numargs;
|
||||
|
||||
sal = find_pc_line (fi->pc, fi->next_frame);
|
||||
func = find_pc_function (fi->pc);
|
||||
if (func)
|
||||
funname = SYMBOL_NAME (func);
|
||||
else
|
||||
{
|
||||
register int misc_index = find_pc_misc_function (fi->pc);
|
||||
if (misc_index >= 0)
|
||||
funname = misc_function_vector[misc_index].name;
|
||||
}
|
||||
|
||||
if (source >= 0 || !sal.symtab)
|
||||
{
|
||||
if (level >= 0)
|
||||
printf ("#%-2d ", level);
|
||||
if (fi->pc != sal.pc || !sal.symtab)
|
||||
printf ("0x%x in ", fi->pc);
|
||||
printf ("%s (", funname ? funname : "??");
|
||||
if (args)
|
||||
{
|
||||
FRAME_NUM_ARGS (numargs, fi);
|
||||
print_frame_args (func, fi, numargs, stdout);
|
||||
}
|
||||
printf (")");
|
||||
if (sal.symtab)
|
||||
printf (" (%s line %d)", sal.symtab->filename, sal.line);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
if (source != 0 && sal.symtab)
|
||||
{
|
||||
int done = 0;
|
||||
int mid_statement = source < 0 && fi->pc != sal.pc;
|
||||
if (frame_file_full_name)
|
||||
done = identify_source_line (sal.symtab, sal.line, mid_statement);
|
||||
if (!done)
|
||||
{
|
||||
if (mid_statement)
|
||||
printf ("0x%x\t", fi->pc);
|
||||
print_source_lines (sal.symtab, sal.line, sal.line + 1, 1);
|
||||
}
|
||||
current_source_line = max (sal.line - 5, 1);
|
||||
}
|
||||
if (source != 0)
|
||||
set_default_breakpoint (1, fi->pc, sal.symtab, sal.line);
|
||||
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
/* Call here to print info on selected frame, after a trap. */
|
||||
|
||||
void
|
||||
print_sel_frame (just_source)
|
||||
int just_source;
|
||||
{
|
||||
print_stack_frame (selected_frame, -1, just_source ? -1 : 1);
|
||||
}
|
||||
|
||||
/* Print info on the selected frame, including level number
|
||||
but not source. */
|
||||
|
||||
void
|
||||
print_selected_frame ()
|
||||
{
|
||||
print_stack_frame (selected_frame, selected_frame_level, 0);
|
||||
}
|
||||
|
||||
void flush_cached_frames (); /* FIXME, never called! */
|
||||
|
||||
#ifdef FRAME_SPECIFICATION_DYADIC
|
||||
extern FRAME setup_arbitrary_frame ();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read a frame specification in whatever the appropriate format is.
|
||||
*/
|
||||
static FRAME
|
||||
parse_frame_specification (frame_exp)
|
||||
char *frame_exp;
|
||||
{
|
||||
int numargs = 0;
|
||||
int arg1, arg2;
|
||||
|
||||
if (frame_exp)
|
||||
{
|
||||
char *addr_string, *p;
|
||||
struct cleanup *tmp_cleanup;
|
||||
struct frame_info *fci;
|
||||
|
||||
while (*frame_exp == ' ') frame_exp++;
|
||||
for (p = frame_exp; *p && *p != ' '; p++)
|
||||
;
|
||||
|
||||
if (*frame_exp)
|
||||
{
|
||||
numargs = 1;
|
||||
addr_string = savestring(frame_exp, p - frame_exp);
|
||||
|
||||
{
|
||||
tmp_cleanup = make_cleanup (free, addr_string);
|
||||
arg1 = parse_and_eval_address (addr_string);
|
||||
do_cleanups (tmp_cleanup);
|
||||
}
|
||||
|
||||
while (*p == ' ') p++;
|
||||
|
||||
if (*p)
|
||||
{
|
||||
numargs = 2;
|
||||
arg2 = parse_and_eval_address (p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (numargs)
|
||||
{
|
||||
case 0:
|
||||
if (selected_frame == 0)
|
||||
error (no_sel_frame);
|
||||
return selected_frame;
|
||||
/* NOTREACHED */
|
||||
case 1:
|
||||
{
|
||||
int level = arg1;
|
||||
FRAME fid = find_relative_frame (get_current_frame (), &level);
|
||||
FRAME tfid;
|
||||
|
||||
if (level == 0)
|
||||
/* find_relative_frame was successful */
|
||||
return fid;
|
||||
|
||||
/* If (s)he specifies the frame with an address, he deserves what
|
||||
(s)he gets. Still, give the highest one that matches. */
|
||||
|
||||
for (fid = get_current_frame ();
|
||||
fid && FRAME_FP (fid) != arg1;
|
||||
fid = get_prev_frame (fid))
|
||||
;
|
||||
|
||||
if (fid)
|
||||
while ((tfid = get_prev_frame (fid)) &&
|
||||
(FRAME_FP (tfid) == arg1))
|
||||
fid = tfid;
|
||||
|
||||
#ifdef FRAME_SPECIFICATION_DYADIC
|
||||
if (!fid)
|
||||
error ("Incorrect number of args in frame specification");
|
||||
|
||||
return fid;
|
||||
#else
|
||||
return create_new_frame (arg1, 0);
|
||||
#endif
|
||||
}
|
||||
/* NOTREACHED */
|
||||
case 2:
|
||||
/* Must be addresses */
|
||||
#ifndef FRAME_SPECIFICATION_DYADIC
|
||||
error ("Incorrect number of args in frame specification");
|
||||
#else
|
||||
return setup_arbitrary_frame (arg1, arg2);
|
||||
#endif
|
||||
/* NOTREACHED */
|
||||
}
|
||||
fatal ("Internal: Error in parsing in parse_frame_specification");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* Print verbosely the selected frame or the frame at address ADDR.
|
||||
This means absolutely all information in the frame is printed. */
|
||||
|
||||
static void
|
||||
frame_info (addr_exp)
|
||||
char *addr_exp;
|
||||
{
|
||||
FRAME frame;
|
||||
struct frame_info *fi;
|
||||
struct frame_saved_regs fsr;
|
||||
struct symtab_and_line sal;
|
||||
struct symbol *func;
|
||||
FRAME calling_frame;
|
||||
int i, count;
|
||||
char *funname = 0;
|
||||
int numargs;
|
||||
|
||||
frame = parse_frame_specification (addr_exp);
|
||||
|
||||
fi = get_frame_info (frame);
|
||||
get_frame_saved_regs (fi, &fsr);
|
||||
sal = find_pc_line (fi->pc, fi->next_frame);
|
||||
func = get_frame_function (frame);
|
||||
if (func)
|
||||
funname = SYMBOL_NAME (func);
|
||||
else
|
||||
{
|
||||
register int misc_index = find_pc_misc_function (fi->pc);
|
||||
if (misc_index >= 0)
|
||||
funname = misc_function_vector[misc_index].name;
|
||||
}
|
||||
calling_frame = get_prev_frame (frame);
|
||||
|
||||
if (!addr_exp && selected_frame_level >= 0)
|
||||
printf ("Stack level %d, frame at 0x%x:\n pc = 0x%x",
|
||||
selected_frame_level, FRAME_FP(frame), fi->pc);
|
||||
else
|
||||
printf ("Stack frame at 0x%x:\n pc = 0x%x",
|
||||
FRAME_FP(frame), fi->pc);
|
||||
|
||||
if (funname)
|
||||
printf (" in %s", funname);
|
||||
if (sal.symtab)
|
||||
printf (" (%s line %d)", sal.symtab->filename, sal.line);
|
||||
printf ("; saved pc 0x%x\n", FRAME_SAVED_PC (frame));
|
||||
if (calling_frame)
|
||||
printf (" called by frame at 0x%x", FRAME_FP (calling_frame));
|
||||
if (fi->next_frame && calling_frame)
|
||||
printf (",");
|
||||
if (fi->next_frame)
|
||||
printf (" caller of frame at 0x%x", fi->next_frame);
|
||||
if (fi->next_frame || calling_frame)
|
||||
printf ("\n");
|
||||
printf (" Arglist at 0x%x,", FRAME_ARGS_ADDRESS (fi));
|
||||
FRAME_NUM_ARGS (i, fi);
|
||||
if (i < 0)
|
||||
printf (" args: ");
|
||||
else if (i == 0)
|
||||
printf (" no args.");
|
||||
else if (i == 1)
|
||||
printf (" 1 arg: ");
|
||||
else
|
||||
printf (" %d args: ", i);
|
||||
|
||||
FRAME_NUM_ARGS (numargs, fi);
|
||||
print_frame_args (func, fi, numargs, stdout);
|
||||
printf ("\n");
|
||||
count = 0;
|
||||
for (i = 0; i < NUM_REGS; i++)
|
||||
if (fsr.regs[i])
|
||||
{
|
||||
if (count % 4 != 0)
|
||||
printf (", ");
|
||||
else
|
||||
{
|
||||
if (count == 0)
|
||||
printf (" Saved registers:");
|
||||
printf ("\n ");
|
||||
}
|
||||
printf ("%s at 0x%x", reg_names[i], fsr.regs[i]);
|
||||
count++;
|
||||
}
|
||||
if (count)
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Set a limit on the number of frames printed by default in a
|
||||
backtrace. */
|
||||
|
||||
static int backtrace_limit;
|
||||
|
||||
static void
|
||||
set_backtrace_limit_command (count_exp, from_tty)
|
||||
char *count_exp;
|
||||
int from_tty;
|
||||
{
|
||||
int count = parse_and_eval_address (count_exp);
|
||||
|
||||
if (count < 0)
|
||||
error ("Negative argument not meaningful as backtrace limit.");
|
||||
|
||||
backtrace_limit = count;
|
||||
}
|
||||
|
||||
static void
|
||||
backtrace_limit_info (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
if (arg)
|
||||
error ("\"Info backtrace-limit\" takes no arguments.");
|
||||
|
||||
printf ("Backtrace limit: %d.\n", backtrace_limit);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print briefly all stack frames or just the innermost COUNT frames. */
|
||||
|
||||
static void
|
||||
backtrace_command (count_exp)
|
||||
char *count_exp;
|
||||
{
|
||||
struct frame_info *fi;
|
||||
register int count;
|
||||
register FRAME frame;
|
||||
register int i;
|
||||
register FRAME trailing;
|
||||
register int trailing_level;
|
||||
|
||||
if (have_inferior_p () == 0 && corefile == 0)
|
||||
error ("There is no running program or core file.");
|
||||
|
||||
/* The following code must do two things. First, it must
|
||||
set the variable TRAILING to the frame from which we should start
|
||||
printing. Second, it must set the variable count to the number
|
||||
of frames which we should print, or -1 if all of them. */
|
||||
trailing = get_current_frame ();
|
||||
trailing_level = 0;
|
||||
if (count_exp)
|
||||
{
|
||||
count = parse_and_eval_address (count_exp);
|
||||
if (count < 0)
|
||||
{
|
||||
FRAME current;
|
||||
|
||||
count = -count;
|
||||
|
||||
current = trailing;
|
||||
while (current && count--)
|
||||
current = get_prev_frame (current);
|
||||
|
||||
/* Will stop when CURRENT reaches the top of the stack. TRAILING
|
||||
will be COUNT below it. */
|
||||
while (current)
|
||||
{
|
||||
trailing = get_prev_frame (trailing);
|
||||
current = get_prev_frame (current);
|
||||
trailing_level++;
|
||||
}
|
||||
|
||||
count = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
#if 0
|
||||
count = backtrace_limit;
|
||||
#else
|
||||
count = -1;
|
||||
#endif
|
||||
|
||||
for (i = 0, frame = trailing;
|
||||
frame && count--;
|
||||
i++, frame = get_prev_frame (frame))
|
||||
{
|
||||
QUIT;
|
||||
fi = get_frame_info (frame);
|
||||
print_frame_info (fi, trailing_level + i, 0, 1);
|
||||
}
|
||||
|
||||
/* If we've stopped before the end, mention that. */
|
||||
if (frame)
|
||||
printf ("(More stack frames follow...)\n");
|
||||
}
|
||||
|
||||
/* Print the local variables of a block B active in FRAME. */
|
||||
|
||||
static void
|
||||
print_block_frame_locals (b, frame, stream)
|
||||
struct block *b;
|
||||
register FRAME frame;
|
||||
register FILE *stream;
|
||||
{
|
||||
int nsyms;
|
||||
register int i;
|
||||
register struct symbol *sym;
|
||||
|
||||
nsyms = BLOCK_NSYMS (b);
|
||||
|
||||
for (i = 0; i < nsyms; i++)
|
||||
{
|
||||
sym = BLOCK_SYM (b, i);
|
||||
if (SYMBOL_CLASS (sym) == LOC_LOCAL
|
||||
|| SYMBOL_CLASS (sym) == LOC_REGISTER
|
||||
|| SYMBOL_CLASS (sym) == LOC_STATIC)
|
||||
{
|
||||
fprintf (stream, "%s = ", SYMBOL_NAME (sym));
|
||||
print_variable_value (sym, frame, stream);
|
||||
fprintf (stream, "\n");
|
||||
fflush (stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print on STREAM all the local variables in frame FRAME,
|
||||
including all the blocks active in that frame
|
||||
at its current pc.
|
||||
|
||||
Returns 1 if the job was done,
|
||||
or 0 if nothing was printed because we have no info
|
||||
on the function running in FRAME. */
|
||||
|
||||
static int
|
||||
print_frame_local_vars (frame, stream)
|
||||
register FRAME frame;
|
||||
register FILE *stream;
|
||||
{
|
||||
register struct block *block;
|
||||
|
||||
block = get_frame_block (frame);
|
||||
if (block == 0)
|
||||
return 0;
|
||||
while (block != 0)
|
||||
{
|
||||
print_block_frame_locals (block, frame, stream);
|
||||
/* After handling the function's top-level block, stop.
|
||||
Don't continue to its superblock, the block of
|
||||
per-file symbols. */
|
||||
if (BLOCK_FUNCTION (block))
|
||||
break;
|
||||
block = BLOCK_SUPERBLOCK (block);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
locals_info ()
|
||||
{
|
||||
if (selected_frame == 0)
|
||||
error(no_sel_frame);
|
||||
print_frame_local_vars (selected_frame, stdout);
|
||||
}
|
||||
|
||||
static int
|
||||
print_frame_arg_vars (frame, stream)
|
||||
register FRAME frame;
|
||||
register FILE *stream;
|
||||
{
|
||||
struct symbol *func;
|
||||
register struct block *b;
|
||||
int nsyms;
|
||||
register int i;
|
||||
register struct symbol *sym;
|
||||
|
||||
func = get_frame_function (frame);
|
||||
if (func == 0)
|
||||
return 0;
|
||||
|
||||
b = SYMBOL_BLOCK_VALUE (func);
|
||||
nsyms = BLOCK_NSYMS (b);
|
||||
|
||||
for (i = 0; i < nsyms; i++)
|
||||
{
|
||||
sym = BLOCK_SYM (b, i);
|
||||
if (SYMBOL_CLASS (sym) == LOC_ARG || SYMBOL_CLASS (sym) == LOC_REGPARM)
|
||||
{
|
||||
fprintf (stream, "%s = ", SYMBOL_NAME (sym));
|
||||
print_variable_value (sym, frame, stream);
|
||||
fprintf (stream, "\n");
|
||||
fflush (stream);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
args_info ()
|
||||
{
|
||||
if (selected_frame == 0)
|
||||
error(no_sel_frame);
|
||||
print_frame_arg_vars (selected_frame, stdout);
|
||||
}
|
||||
|
||||
/* Select frame FRAME, and note that its stack level is LEVEL.
|
||||
LEVEL may be -1 if an actual level number is not known. */
|
||||
|
||||
void
|
||||
select_frame (frame, level)
|
||||
FRAME frame;
|
||||
int level;
|
||||
{
|
||||
selected_frame = frame;
|
||||
selected_frame_level = level;
|
||||
}
|
||||
|
||||
/* Store the selected frame and its level into *FRAMEP and *LEVELP. */
|
||||
|
||||
void
|
||||
record_selected_frame (frameaddrp, levelp)
|
||||
FRAME_ADDR *frameaddrp;
|
||||
int *levelp;
|
||||
{
|
||||
*frameaddrp = FRAME_FP (selected_frame);
|
||||
*levelp = selected_frame_level;
|
||||
}
|
||||
|
||||
/* Return the symbol-block in which the selected frame is executing.
|
||||
Can return zero under various legitimate circumstances. */
|
||||
|
||||
struct block *
|
||||
get_selected_block ()
|
||||
{
|
||||
if (!have_inferior_p () && !have_core_file_p ())
|
||||
return 0;
|
||||
|
||||
if (!selected_frame)
|
||||
return get_current_block ();
|
||||
return get_frame_block (selected_frame);
|
||||
}
|
||||
|
||||
/* Find a frame a certain number of levels away from FRAME.
|
||||
LEVEL_OFFSET_PTR points to an int containing the number of levels.
|
||||
Positive means go to earlier frames (up); negative, the reverse.
|
||||
The int that contains the number of levels is counted toward
|
||||
zero as the frames for those levels are found.
|
||||
If the top or bottom frame is reached, that frame is returned,
|
||||
but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates
|
||||
how much farther the original request asked to go. */
|
||||
|
||||
FRAME
|
||||
find_relative_frame (frame, level_offset_ptr)
|
||||
register FRAME frame;
|
||||
register int* level_offset_ptr;
|
||||
{
|
||||
register FRAME prev;
|
||||
register FRAME frame1, frame2;
|
||||
|
||||
if (frame == 0)
|
||||
error (no_sel_frame);
|
||||
/* Going up is simple: just do get_prev_frame enough times
|
||||
or until initial frame is reached. */
|
||||
while (*level_offset_ptr > 0)
|
||||
{
|
||||
prev = get_prev_frame (frame);
|
||||
if (prev == 0)
|
||||
break;
|
||||
(*level_offset_ptr)--;
|
||||
frame = prev;
|
||||
}
|
||||
/* Going down could be done by iterating get_frame_info to
|
||||
find the next frame, but that would be quadratic
|
||||
since get_frame_info must scan all the way from the current frame.
|
||||
The following algorithm is linear. */
|
||||
if (*level_offset_ptr < 0)
|
||||
{
|
||||
/* First put frame1 at innermost frame
|
||||
and frame2 N levels up from there. */
|
||||
frame1 = get_current_frame ();
|
||||
frame2 = frame1;
|
||||
while (*level_offset_ptr < 0 && frame2 != frame)
|
||||
{
|
||||
frame2 = get_prev_frame (frame2);
|
||||
(*level_offset_ptr) ++;
|
||||
}
|
||||
/* Then slide frame1 and frame2 up in synchrony
|
||||
and when frame2 reaches our starting point
|
||||
frame1 must be N levels down from there. */
|
||||
while (frame2 != frame)
|
||||
{
|
||||
frame1 = get_prev_frame (frame1);
|
||||
frame2 = get_prev_frame (frame2);
|
||||
}
|
||||
return frame1;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
/* The "frame" command. With no arg, print selected frame briefly.
|
||||
With arg LEVEL_EXP, select the frame at level LEVEL if it is a
|
||||
valid level. Otherwise, treat level_exp as an address expression
|
||||
and print it. See parse_frame_specification for more info on proper
|
||||
frame expressions. */
|
||||
|
||||
static void
|
||||
frame_command (level_exp, from_tty)
|
||||
char *level_exp;
|
||||
int from_tty;
|
||||
{
|
||||
register FRAME frame, frame1;
|
||||
unsigned int level = 0;
|
||||
|
||||
frame = parse_frame_specification (level_exp);
|
||||
|
||||
for (frame1 = get_prev_frame (0);
|
||||
frame1 && frame1 != frame;
|
||||
frame1 = get_prev_frame (frame1))
|
||||
level++;
|
||||
|
||||
if (!frame1)
|
||||
level = 0;
|
||||
|
||||
select_frame (frame, level);
|
||||
|
||||
if (!from_tty)
|
||||
return;
|
||||
|
||||
print_stack_frame (selected_frame, selected_frame_level, 1);
|
||||
}
|
||||
|
||||
/* Select the frame up one or COUNT stack levels
|
||||
from the previously selected frame, and print it briefly. */
|
||||
|
||||
static void
|
||||
up_command (count_exp)
|
||||
char *count_exp;
|
||||
{
|
||||
register FRAME frame;
|
||||
int count = 1, count1;
|
||||
if (count_exp)
|
||||
count = parse_and_eval_address (count_exp);
|
||||
count1 = count;
|
||||
|
||||
frame = find_relative_frame (selected_frame, &count1);
|
||||
if (count1 != 0 && count_exp == 0)
|
||||
error ("Initial frame selected; you cannot go up.");
|
||||
select_frame (frame, selected_frame_level + count - count1);
|
||||
|
||||
print_stack_frame (selected_frame, selected_frame_level, 1);
|
||||
}
|
||||
|
||||
/* Select the frame down one or COUNT stack levels
|
||||
from the previously selected frame, and print it briefly. */
|
||||
|
||||
static void
|
||||
down_command (count_exp)
|
||||
char *count_exp;
|
||||
{
|
||||
register FRAME frame;
|
||||
int count = -1, count1;
|
||||
if (count_exp)
|
||||
count = - parse_and_eval_address (count_exp);
|
||||
count1 = count;
|
||||
|
||||
frame = find_relative_frame (selected_frame, &count1);
|
||||
if (count1 != 0 && count_exp == 0)
|
||||
error ("Bottom (i.e., innermost) frame selected; you cannot go down.");
|
||||
select_frame (frame, selected_frame_level + count - count1);
|
||||
|
||||
print_stack_frame (selected_frame, selected_frame_level, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
return_command (retval_exp, from_tty)
|
||||
char *retval_exp;
|
||||
int from_tty;
|
||||
{
|
||||
struct symbol *thisfun = get_frame_function (selected_frame);
|
||||
|
||||
/* If interactive, require confirmation. */
|
||||
|
||||
if (from_tty)
|
||||
{
|
||||
if (thisfun != 0)
|
||||
{
|
||||
if (!query ("Make %s return now? ", SYMBOL_NAME (thisfun)))
|
||||
error ("Not confirmed.");
|
||||
}
|
||||
else
|
||||
if (!query ("Make selected stack frame return now? "))
|
||||
error ("Not confirmed.");
|
||||
}
|
||||
|
||||
/* Do the real work. Pop until the specified frame is current. */
|
||||
|
||||
while (selected_frame != get_current_frame ())
|
||||
POP_FRAME;
|
||||
|
||||
/* Then pop that frame. */
|
||||
|
||||
POP_FRAME;
|
||||
|
||||
/* Compute the return value (if any) and store in the place
|
||||
for return values. */
|
||||
|
||||
if (retval_exp)
|
||||
set_return_value (parse_and_eval (retval_exp));
|
||||
|
||||
/* If interactive, print the frame that is now current. */
|
||||
|
||||
if (from_tty)
|
||||
frame_command ("0", 1);
|
||||
}
|
||||
|
||||
extern struct cmd_list_element *setlist;
|
||||
|
||||
void
|
||||
_initialize_stack ()
|
||||
{
|
||||
#if 0
|
||||
backtrace_limit = 30;
|
||||
#endif
|
||||
|
||||
add_com ("return", class_stack, return_command,
|
||||
"Make selected stack frame return to its caller.\n\
|
||||
Control remains in the debugger, but when you continue\n\
|
||||
execution will resume in the frame above the one now selected.\n\
|
||||
If an argument is given, it is an expression for the value to return.");
|
||||
|
||||
add_com ("up", class_stack, up_command,
|
||||
"Select and print stack frame that called this one.\n\
|
||||
An argument says how many frames up to go.");
|
||||
|
||||
add_com ("down", class_stack, down_command,
|
||||
"Select and print stack frame called by this one.\n\
|
||||
An argument says how many frames down to go.");
|
||||
add_com_alias ("do", "down", class_stack, 1);
|
||||
|
||||
add_com ("frame", class_stack, frame_command,
|
||||
"Select and print a stack frame.\n\
|
||||
With no argument, print the selected stack frame. (See also \"info frame\").\n\
|
||||
An argument specifies the frame to select.\n\
|
||||
It can be a stack frame number or the address of the frame.\n\
|
||||
With argument, nothing is printed if input is coming from\n\
|
||||
a command file or a user-defined command.");
|
||||
|
||||
add_com_alias ("f", "frame", class_stack, 1);
|
||||
|
||||
add_com ("backtrace", class_stack, backtrace_command,
|
||||
"Print backtrace of all stack frames, or innermost COUNT frames.\n\
|
||||
With a negative argument, print outermost -COUNT frames.");
|
||||
add_com_alias ("bt", "backtrace", class_stack, 0);
|
||||
add_com_alias ("where", "backtrace", class_alias, 0);
|
||||
add_info ("stack", backtrace_command,
|
||||
"Backtrace of the stack, or innermost COUNT frames.");
|
||||
add_info_alias ("s", "stack", 1);
|
||||
add_info ("frame", frame_info,
|
||||
"All about selected stack frame, or frame at ADDR.");
|
||||
add_info_alias ("f", "frame", 1);
|
||||
add_info ("locals", locals_info,
|
||||
"Local variables of current stack frame.");
|
||||
add_info ("args", args_info,
|
||||
"Argument variables of current stack frame.");
|
||||
|
||||
#if 0
|
||||
add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command,
|
||||
"Specify maximum number of frames for \"backtrace\" to print by default.",
|
||||
&setlist);
|
||||
add_info ("backtrace-limit", backtrace_limit_info,
|
||||
"The maximum number of frames for \"backtrace\" to print by default.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d2 1
|
||||
a2 1
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
d27 2
|
||||
d42 3
|
||||
d64 4
|
||||
d76 2
|
||||
d162 1
|
||||
a162 1
|
||||
void flush_cached_frames ();
|
||||
d212 2
|
||||
d392 3
|
||||
d489 3
|
||||
a491 1
|
||||
register struct block *block = get_frame_block (frame);
|
||||
d510 2
|
||||
d520 1
|
||||
a520 1
|
||||
struct symbol *func = get_frame_function (frame);
|
||||
d526 1
|
||||
d551 2
|
||||
d610 2
|
||||
@
|
726
gdb/RCS/utils.c,v
Normal file
726
gdb/RCS/utils.c,v
Normal file
@ -0,0 +1,726 @@
|
||||
head 1.2;
|
||||
access ;
|
||||
symbols ;
|
||||
locks ; strict;
|
||||
comment @ * @;
|
||||
|
||||
|
||||
1.2
|
||||
date 89.03.27.20.22.34; author gnu; state Exp;
|
||||
branches ;
|
||||
next 1.1;
|
||||
|
||||
1.1
|
||||
date 89.03.23.14.27.48; author gnu; state Exp;
|
||||
branches ;
|
||||
next ;
|
||||
|
||||
|
||||
desc
|
||||
@@
|
||||
|
||||
|
||||
1.2
|
||||
log
|
||||
@Portability changes. If USG, we need to re-enable the SIGINT
|
||||
signal handler when it is called. Also, build the sys_siglist
|
||||
table at runtime, based on the actual values of the signal
|
||||
#define's. Too many USG systems added Berkeley signal names
|
||||
as various numbers.
|
||||
@
|
||||
text
|
||||
@/* General utility routines for GDB, the GNU debugger.
|
||||
Copyright (C) 1986 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#ifdef HAVE_TERMIO
|
||||
#include <termio.h>
|
||||
#endif
|
||||
|
||||
void error ();
|
||||
void fatal ();
|
||||
|
||||
/* Chain of cleanup actions established with make_cleanup,
|
||||
to be executed if an error happens. */
|
||||
|
||||
static struct cleanup *cleanup_chain;
|
||||
|
||||
/* Nonzero means a quit has been requested. */
|
||||
|
||||
int quit_flag;
|
||||
|
||||
/* Nonzero means quit immediately if Control-C is typed now,
|
||||
rather than waiting until QUIT is executed. */
|
||||
|
||||
int immediate_quit;
|
||||
|
||||
/* Add a new cleanup to the cleanup_chain,
|
||||
and return the previous chain pointer
|
||||
to be passed later to do_cleanups or discard_cleanups.
|
||||
Args are FUNCTION to clean up with, and ARG to pass to it. */
|
||||
|
||||
struct cleanup *
|
||||
make_cleanup (function, arg)
|
||||
void (*function) ();
|
||||
int arg;
|
||||
{
|
||||
register struct cleanup *new
|
||||
= (struct cleanup *) xmalloc (sizeof (struct cleanup));
|
||||
register struct cleanup *old_chain = cleanup_chain;
|
||||
|
||||
new->next = cleanup_chain;
|
||||
new->function = function;
|
||||
new->arg = arg;
|
||||
cleanup_chain = new;
|
||||
|
||||
return old_chain;
|
||||
}
|
||||
|
||||
/* Discard cleanups and do the actions they describe
|
||||
until we get back to the point OLD_CHAIN in the cleanup_chain. */
|
||||
|
||||
void
|
||||
do_cleanups (old_chain)
|
||||
register struct cleanup *old_chain;
|
||||
{
|
||||
register struct cleanup *ptr;
|
||||
while ((ptr = cleanup_chain) != old_chain)
|
||||
{
|
||||
(*ptr->function) (ptr->arg);
|
||||
cleanup_chain = ptr->next;
|
||||
free (ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Discard cleanups, not doing the actions they describe,
|
||||
until we get back to the point OLD_CHAIN in the cleanup_chain. */
|
||||
|
||||
void
|
||||
discard_cleanups (old_chain)
|
||||
register struct cleanup *old_chain;
|
||||
{
|
||||
register struct cleanup *ptr;
|
||||
while ((ptr = cleanup_chain) != old_chain)
|
||||
{
|
||||
cleanup_chain = ptr->next;
|
||||
free (ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the cleanup_chain to 0, and return the old cleanup chain. */
|
||||
struct cleanup *
|
||||
save_cleanups ()
|
||||
{
|
||||
struct cleanup *old_chain = cleanup_chain;
|
||||
|
||||
cleanup_chain = 0;
|
||||
return old_chain;
|
||||
}
|
||||
|
||||
/* Restore the cleanup chain from a previously saved chain. */
|
||||
void
|
||||
restore_cleanups (chain)
|
||||
struct cleanup *chain;
|
||||
{
|
||||
cleanup_chain = chain;
|
||||
}
|
||||
|
||||
/* This function is useful for cleanups.
|
||||
Do
|
||||
|
||||
foo = xmalloc (...);
|
||||
old_chain = make_cleanup (free_current_contents, &foo);
|
||||
|
||||
to arrange to free the object thus allocated. */
|
||||
|
||||
void
|
||||
free_current_contents (location)
|
||||
char **location;
|
||||
{
|
||||
free (*location);
|
||||
}
|
||||
|
||||
/* Generally useful subroutines used throughout the program. */
|
||||
|
||||
/* Like malloc but get error if no storage available. */
|
||||
|
||||
char *
|
||||
xmalloc (size)
|
||||
long size;
|
||||
{
|
||||
register char *val = (char *) malloc (size);
|
||||
if (!val)
|
||||
fatal ("virtual memory exhausted.", 0);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Like realloc but get error if no storage available. */
|
||||
|
||||
char *
|
||||
xrealloc (ptr, size)
|
||||
char *ptr;
|
||||
long size;
|
||||
{
|
||||
register char *val = (char *) realloc (ptr, size);
|
||||
if (!val)
|
||||
fatal ("virtual memory exhausted.", 0);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Print the system error message for errno, and also mention STRING
|
||||
as the file name for which the error was encountered.
|
||||
Then return to command level. */
|
||||
|
||||
void
|
||||
perror_with_name (string)
|
||||
char *string;
|
||||
{
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
extern int errno;
|
||||
char *err;
|
||||
char *combined;
|
||||
|
||||
if (errno < sys_nerr)
|
||||
err = sys_errlist[errno];
|
||||
else
|
||||
err = "unknown error";
|
||||
|
||||
combined = (char *) alloca (strlen (err) + strlen (string) + 3);
|
||||
strcpy (combined, string);
|
||||
strcat (combined, ": ");
|
||||
strcat (combined, err);
|
||||
|
||||
error ("%s.", combined);
|
||||
}
|
||||
|
||||
/* Print the system error message for ERRCODE, and also mention STRING
|
||||
as the file name for which the error was encountered. */
|
||||
|
||||
void
|
||||
print_sys_errmsg (string, errcode)
|
||||
char *string;
|
||||
int errcode;
|
||||
{
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
char *err;
|
||||
char *combined;
|
||||
|
||||
if (errcode < sys_nerr)
|
||||
err = sys_errlist[errcode];
|
||||
else
|
||||
err = "unknown error";
|
||||
|
||||
combined = (char *) alloca (strlen (err) + strlen (string) + 3);
|
||||
strcpy (combined, string);
|
||||
strcat (combined, ": ");
|
||||
strcat (combined, err);
|
||||
|
||||
printf ("%s.\n", combined);
|
||||
}
|
||||
|
||||
void
|
||||
quit ()
|
||||
{
|
||||
fflush (stdout);
|
||||
#ifdef HAVE_TERMIO
|
||||
ioctl (fileno (stdout), TCFLSH, 1);
|
||||
#else /* not HAVE_TERMIO */
|
||||
ioctl (fileno (stdout), TIOCFLUSH, 0);
|
||||
#endif /* not HAVE_TERMIO */
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
error ("Quit");
|
||||
#else
|
||||
error ("Quit (expect signal %d when inferior is resumed)", SIGINT);
|
||||
#endif /* TIOCGPGRP */
|
||||
}
|
||||
|
||||
/* Control C comes here */
|
||||
|
||||
void
|
||||
request_quit ()
|
||||
{
|
||||
quit_flag = 1;
|
||||
|
||||
#ifdef USG
|
||||
/* Restore the signal handler */
|
||||
signal(SIGINT, request_quit);
|
||||
#endif
|
||||
|
||||
if (immediate_quit)
|
||||
quit ();
|
||||
}
|
||||
|
||||
/* Print an error message and return to command level.
|
||||
STRING is the error message, used as a fprintf string,
|
||||
and ARG is passed as an argument to it. */
|
||||
|
||||
void
|
||||
error (string, arg1, arg2, arg3)
|
||||
char *string;
|
||||
int arg1, arg2, arg3;
|
||||
{
|
||||
fflush (stdout);
|
||||
fprintf (stderr, string, arg1, arg2, arg3);
|
||||
fprintf (stderr, "\n");
|
||||
return_to_top_level ();
|
||||
}
|
||||
|
||||
/* Print an error message and exit reporting failure.
|
||||
This is for a error that we cannot continue from.
|
||||
STRING and ARG are passed to fprintf. */
|
||||
|
||||
void
|
||||
fatal (string, arg)
|
||||
char *string;
|
||||
int arg;
|
||||
{
|
||||
fprintf (stderr, "gdb: ");
|
||||
fprintf (stderr, string, arg);
|
||||
fprintf (stderr, "\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Make a copy of the string at PTR with SIZE characters
|
||||
(and add a null character at the end in the copy).
|
||||
Uses malloc to get the space. Returns the address of the copy. */
|
||||
|
||||
char *
|
||||
savestring (ptr, size)
|
||||
char *ptr;
|
||||
int size;
|
||||
{
|
||||
register char *p = (char *) xmalloc (size + 1);
|
||||
bcopy (ptr, p, size);
|
||||
p[size] = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
char *
|
||||
concat (s1, s2, s3)
|
||||
char *s1, *s2, *s3;
|
||||
{
|
||||
register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
|
||||
register char *val = (char *) xmalloc (len);
|
||||
strcpy (val, s1);
|
||||
strcat (val, s2);
|
||||
strcat (val, s3);
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
print_spaces (n, file)
|
||||
register int n;
|
||||
register FILE *file;
|
||||
{
|
||||
while (n-- > 0)
|
||||
fputc (' ', file);
|
||||
}
|
||||
|
||||
/* Ask user a y-or-n question and return 1 iff answer is yes.
|
||||
Takes three args which are given to printf to print the question.
|
||||
The first, a control string, should end in "? ".
|
||||
It should not say how to answer, because we do that. */
|
||||
|
||||
int
|
||||
query (ctlstr, arg1, arg2)
|
||||
char *ctlstr;
|
||||
{
|
||||
register int answer;
|
||||
|
||||
/* Automatically answer "yes" if input is not from a terminal. */
|
||||
if (!input_from_terminal_p ())
|
||||
return 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
printf (ctlstr, arg1, arg2);
|
||||
printf ("(y or n) ");
|
||||
fflush (stdout);
|
||||
answer = fgetc (stdin);
|
||||
clearerr (stdin); /* in case of C-d */
|
||||
if (answer != '\n')
|
||||
while (fgetc (stdin) != '\n') clearerr (stdin);
|
||||
if (answer >= 'a')
|
||||
answer -= 040;
|
||||
if (answer == 'Y')
|
||||
return 1;
|
||||
if (answer == 'N')
|
||||
return 0;
|
||||
printf ("Please answer y or n.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a C escape sequence. STRING_PTR points to a variable
|
||||
containing a pointer to the string to parse. That pointer
|
||||
is updated past the characters we use. The value of the
|
||||
escape sequence is returned.
|
||||
|
||||
A negative value means the sequence \ newline was seen,
|
||||
which is supposed to be equivalent to nothing at all.
|
||||
|
||||
If \ is followed by a null character, we return a negative
|
||||
value and leave the string pointer pointing at the null character.
|
||||
|
||||
If \ is followed by 000, we return 0 and leave the string pointer
|
||||
after the zeros. A value of 0 does not mean end of string. */
|
||||
|
||||
int
|
||||
parse_escape (string_ptr)
|
||||
char **string_ptr;
|
||||
{
|
||||
register int c = *(*string_ptr)++;
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
return '\a';
|
||||
case 'b':
|
||||
return '\b';
|
||||
case 'e':
|
||||
return 033;
|
||||
case 'f':
|
||||
return '\f';
|
||||
case 'n':
|
||||
return '\n';
|
||||
case 'r':
|
||||
return '\r';
|
||||
case 't':
|
||||
return '\t';
|
||||
case 'v':
|
||||
return '\v';
|
||||
case '\n':
|
||||
return -2;
|
||||
case 0:
|
||||
(*string_ptr)--;
|
||||
return 0;
|
||||
case '^':
|
||||
c = *(*string_ptr)++;
|
||||
if (c == '\\')
|
||||
c = parse_escape (string_ptr);
|
||||
if (c == '?')
|
||||
return 0177;
|
||||
return (c & 0200) | (c & 037);
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
{
|
||||
register int i = c - '0';
|
||||
register int count = 0;
|
||||
while (++count < 3)
|
||||
{
|
||||
if ((c = *(*string_ptr)++) >= '0' && c <= '7')
|
||||
{
|
||||
i *= 8;
|
||||
i += c - '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
(*string_ptr)--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the character CH on STREAM as part of the contents
|
||||
of a literal string whose delimiter is QUOTER. */
|
||||
|
||||
void
|
||||
printchar (ch, stream, quoter)
|
||||
unsigned char ch;
|
||||
FILE *stream;
|
||||
int quoter;
|
||||
{
|
||||
register int c = ch;
|
||||
if (c < 040 || c >= 0177)
|
||||
{
|
||||
if (c == '\n')
|
||||
fprintf (stream, "\\n");
|
||||
else if (c == '\b')
|
||||
fprintf (stream, "\\b");
|
||||
else if (c == '\t')
|
||||
fprintf (stream, "\\t");
|
||||
else if (c == '\f')
|
||||
fprintf (stream, "\\f");
|
||||
else if (c == '\r')
|
||||
fprintf (stream, "\\r");
|
||||
else if (c == 033)
|
||||
fprintf (stream, "\\e");
|
||||
else if (c == '\a')
|
||||
fprintf (stream, "\\a");
|
||||
else
|
||||
fprintf (stream, "\\%03o", c);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == '\\' || c == quoter)
|
||||
fputc ('\\', stream);
|
||||
fputc (c, stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef USG
|
||||
bcopy (from, to, count)
|
||||
char *from, *to;
|
||||
{
|
||||
memcpy (to, from, count);
|
||||
}
|
||||
|
||||
bcmp (from, to, count)
|
||||
{
|
||||
return (memcmp (to, from, count));
|
||||
}
|
||||
|
||||
bzero (to, count)
|
||||
char *to;
|
||||
{
|
||||
while (count--)
|
||||
*to++ = 0;
|
||||
}
|
||||
|
||||
getwd (buf)
|
||||
char *buf;
|
||||
{
|
||||
getcwd (buf, MAXPATHLEN);
|
||||
}
|
||||
|
||||
char *
|
||||
index (s, c)
|
||||
char *s;
|
||||
{
|
||||
char *strchr ();
|
||||
return strchr (s, c);
|
||||
}
|
||||
|
||||
char *
|
||||
rindex (s, c)
|
||||
char *s;
|
||||
{
|
||||
char *strrchr ();
|
||||
return strrchr (s, c);
|
||||
}
|
||||
|
||||
/* Queue routines */
|
||||
|
||||
struct queue {
|
||||
struct queue *forw;
|
||||
struct queue *back;
|
||||
};
|
||||
|
||||
insque (item, after)
|
||||
struct queue *item;
|
||||
struct queue *after;
|
||||
{
|
||||
item->forw = after->forw;
|
||||
after->forw->back = item;
|
||||
|
||||
item->back = after;
|
||||
after->forw = item;
|
||||
}
|
||||
|
||||
remque (item)
|
||||
struct queue *item;
|
||||
{
|
||||
item->forw->back = item->back;
|
||||
item->back->forw = item->forw;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* There is too much variation in Sys V signal numbers and names, so
|
||||
* we must initialize them at runtime. If C provided a way to initialize
|
||||
* an array based on subscript and value, this would not be necessary.
|
||||
*/
|
||||
static char undoc[] = "(undocumented)";
|
||||
|
||||
char *sys_siglist[NSIG];
|
||||
|
||||
_initialize_utils()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NSIG; i++)
|
||||
sys_siglist[i] = undoc;
|
||||
|
||||
#ifdef SIGHUP
|
||||
sys_siglist[SIGHUP ] = "SIGHUP";
|
||||
#endif
|
||||
#ifdef SIGINT
|
||||
sys_siglist[SIGINT ] = "SIGINT";
|
||||
#endif
|
||||
#ifdef SIGQUIT
|
||||
sys_siglist[SIGQUIT ] = "SIGQUIT";
|
||||
#endif
|
||||
#ifdef SIGILL
|
||||
sys_siglist[SIGILL ] = "SIGILL";
|
||||
#endif
|
||||
#ifdef SIGTRAP
|
||||
sys_siglist[SIGTRAP ] = "SIGTRAP";
|
||||
#endif
|
||||
#ifdef SIGIOT
|
||||
sys_siglist[SIGIOT ] = "SIGIOT";
|
||||
#endif
|
||||
#ifdef SIGEMT
|
||||
sys_siglist[SIGEMT ] = "SIGEMT";
|
||||
#endif
|
||||
#ifdef SIGFPE
|
||||
sys_siglist[SIGFPE ] = "SIGFPE";
|
||||
#endif
|
||||
#ifdef SIGKILL
|
||||
sys_siglist[SIGKILL ] = "SIGKILL";
|
||||
#endif
|
||||
#ifdef SIGBUS
|
||||
sys_siglist[SIGBUS ] = "SIGBUS";
|
||||
#endif
|
||||
#ifdef SIGSEGV
|
||||
sys_siglist[SIGSEGV ] = "SIGSEGV";
|
||||
#endif
|
||||
#ifdef SIGSYS
|
||||
sys_siglist[SIGSYS ] = "SIGSYS";
|
||||
#endif
|
||||
#ifdef SIGPIPE
|
||||
sys_siglist[SIGPIPE ] = "SIGPIPE";
|
||||
#endif
|
||||
#ifdef SIGALRM
|
||||
sys_siglist[SIGALRM ] = "SIGALRM";
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
sys_siglist[SIGTERM ] = "SIGTERM";
|
||||
#endif
|
||||
#ifdef SIGUSR1
|
||||
sys_siglist[SIGUSR1 ] = "SIGUSR1";
|
||||
#endif
|
||||
#ifdef SIGUSR2
|
||||
sys_siglist[SIGUSR2 ] = "SIGUSR2";
|
||||
#endif
|
||||
#ifdef SIGCLD
|
||||
sys_siglist[SIGCLD ] = "SIGCLD";
|
||||
#endif
|
||||
#ifdef SIGCHLD
|
||||
sys_siglist[SIGCHLD ] = "SIGCHLD";
|
||||
#endif
|
||||
#ifdef SIGPWR
|
||||
sys_siglist[SIGPWR ] = "SIGPWR";
|
||||
#endif
|
||||
#ifdef SIGTSTP
|
||||
sys_siglist[SIGTSTP ] = "SIGTSTP";
|
||||
#endif
|
||||
#ifdef SIGTTIN
|
||||
sys_siglist[SIGTTIN ] = "SIGTTIN";
|
||||
#endif
|
||||
#ifdef SIGTTOU
|
||||
sys_siglist[SIGTTOU ] = "SIGTTOU";
|
||||
#endif
|
||||
#ifdef SIGSTOP
|
||||
sys_siglist[SIGSTOP ] = "SIGSTOP";
|
||||
#endif
|
||||
#ifdef SIGXCPU
|
||||
sys_siglist[SIGXCPU ] = "SIGXCPU";
|
||||
#endif
|
||||
#ifdef SIGXFSZ
|
||||
sys_siglist[SIGXFSZ ] = "SIGXFSZ";
|
||||
#endif
|
||||
#ifdef SIGVTALRM
|
||||
sys_siglist[SIGVTALRM ] = "SIGVTALRM";
|
||||
#endif
|
||||
#ifdef SIGPROF
|
||||
sys_siglist[SIGPROF ] = "SIGPROF";
|
||||
#endif
|
||||
#ifdef SIGWINCH
|
||||
sys_siglist[SIGWINCH ] = "SIGWINCH";
|
||||
#endif
|
||||
#ifdef SIGCONT
|
||||
sys_siglist[SIGCONT ] = "SIGCONT";
|
||||
#endif
|
||||
#ifdef SIGURG
|
||||
sys_siglist[SIGURG ] = "SIGURG";
|
||||
#endif
|
||||
#ifdef SIGIO
|
||||
sys_siglist[SIGIO ] = "SIGIO";
|
||||
#endif
|
||||
#ifdef SIGWIND
|
||||
sys_siglist[SIGWIND ] = "SIGWIND";
|
||||
#endif
|
||||
#ifdef SIGPHONE
|
||||
sys_siglist[SIGPHONE ] = "SIGPHONE";
|
||||
#endif
|
||||
#ifdef SIGPOLL
|
||||
sys_siglist[SIGPOLL ] = "SIGPOLL";
|
||||
#endif
|
||||
}
|
||||
#endif /* USG */
|
||||
|
||||
@
|
||||
|
||||
|
||||
1.1
|
||||
log
|
||||
@Initial revision
|
||||
@
|
||||
text
|
||||
@d223 1
|
||||
d237 6
|
||||
a506 26
|
||||
char *sys_siglist[32] = {
|
||||
"SIG0",
|
||||
"SIGHUP",
|
||||
"SIGINT",
|
||||
"SIGQUIT",
|
||||
"SIGILL",
|
||||
"SIGTRAP",
|
||||
"SIGIOT",
|
||||
"SIGEMT",
|
||||
"SIGFPE",
|
||||
"SIGKILL",
|
||||
"SIGBUS",
|
||||
"SIGSEGV",
|
||||
"SIGSYS",
|
||||
"SIGPIPE",
|
||||
"SIGALRM",
|
||||
"SIGTERM",
|
||||
"SIGUSR1",
|
||||
"SIGUSR2",
|
||||
"SIGCLD",
|
||||
"SIGPWR",
|
||||
"SIGWIND",
|
||||
"SIGPHONE",
|
||||
"SIGPOLL",
|
||||
};
|
||||
|
||||
d530 124
|
||||
@
|
1117
gdb/RCS/valprint.c,v
Normal file
1117
gdb/RCS/valprint.c,v
Normal file
File diff suppressed because it is too large
Load Diff
1047
gdb/RCS/values.c,v
Normal file
1047
gdb/RCS/values.c,v
Normal file
File diff suppressed because it is too large
Load Diff
61
gdb/README
61
gdb/README
@ -1,15 +1,10 @@
|
||||
This is GDB, a source-level debugger intended for GNU,
|
||||
presently running under un*x.
|
||||
|
||||
Before compiling GDB, you must set up links to four files according to
|
||||
Before compiling GDB, you must set up links to five files according to
|
||||
the kind of machine you are running on. To do this, type `config.gdb
|
||||
machine', where machine is something like `vax' or `sun2'. This
|
||||
creates links named `param.h', `m-init.h', `opcode.h', and `pinsn.c'.
|
||||
(Note: we lack information on certain machines.)
|
||||
|
||||
Also, `Makefile' must be changed to say `OBSTACK = obstack.o' instead
|
||||
of `OBSTACK=-lobstack' (unless you want to install obstack.o as
|
||||
/lib/libobstack.a).
|
||||
creates links named `param.h', `opcode.h', `pinsn.c', and `infdep.c'.
|
||||
|
||||
Once these files are set up, just `make' will do everything,
|
||||
producing an executable `gdb' in this directory.
|
||||
@ -21,12 +16,52 @@ m-<machine>.h
|
||||
This file contains macro definitions that express information
|
||||
about the machine's registers, stack frame format and instructions.
|
||||
|
||||
m-<machine>init.h
|
||||
|
||||
This file defines one macro, which says how to round up from the
|
||||
address of the end of the text of one .o file to the beginning of
|
||||
the text of the next .o file.
|
||||
|
||||
<machine>-opcode.h, <machine>-pinsn.c
|
||||
These files contain the information necessary to print instructions
|
||||
for your cpu type.
|
||||
|
||||
<machine>-dep.c
|
||||
Those routines which provide a low level interface to ptrace and which
|
||||
tend to be machine-dependent. (The machine-independent routines are in
|
||||
`infrun.c' and `inflow.c')
|
||||
|
||||
About debugging gdb with itself...
|
||||
|
||||
You probably want to do a "make TAGS" after you configure your
|
||||
distribution; this will put the machine dependent routines for your
|
||||
local machine where they will be accessed first by a M-period .
|
||||
|
||||
Also, you want to make sure that gdb is not compiled with shared
|
||||
libraries on the Sun 4. And you want to make sure that you've
|
||||
compiled gdb with your local cc or taken appropriate precautions
|
||||
regarding ansification of include files. See the Makefile for more
|
||||
information.
|
||||
|
||||
The "info" command, when executed without a subcommand in a gdb being
|
||||
debugged by gdb, will pop you back up to the top level gdb. See
|
||||
.gdbinit for more details.
|
||||
|
||||
About languages other than C...
|
||||
|
||||
C++ support has been integrated into gdb; it works, but somewhat
|
||||
buggily. Pascal support has not yet been integrated in gdb; the work
|
||||
is being done.
|
||||
|
||||
About reporting bugs...
|
||||
|
||||
The correct address for reporting bugs found with gdb is
|
||||
"bug-gdb@prep.ai.mit.edu". Please send all bugs to that address.
|
||||
|
||||
About xgdb...
|
||||
|
||||
xgdb.c was provided to us by the user community; it is not an integral
|
||||
part of the gdb distribution. The problem of providing visual
|
||||
debugging support on top of gdb is peripheral to the GNU project and
|
||||
(at least right now) we can't afford to put time into it. So while we
|
||||
will be happy to incorporate user fixes to xgdb.c, we do not guarantee
|
||||
that it will work and we will not fix bugs reported in it.
|
||||
|
||||
For those intersted in auto display of source and the availability of
|
||||
an editor while debugging I suggest trying gdb-mode in gnu-emacs.
|
||||
Comments on this mode are welcome.
|
||||
|
||||
|
112
gdb/a.out.encap.h
Normal file
112
gdb/a.out.encap.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* another try at encapsulating bsd object files in coff
|
||||
* by Pace Willisson 12/9/88
|
||||
*
|
||||
* This time, we will only use the coff headers to tell the kernel
|
||||
* how to exec the file. Therefore, the only fields that need to
|
||||
* be filled in are the scnptr and vaddr for the text and data
|
||||
* sections, and the vaddr for the bss. As far as coff is concerned,
|
||||
* there is no symbol table, relocation, or line numbers.
|
||||
*
|
||||
* A normal bsd header (struct exec) is placed after the coff headers,
|
||||
* and before the real text. I defined a the new fields 'a_machtype'
|
||||
* and a_flags. If a_machtype is M_386, and a_flags & A_ENCAP is
|
||||
* true, then the bsd header is preceeded by a coff header. Macros
|
||||
* like N_TXTOFF and N_TXTADDR use this field to find the bsd header.
|
||||
*
|
||||
* The only problem is to track down the bsd exec header. The
|
||||
* macros HEADER_OFFSET, etc do this. Look at nm.c, dis.c, etc
|
||||
* for examples.
|
||||
*/
|
||||
|
||||
#include "a.out.gnu.h"
|
||||
|
||||
#define N_FLAGS_COFF_ENCAPSULATE 0x20 /* coff header precedes bsd header */
|
||||
|
||||
/* Describe the COFF header used for encapsulation. */
|
||||
|
||||
struct coffheader
|
||||
{
|
||||
/* filehdr */
|
||||
unsigned short f_magic;
|
||||
unsigned short f_nscns;
|
||||
long f_timdat;
|
||||
long f_symptr;
|
||||
long f_nsyms;
|
||||
unsigned short f_opthdr;
|
||||
unsigned short f_flags;
|
||||
/* aouthdr */
|
||||
short magic;
|
||||
short vstamp;
|
||||
long tsize;
|
||||
long dsize;
|
||||
long bsize;
|
||||
long entry;
|
||||
long text_start;
|
||||
long data_start;
|
||||
struct coffscn
|
||||
{
|
||||
char s_name[8];
|
||||
long s_paddr;
|
||||
long s_vaddr;
|
||||
long s_size;
|
||||
long s_scnptr;
|
||||
long s_relptr;
|
||||
long s_lnnoptr;
|
||||
unsigned short s_nreloc;
|
||||
unsigned short s_nlnno;
|
||||
long s_flags;
|
||||
} scns[3];
|
||||
};
|
||||
|
||||
/* Describe some of the parameters of the encapsulation,
|
||||
including how to find the encapsulated BSD header. */
|
||||
|
||||
#ifdef i386
|
||||
#define COFF_MAGIC 0514 /* I386MAGIC */
|
||||
#endif
|
||||
|
||||
#if defined(i386)
|
||||
short __header_offset_temp;
|
||||
#define HEADER_OFFSET(f) \
|
||||
(__header_offset_temp = 0, \
|
||||
fread ((char *)&__header_offset_temp, sizeof (short), 1, (f)), \
|
||||
fseek ((f), -sizeof (short), 1), \
|
||||
__header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0)
|
||||
|
||||
#define HEADER_OFFSET_FD(fd) \
|
||||
(__header_offset_temp = 0, \
|
||||
read ((fd), (char *)&__header_offset_temp, sizeof (short)), \
|
||||
lseek ((fd), -sizeof (short), 1), \
|
||||
__header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0)
|
||||
|
||||
|
||||
#else
|
||||
#define HEADER_OFFSET(f) 0
|
||||
#define HEADER_OFFSET_FD(fd) 0
|
||||
#endif
|
||||
|
||||
#define HEADER_SEEK(f) (fseek ((f), HEADER_OFFSET((f)), 1))
|
||||
#define HEADER_SEEK_FD(fd) (lseek ((fd), HEADER_OFFSET_FD((fd)), 1))
|
||||
|
||||
|
||||
/* Describe the characteristics of the BSD header
|
||||
that appears inside the encapsulation. */
|
||||
|
||||
#undef _N_HDROFF
|
||||
#undef N_TXTADDR
|
||||
#undef N_DATADDR
|
||||
|
||||
#define _N_HDROFF(x) ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
|
||||
sizeof (struct coffheader) : 0)
|
||||
|
||||
/* Address of text segment in memory after it is loaded. */
|
||||
#define N_TXTADDR(x) \
|
||||
((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
|
||||
sizeof (struct coffheader) + sizeof (struct exec) : 0)
|
||||
|
||||
#define SEGMENT_SIZE 0x400000
|
||||
#define N_DATADDR(x) \
|
||||
((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \
|
||||
(SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))) : \
|
||||
(N_TXTADDR(x)+(x).a_text))
|
182
gdb/a.out.gnu.h
Normal file
182
gdb/a.out.gnu.h
Normal file
@ -0,0 +1,182 @@
|
||||
#ifndef __A_OUT_GNU_H__
|
||||
#define __A_OUT_GNU_H__
|
||||
|
||||
#define __GNU_EXEC_MACROS__
|
||||
|
||||
#ifndef __STRUCT_EXEC_OVERRIDE__
|
||||
|
||||
struct exec
|
||||
{
|
||||
unsigned long a_info; /* Use macros N_MAGIC, etc for access */
|
||||
unsigned a_text; /* length of text, in bytes */
|
||||
unsigned a_data; /* length of data, in bytes */
|
||||
unsigned a_bss; /* length of uninitialized data area for file, in bytes */
|
||||
unsigned a_syms; /* length of symbol table data in file, in bytes */
|
||||
unsigned a_entry; /* start address */
|
||||
unsigned a_trsize; /* length of relocation info for text, in bytes */
|
||||
unsigned a_drsize; /* length of relocation info for data, in bytes */
|
||||
};
|
||||
|
||||
#endif /* __STRUCT_EXEC_OVERRIDE__ */
|
||||
|
||||
/* these go in the N_MACHTYPE field */
|
||||
enum machine_type {
|
||||
M_OLDSUN2 = 0,
|
||||
M_68010 = 1,
|
||||
M_68020 = 2,
|
||||
M_SPARC = 3,
|
||||
/* skip a bunch so we don't run into any of sun's numbers */
|
||||
M_386 = 100,
|
||||
};
|
||||
|
||||
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
|
||||
#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
|
||||
#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
|
||||
#define N_SET_INFO(exec, magic, type, flags) \
|
||||
((exec).a_info = ((magic) & 0xffff) \
|
||||
| (((int)(type) & 0xff) << 16) \
|
||||
| (((flags) & 0xff) << 24))
|
||||
#define N_SET_MAGIC(exec, magic) \
|
||||
((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
|
||||
|
||||
#define N_SET_MACHTYPE(exec, machtype) \
|
||||
((exec).a_info = \
|
||||
((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
|
||||
|
||||
#define N_SET_FLAGS(exec, flags) \
|
||||
((exec).a_info = \
|
||||
((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
|
||||
|
||||
/* Code indicating object file or impure executable. */
|
||||
#define OMAGIC 0407
|
||||
/* Code indicating pure executable. */
|
||||
#define NMAGIC 0410
|
||||
/* Code indicating demand-paged executable. */
|
||||
#define ZMAGIC 0413
|
||||
|
||||
#define N_BADMAG(x) \
|
||||
(N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
|
||||
&& N_MAGIC(x) != ZMAGIC)
|
||||
|
||||
#define _N_HDROFF(x) (1024 - sizeof (struct exec))
|
||||
|
||||
#define N_TXTOFF(x) \
|
||||
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
|
||||
|
||||
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
|
||||
|
||||
#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
|
||||
|
||||
#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
|
||||
|
||||
#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
|
||||
|
||||
#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
|
||||
|
||||
/* Address of text segment in memory after it is loaded. */
|
||||
#define N_TXTADDR(x) 0
|
||||
|
||||
/* Address of data segment in memory after it is loaded.
|
||||
Note that it is up to you to define SEGMENT_SIZE
|
||||
on machines not listed here. */
|
||||
#ifdef vax
|
||||
#define SEGMENT_SIZE page_size
|
||||
#endif
|
||||
#ifdef is68k
|
||||
#define SEGMENT_SIZE 0x20000
|
||||
#endif
|
||||
|
||||
#ifndef N_DATADDR
|
||||
#define N_DATADDR(x) \
|
||||
(N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+(x).a_text) \
|
||||
: (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))))
|
||||
#endif
|
||||
|
||||
/* Address of bss segment in memory after it is loaded. */
|
||||
#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
|
||||
|
||||
struct nlist {
|
||||
union {
|
||||
char *n_name;
|
||||
struct nlist *n_next;
|
||||
long n_strx;
|
||||
} n_un;
|
||||
char n_type;
|
||||
char n_other;
|
||||
short n_desc;
|
||||
unsigned n_value;
|
||||
};
|
||||
|
||||
#define N_UNDF 0
|
||||
#define N_ABS 2
|
||||
#define N_TEXT 4
|
||||
#define N_DATA 6
|
||||
#define N_BSS 8
|
||||
#define N_FN 15
|
||||
|
||||
#define N_EXT 1
|
||||
#define N_TYPE 036
|
||||
#define N_STAB 0340
|
||||
|
||||
/* The following type indicates the definition of a symbol as being
|
||||
an indirect reference to another symbol. The other symbol
|
||||
appears as an undefined reference, immediately following this symbol.
|
||||
|
||||
Indirection is asymmetrical. The other symbol's value will be used
|
||||
to satisfy requests for the indirect symbol, but not vice versa.
|
||||
If the other symbol does not have a definition, libraries will
|
||||
be searched to find a definition. */
|
||||
#define N_INDR 0xa
|
||||
|
||||
/* The following symbols refer to set elements.
|
||||
All the N_SET[ATDB] symbols with the same name form one set.
|
||||
Space is allocated for the set in the text section, and each set
|
||||
element's value is stored into one word of the space.
|
||||
The first word of the space is the length of the set (number of elements).
|
||||
|
||||
The address of the set is made into an N_SETV symbol
|
||||
whose name is the same as the name of the set.
|
||||
This symbol acts like a N_DATA global symbol
|
||||
in that it can satisfy undefined external references. */
|
||||
|
||||
/* These appear as input to LD, in a .o file. */
|
||||
#define N_SETA 0x14 /* Absolute set element symbol */
|
||||
#define N_SETT 0x16 /* Text set element symbol */
|
||||
#define N_SETD 0x18 /* Data set element symbol */
|
||||
#define N_SETB 0x1A /* Bss set element symbol */
|
||||
|
||||
/* This is output from LD. */
|
||||
#define N_SETV 0x1C /* Pointer to set vector in data area. */
|
||||
|
||||
/* This structure describes a single relocation to be performed.
|
||||
The text-relocation section of the file is a vector of these structures,
|
||||
all of which apply to the text section.
|
||||
Likewise, the data-relocation section applies to the data section. */
|
||||
|
||||
struct relocation_info
|
||||
{
|
||||
/* Address (within segment) to be relocated. */
|
||||
int r_address;
|
||||
/* The meaning of r_symbolnum depends on r_extern. */
|
||||
unsigned int r_symbolnum:24;
|
||||
/* Nonzero means value is a pc-relative offset
|
||||
and it should be relocated for changes in its own address
|
||||
as well as for changes in the symbol or section specified. */
|
||||
unsigned int r_pcrel:1;
|
||||
/* Length (as exponent of 2) of the field to be relocated.
|
||||
Thus, a value of 2 indicates 1<<2 bytes. */
|
||||
unsigned int r_length:2;
|
||||
/* 1 => relocate with value of symbol.
|
||||
r_symbolnum is the index of the symbol
|
||||
in file's the symbol table.
|
||||
0 => relocate with the address of a segment.
|
||||
r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
|
||||
(the N_EXT bit may be set also, but signifies nothing). */
|
||||
unsigned int r_extern:1;
|
||||
/* Four bits that aren't used, but when writing an object file
|
||||
it is desirable to clear them. */
|
||||
unsigned int r_pad:4;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __A_OUT_GNU_H__ */
|
191
gdb/alloca.c
Normal file
191
gdb/alloca.c
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
alloca -- (mostly) portable public-domain implementation -- D A Gwyn
|
||||
|
||||
last edit: 86/05/30 rms
|
||||
include config.h, since on VMS it renames some symbols.
|
||||
Use xmalloc instead of malloc.
|
||||
|
||||
This implementation of the PWB library alloca() function,
|
||||
which is used to allocate space off the run-time stack so
|
||||
that it is automatically reclaimed upon procedure exit,
|
||||
was inspired by discussions with J. Q. Johnson of Cornell.
|
||||
|
||||
It should work under any C implementation that uses an
|
||||
actual procedure stack (as opposed to a linked list of
|
||||
frames). There are some preprocessor constants that can
|
||||
be defined when compiling for your specific system, for
|
||||
improved efficiency; however, the defaults should be okay.
|
||||
|
||||
The general concept of this implementation is to keep
|
||||
track of all alloca()-allocated blocks, and reclaim any
|
||||
that are found to be deeper in the stack than the current
|
||||
invocation. This heuristic does not reclaim storage as
|
||||
soon as it becomes invalid, but it will do so eventually.
|
||||
|
||||
As a special case, alloca(0) reclaims storage without
|
||||
allocating any. It is a good idea to use alloca(0) in
|
||||
your main control loop, etc. to force garbage collection.
|
||||
*/
|
||||
#ifndef lint
|
||||
static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
|
||||
#endif
|
||||
|
||||
#ifdef emacs
|
||||
#include "config.h"
|
||||
#ifdef static
|
||||
/* actually, only want this if static is defined as ""
|
||||
-- this is for usg, in which emacs must undefine static
|
||||
in order to make unexec workable
|
||||
*/
|
||||
#ifndef STACK_DIRECTION
|
||||
you
|
||||
lose
|
||||
-- must know STACK_DIRECTION at compile-time
|
||||
#endif /* STACK_DIRECTION undefined */
|
||||
#endif static
|
||||
#endif emacs
|
||||
|
||||
#ifdef X3J11
|
||||
typedef void *pointer; /* generic pointer type */
|
||||
#else
|
||||
typedef char *pointer; /* generic pointer type */
|
||||
#endif
|
||||
|
||||
#define NULL 0 /* null pointer constant */
|
||||
|
||||
extern void free();
|
||||
extern pointer xmalloc();
|
||||
|
||||
/*
|
||||
Define STACK_DIRECTION if you know the direction of stack
|
||||
growth for your system; otherwise it will be automatically
|
||||
deduced at run-time.
|
||||
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown
|
||||
*/
|
||||
|
||||
#ifndef STACK_DIRECTION
|
||||
#define STACK_DIRECTION 0 /* direction unknown */
|
||||
#endif
|
||||
|
||||
#if STACK_DIRECTION != 0
|
||||
|
||||
#define STACK_DIR STACK_DIRECTION /* known at compile-time */
|
||||
|
||||
#else /* STACK_DIRECTION == 0; need run-time code */
|
||||
|
||||
static int stack_dir; /* 1 or -1 once known */
|
||||
#define STACK_DIR stack_dir
|
||||
|
||||
static void
|
||||
find_stack_direction (/* void */)
|
||||
{
|
||||
static char *addr = NULL; /* address of first
|
||||
`dummy', once known */
|
||||
auto char dummy; /* to get stack address */
|
||||
|
||||
if (addr == NULL)
|
||||
{ /* initial entry */
|
||||
addr = &dummy;
|
||||
|
||||
find_stack_direction (); /* recurse once */
|
||||
}
|
||||
else /* second entry */
|
||||
if (&dummy > addr)
|
||||
stack_dir = 1; /* stack grew upward */
|
||||
else
|
||||
stack_dir = -1; /* stack grew downward */
|
||||
}
|
||||
|
||||
#endif /* STACK_DIRECTION == 0 */
|
||||
|
||||
/*
|
||||
An "alloca header" is used to:
|
||||
(a) chain together all alloca()ed blocks;
|
||||
(b) keep track of stack depth.
|
||||
|
||||
It is very important that sizeof(header) agree with malloc()
|
||||
alignment chunk size. The following default should work okay.
|
||||
*/
|
||||
|
||||
#ifndef ALIGN_SIZE
|
||||
#define ALIGN_SIZE sizeof(double)
|
||||
#endif
|
||||
|
||||
typedef union hdr
|
||||
{
|
||||
char align[ALIGN_SIZE]; /* to force sizeof(header) */
|
||||
struct
|
||||
{
|
||||
union hdr *next; /* for chaining headers */
|
||||
char *deep; /* for stack depth measure */
|
||||
} h;
|
||||
} header;
|
||||
|
||||
/*
|
||||
alloca( size ) returns a pointer to at least `size' bytes of
|
||||
storage which will be automatically reclaimed upon exit from
|
||||
the procedure that called alloca(). Originally, this space
|
||||
was supposed to be taken from the current stack frame of the
|
||||
caller, but that method cannot be made to work for some
|
||||
implementations of C, for example under Gould's UTX/32.
|
||||
*/
|
||||
|
||||
static header *last_alloca_header = NULL; /* -> last alloca header */
|
||||
|
||||
pointer
|
||||
alloca (size) /* returns pointer to storage */
|
||||
unsigned size; /* # bytes to allocate */
|
||||
{
|
||||
auto char probe; /* probes stack depth: */
|
||||
register char *depth = &probe;
|
||||
|
||||
#if STACK_DIRECTION == 0
|
||||
if (STACK_DIR == 0) /* unknown growth direction */
|
||||
find_stack_direction ();
|
||||
#endif
|
||||
|
||||
/* Reclaim garbage, defined as all alloca()ed storage that
|
||||
was allocated from deeper in the stack than currently. */
|
||||
|
||||
{
|
||||
register header *hp; /* traverses linked list */
|
||||
|
||||
for (hp = last_alloca_header; hp != NULL;)
|
||||
if (STACK_DIR > 0 && hp->h.deep > depth
|
||||
|| STACK_DIR < 0 && hp->h.deep < depth)
|
||||
{
|
||||
register header *np = hp->h.next;
|
||||
|
||||
free ((pointer) hp); /* collect garbage */
|
||||
|
||||
hp = np; /* -> next header */
|
||||
}
|
||||
else
|
||||
break; /* rest are not deeper */
|
||||
|
||||
last_alloca_header = hp; /* -> last valid storage */
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return NULL; /* no allocation required */
|
||||
|
||||
/* Allocate combined header + user data storage. */
|
||||
|
||||
{
|
||||
register pointer new = xmalloc (sizeof (header) + size);
|
||||
/* address of header */
|
||||
|
||||
((header *)new)->h.next = last_alloca_header;
|
||||
((header *)new)->h.deep = depth;
|
||||
|
||||
last_alloca_header = (header *)new;
|
||||
|
||||
/* User storage begins just after header. */
|
||||
|
||||
return (pointer)((char *)new + sizeof(header));
|
||||
}
|
||||
}
|
||||
|
BIN
gdb/alloca.o
Normal file
BIN
gdb/alloca.o
Normal file
Binary file not shown.
354
gdb/blockframe.c
354
gdb/blockframe.c
@ -20,7 +20,6 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "initialize.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
@ -39,7 +38,12 @@ static FRAME current_frame;
|
||||
struct block *block_for_pc ();
|
||||
CORE_ADDR get_pc_function_start ();
|
||||
|
||||
START_FILE
|
||||
/*
|
||||
* Cache for frame addresses already read by gdb. Valid only while
|
||||
* inferior is stopped. Control variables for the frame cache should
|
||||
* be local to this module.
|
||||
*/
|
||||
struct obstack frame_cache_obstack;
|
||||
|
||||
/* Return the innermost (currently executing) stack frame. */
|
||||
|
||||
@ -59,6 +63,31 @@ set_current_frame (frame)
|
||||
current_frame = frame;
|
||||
}
|
||||
|
||||
FRAME
|
||||
create_new_frame (addr, pc)
|
||||
FRAME_ADDR addr;
|
||||
CORE_ADDR pc;
|
||||
{
|
||||
struct frame_info *fci; /* Same type as FRAME */
|
||||
|
||||
fci = (struct frame_info *)
|
||||
obstack_alloc (&frame_cache_obstack,
|
||||
sizeof (struct frame_info));
|
||||
|
||||
/* Arbitrary frame */
|
||||
fci->next = (struct frame_info *) 0;
|
||||
fci->prev = (struct frame_info *) 0;
|
||||
fci->frame = addr;
|
||||
fci->next_frame = 0; /* Since arbitrary */
|
||||
fci->pc = pc;
|
||||
|
||||
#ifdef INIT_EXTRA_FRAME_INFO
|
||||
INIT_EXTRA_FRAME_INFO (fci);
|
||||
#endif
|
||||
|
||||
return fci;
|
||||
}
|
||||
|
||||
/* Return the frame that called FRAME.
|
||||
If FRAME is the original frame (it has no caller), return 0. */
|
||||
|
||||
@ -66,98 +95,154 @@ FRAME
|
||||
get_prev_frame (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
CORE_ADDR pointer;
|
||||
/* The caller of "no frame" is the innermost frame. */
|
||||
if (frame == 0)
|
||||
return get_current_frame ();
|
||||
/* We're allowed to know that FRAME and "struct frame_info *" are
|
||||
the same */
|
||||
return get_prev_frame_info (frame);
|
||||
}
|
||||
|
||||
/* Two macros defined in param.h specify the machine-dependent
|
||||
actions to be performed here. */
|
||||
/* First, get the frame's chain-pointer.
|
||||
If that is zero, the frame is the outermost frame. */
|
||||
pointer = FRAME_CHAIN (frame);
|
||||
if (!FRAME_CHAIN_VALID (pointer, frame))
|
||||
return 0;
|
||||
/* If frame has a caller, combine the chain pointer and the frame's own
|
||||
address to get the address of the caller. */
|
||||
return FRAME_CHAIN_COMBINE (pointer, frame);
|
||||
/*
|
||||
* Flush the entire frame cache.
|
||||
*/
|
||||
void
|
||||
flush_cached_frames ()
|
||||
{
|
||||
/* Since we can't really be sure what the first object allocated was */
|
||||
obstack_free (&frame_cache_obstack, 0);
|
||||
obstack_init (&frame_cache_obstack);
|
||||
|
||||
current_frame = (struct frame_info *) 0; /* Invalidate cache */
|
||||
}
|
||||
|
||||
/* Return a structure containing various interesting information
|
||||
about a specified stack frame. */
|
||||
/* How do I justify including this function? Well, the FRAME
|
||||
identifier format has gone through several changes recently, and
|
||||
it's not completely inconceivable that it could happen again. If
|
||||
it does, have this routine around will help */
|
||||
|
||||
struct frame_info
|
||||
struct frame_info *
|
||||
get_frame_info (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
struct frame_info val;
|
||||
FRAME current = get_current_frame ();
|
||||
register FRAME frame1, frame2;
|
||||
|
||||
val.frame = frame;
|
||||
|
||||
if (frame == current)
|
||||
{
|
||||
val.pc = read_pc ();
|
||||
val.next_frame = 0;
|
||||
val.next_next_frame = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (frame1 = current, frame2 = 0;
|
||||
frame1;
|
||||
frame2 = frame1, frame1 = get_prev_frame (frame1))
|
||||
{
|
||||
QUIT;
|
||||
if (frame1 == frame)
|
||||
break;
|
||||
|
||||
val.pc = FRAME_SAVED_PC (frame1, frame2);
|
||||
val.next_frame = frame1;
|
||||
val.next_next_frame = frame2;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
return frame;
|
||||
}
|
||||
|
||||
/* Return a structure containing various interesting information
|
||||
about the frame that called FRAME.
|
||||
about the frame that called NEXT_FRAME. */
|
||||
|
||||
This is much faster than get_frame_info (get_prev_frame (FRAME))
|
||||
because it does not need to search the entire stack
|
||||
to find the frame called by the one being described -- that is FRAME. */
|
||||
|
||||
struct frame_info
|
||||
get_prev_frame_info (next_frame, next_next_frame)
|
||||
FRAME next_frame, next_next_frame;
|
||||
struct frame_info *
|
||||
get_prev_frame_info (next_frame)
|
||||
FRAME next_frame;
|
||||
{
|
||||
struct frame_info val;
|
||||
register FRAME frame = get_prev_frame (next_frame);
|
||||
FRAME_ADDR address;
|
||||
struct frame_info *prev;
|
||||
int fromleaf = 0;
|
||||
|
||||
val.frame = frame;
|
||||
val.next_frame = next_frame;
|
||||
val.next_next_frame = next_next_frame;
|
||||
/* If we are within "start" right now, don't go any higher. */
|
||||
/* This truncates stack traces of things at sigtramp() though,
|
||||
because sigtramp() doesn't have a normal return PC, it has
|
||||
garbage or a small value (seen: 3) in the return PC slot.
|
||||
It's VITAL to see where the signal occurred, so punt this. */
|
||||
#if 0
|
||||
if (next_frame && next_frame->pc < first_object_file_end)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (next_frame == 0)
|
||||
/* If the requested entry is in the cache, return it.
|
||||
Otherwise, figure out what the address should be for the entry
|
||||
we're about to add to the cache. */
|
||||
|
||||
if (!next_frame)
|
||||
{
|
||||
val.pc = read_pc ();
|
||||
if (!current_frame)
|
||||
error ("No frame is currently selected.");
|
||||
|
||||
return current_frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
val.pc = FRAME_SAVED_PC (next_frame, next_next_frame);
|
||||
/* If we have the prev one, return it */
|
||||
if (next_frame->prev)
|
||||
return next_frame->prev;
|
||||
|
||||
/* There is a questionable, but probably always correct
|
||||
assumption being made here. The assumption is that if
|
||||
functions on a specific machine has a FUNCTION_START_OFFSET,
|
||||
then this is used by the function call instruction for some
|
||||
purpose. If the function call instruction has this much hair
|
||||
in it, it probably also sets up the frame pointer
|
||||
automatically (ie. we'll never have what I am calling a
|
||||
"leaf node", one which shares a frame pointer with it's
|
||||
calling function). This is true on a vax. The only other
|
||||
way to find this out would be to setup a seperate macro
|
||||
"FUNCTION_HAS_FRAME_POINTER", which would often be equivalent
|
||||
to SKIP_PROLOGUE modifying a pc value. */
|
||||
|
||||
#if FUNCTION_START_OFFSET == 0
|
||||
if (!(next_frame->next))
|
||||
{
|
||||
/* Innermost */
|
||||
CORE_ADDR func_start, after_prologue;
|
||||
|
||||
func_start = (get_pc_function_start (next_frame->pc) +
|
||||
FUNCTION_START_OFFSET);
|
||||
after_prologue = func_start;
|
||||
SKIP_PROLOGUE (after_prologue);
|
||||
if (after_prologue == func_start)
|
||||
{
|
||||
fromleaf = 1;
|
||||
address = next_frame->frame;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!fromleaf)
|
||||
{
|
||||
/* Two macros defined in param.h specify the machine-dependent
|
||||
actions to be performed here. */
|
||||
/* First, get the frame's chain-pointer.
|
||||
If that is zero, the frame is the outermost frame. */
|
||||
address = FRAME_CHAIN (next_frame);
|
||||
if (!FRAME_CHAIN_VALID (address, next_frame))
|
||||
return 0;
|
||||
|
||||
/* If frame has a caller, combine the chain pointer and
|
||||
the frame's own address to get the address of the caller. */
|
||||
address = FRAME_CHAIN_COMBINE (address, next_frame);
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
prev = (struct frame_info *)
|
||||
obstack_alloc (&frame_cache_obstack,
|
||||
sizeof (struct frame_info));
|
||||
|
||||
if (next_frame)
|
||||
next_frame->prev = prev;
|
||||
prev->next = next_frame;
|
||||
prev->prev = (struct frame_info *) 0;
|
||||
prev->frame = address;
|
||||
prev->next_frame = prev->next ? prev->next->frame : 0;
|
||||
|
||||
#ifdef INIT_EXTRA_FRAME_INFO
|
||||
INIT_EXTRA_FRAME_INFO(prev);
|
||||
#endif
|
||||
|
||||
/* This entry is in the frame queue now, which is good since
|
||||
FRAME_SAVED_PC may use that queue to figure out it's value
|
||||
(see m-sparc.h). We want the pc saved in the inferior frame. */
|
||||
prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) :
|
||||
next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ());
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
get_frame_pc (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
struct frame_info fi;
|
||||
struct frame_info *fi;
|
||||
fi = get_frame_info (frame);
|
||||
return fi.pc;
|
||||
return fi->pc;
|
||||
}
|
||||
|
||||
/* Find the addresses in which registers are saved in FRAME. */
|
||||
@ -167,7 +252,102 @@ get_frame_saved_regs (frame_info_addr, saved_regs_addr)
|
||||
struct frame_info *frame_info_addr;
|
||||
struct frame_saved_regs *saved_regs_addr;
|
||||
{
|
||||
FRAME_FIND_SAVED_REGS (*frame_info_addr, *saved_regs_addr);
|
||||
#if 1
|
||||
FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr);
|
||||
#else
|
||||
{
|
||||
register int regnum;
|
||||
register int regmask;
|
||||
register CORE_ADDR next_addr;
|
||||
register CORE_ADDR pc;
|
||||
int nextinsn;
|
||||
bzero (&*saved_regs_addr, sizeof *saved_regs_addr);
|
||||
if ((frame_info_addr)->pc >= ((frame_info_addr)->frame
|
||||
- CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4)
|
||||
&& (frame_info_addr)->pc <= (frame_info_addr)->frame)
|
||||
{
|
||||
next_addr = (frame_info_addr)->frame;
|
||||
pc = (frame_info_addr)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
pc = get_pc_function_start ((frame_info_addr)->pc);
|
||||
/* Verify we have a link a6 instruction next;
|
||||
if not we lose. If we win, find the address above the saved
|
||||
regs using the amount of storage from the link instruction. */
|
||||
if (044016 == read_memory_integer (pc, 2))
|
||||
{
|
||||
next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 4);
|
||||
pc += 4;
|
||||
}
|
||||
else if (047126 == read_memory_integer (pc, 2))
|
||||
{
|
||||
next_addr = (frame_info_addr)->frame + read_memory_integer (pc += 2, 2);
|
||||
pc+=2;
|
||||
}
|
||||
else goto lose;
|
||||
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774)
|
||||
{
|
||||
next_addr += read_memory_integer (pc += 2, 4);
|
||||
pc += 4;
|
||||
}
|
||||
}
|
||||
/* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
|
||||
/* But before that can come an fmovem. Check for it. */
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2);
|
||||
if (0xf227 == nextinsn
|
||||
&& (regmask & 0xff00) == 0xe000)
|
||||
{
|
||||
pc += 4; /* Regmask's low bit is for register fp7, the first pushed */
|
||||
for (regnum = FP0_REGNUM + 7;
|
||||
regnum >= FP0_REGNUM;
|
||||
regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr -= 12);
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
}
|
||||
if (0044327 == read_memory_integer (pc, 2))
|
||||
{
|
||||
pc += 4; /* Regmask's low bit is for register 0, the first written */
|
||||
for (regnum = 0; regnum < 16; regnum++, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr += 4) - 4;
|
||||
}
|
||||
else if (0044347 == read_memory_integer (pc, 2))
|
||||
{ pc += 4; /* Regmask's low bit is for register 15, the first pushed */
|
||||
for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr -= 4); }
|
||||
else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2)))
|
||||
{ regnum = 0xf & read_memory_integer (pc, 2); pc += 2;
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr -= 4); }
|
||||
/* fmovemx to index of sp may follow. */
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2);
|
||||
if (0xf236 == nextinsn
|
||||
&& (regmask & 0xff00) == 0xf000)
|
||||
{
|
||||
pc += 10; /* Regmask's low bit is for register fp0, the first written */
|
||||
for (regnum = FP0_REGNUM + 7;
|
||||
regnum >= FP0_REGNUM;
|
||||
regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
(*saved_regs_addr).regs[regnum] = (next_addr += 12) - 12;
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
}
|
||||
/* clrw -(sp); movw ccr,-(sp) may follow. */
|
||||
if (0x426742e7 == read_memory_integer (pc, 4))
|
||||
(*saved_regs_addr).regs[PS_REGNUM] = (next_addr -= 4);
|
||||
lose: ;
|
||||
(*saved_regs_addr).regs[SP_REGNUM] = (frame_info_addr)->frame + 8;
|
||||
(*saved_regs_addr).regs[FP_REGNUM] = (frame_info_addr)->frame;
|
||||
(*saved_regs_addr).regs[PC_REGNUM] = (frame_info_addr)->frame + 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the innermost lexical block in execution
|
||||
@ -177,10 +357,10 @@ struct block *
|
||||
get_frame_block (frame)
|
||||
FRAME frame;
|
||||
{
|
||||
struct frame_info fi;
|
||||
struct frame_info *fi;
|
||||
|
||||
fi = get_frame_info (frame);
|
||||
return block_for_pc (fi.pc);
|
||||
return block_for_pc (fi->pc);
|
||||
}
|
||||
|
||||
struct block *
|
||||
@ -195,17 +375,16 @@ get_pc_function_start (pc)
|
||||
{
|
||||
register struct block *bl = block_for_pc (pc);
|
||||
register struct symbol *symbol;
|
||||
if (bl == 0)
|
||||
if (bl == 0 || (symbol = block_function (bl)) == 0)
|
||||
{
|
||||
register int misc_index = find_pc_misc_function (pc);
|
||||
if (misc_index >= 0)
|
||||
return misc_function_vector[misc_index].address;
|
||||
return 0;
|
||||
}
|
||||
symbol = block_function (bl);
|
||||
bl = SYMBOL_BLOCK_VALUE (symbol);
|
||||
return BLOCK_START (bl);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the symbol for the function executing in frame FRAME. */
|
||||
|
||||
@ -222,6 +401,8 @@ get_frame_function (frame)
|
||||
/* Return the innermost lexical block containing the specified pc value,
|
||||
or 0 if there is none. */
|
||||
|
||||
extern struct symtab *psymtab_to_symtab ();
|
||||
|
||||
struct block *
|
||||
block_for_pc (pc)
|
||||
register CORE_ADDR pc;
|
||||
@ -229,6 +410,7 @@ block_for_pc (pc)
|
||||
register struct block *b;
|
||||
register int bot, top, half;
|
||||
register struct symtab *s;
|
||||
register struct partial_symtab *ps;
|
||||
struct blockvector *bl;
|
||||
|
||||
/* First search all symtabs for one whose file contains our pc */
|
||||
@ -242,6 +424,19 @@ block_for_pc (pc)
|
||||
break;
|
||||
}
|
||||
|
||||
if (s == 0)
|
||||
for (ps = partial_symtab_list; ps; ps = ps->next)
|
||||
{
|
||||
if (ps->textlow <= pc
|
||||
&& ps->texthigh > pc)
|
||||
{
|
||||
s = psymtab_to_symtab (ps);
|
||||
bl = BLOCKVECTOR (s);
|
||||
b = BLOCKVECTOR_BLOCK (bl, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == 0)
|
||||
return 0;
|
||||
|
||||
@ -307,7 +502,7 @@ find_pc_misc_function (pc)
|
||||
if (hi < 0) return -1; /* no misc functions recorded */
|
||||
|
||||
/* trivial reject range test */
|
||||
if (pc < misc_function_vector[0].address ||
|
||||
if (pc < misc_function_vector[0].address ||
|
||||
pc > misc_function_vector[hi].address)
|
||||
return -1;
|
||||
|
||||
@ -333,7 +528,7 @@ FRAME
|
||||
block_innermost_frame (block)
|
||||
struct block *block;
|
||||
{
|
||||
struct frame_info fi;
|
||||
struct frame_info *fi;
|
||||
register FRAME frame;
|
||||
register CORE_ADDR start = BLOCK_START (block);
|
||||
register CORE_ADDR end = BLOCK_END (block);
|
||||
@ -341,18 +536,17 @@ block_innermost_frame (block)
|
||||
frame = 0;
|
||||
while (1)
|
||||
{
|
||||
fi = get_prev_frame_info (frame);
|
||||
frame = fi.frame;
|
||||
frame = get_prev_frame (frame);
|
||||
if (frame == 0)
|
||||
return 0;
|
||||
if (fi.pc >= start && fi.pc < end)
|
||||
fi = get_frame_info (frame);
|
||||
if (fi->pc >= start && fi->pc < end)
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
initialize ()
|
||||
void
|
||||
_initialize_blockframe ()
|
||||
{
|
||||
obstack_init (&frame_cache_obstack);
|
||||
}
|
||||
|
||||
END_FILE
|
||||
|
371
gdb/breakpoint.c
371
gdb/breakpoint.c
@ -19,7 +19,6 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "initialize.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
@ -32,10 +31,16 @@ static char break_insn[] = BREAKPOINT;
|
||||
|
||||
/* States of enablement of breakpoint.
|
||||
`temporary' means disable when hit.
|
||||
`once' means delete when hit. */
|
||||
`delete' means delete when hit. */
|
||||
|
||||
enum enable { disabled, enabled, temporary, delete};
|
||||
|
||||
/* Not that the ->silent field is not currently used by any commands
|
||||
(though the code is in there if it was to be and set_raw_breakpoint
|
||||
does set it to 0). I implemented it because I thought it would be
|
||||
useful for a hack I had to put in; I'm going to leave it in because
|
||||
I can see how there might be times when it would indeed be useful */
|
||||
|
||||
struct breakpoint
|
||||
{
|
||||
struct breakpoint *next;
|
||||
@ -49,6 +54,9 @@ struct breakpoint
|
||||
struct symtab *symtab;
|
||||
/* Zero means disabled; remember the info but don't break here. */
|
||||
enum enable enable;
|
||||
/* Non-zero means a silent breakpoint (don't print frame info
|
||||
if we stop here). */
|
||||
unsigned char silent;
|
||||
/* Number of stops at this breakpoint that should
|
||||
be continued automatically before really stopping. */
|
||||
int ignore_count;
|
||||
@ -62,8 +70,9 @@ struct breakpoint
|
||||
char duplicate;
|
||||
/* Chain of command lines to execute when this breakpoint is hit. */
|
||||
struct command_line *commands;
|
||||
/* Stack depth (frame). If nonzero, break only if fp equals this. */
|
||||
FRAME frame;
|
||||
/* Stack depth (address of frame). If nonzero, break only if fp
|
||||
equals this. */
|
||||
FRAME_ADDR frame;
|
||||
/* Conditional. Break only if this expression's value is nonzero. */
|
||||
struct expression *cond;
|
||||
};
|
||||
@ -95,10 +104,6 @@ int default_breakpoint_line;
|
||||
|
||||
struct command_line *breakpoint_commands;
|
||||
|
||||
START_FILE
|
||||
|
||||
extern char *read_line ();
|
||||
|
||||
static void delete_breakpoint ();
|
||||
void clear_momentary_breakpoints ();
|
||||
void breakpoint_auto_delete ();
|
||||
@ -161,9 +166,6 @@ commands_command (arg)
|
||||
register int bnum;
|
||||
struct command_line *l;
|
||||
|
||||
if (arg == 0)
|
||||
error_no_arg ("breakpoint number");
|
||||
|
||||
/* If we allowed this, we would have problems with when to
|
||||
free the storage, if we change the commands currently
|
||||
being read from. */
|
||||
@ -171,15 +173,21 @@ commands_command (arg)
|
||||
if (breakpoint_commands)
|
||||
error ("Can't use the \"commands\" command among a breakpoint's commands.");
|
||||
|
||||
p = arg;
|
||||
if (! (*p >= '0' && *p <= '9'))
|
||||
error ("Argument must be integer (a breakpoint number).");
|
||||
|
||||
while (*p >= '0' && *p <= '9') p++;
|
||||
if (*p)
|
||||
error ("Unexpected extra arguments following breakpoint number.");
|
||||
|
||||
bnum = atoi (arg);
|
||||
/* Allow commands by itself to refer to the last breakpoint. */
|
||||
if (arg == 0)
|
||||
bnum = breakpoint_count;
|
||||
else
|
||||
{
|
||||
p = arg;
|
||||
if (! (*p >= '0' && *p <= '9'))
|
||||
error ("Argument must be integer (a breakpoint number).");
|
||||
|
||||
while (*p >= '0' && *p <= '9') p++;
|
||||
if (*p)
|
||||
error ("Unexpected extra arguments following breakpoint number.");
|
||||
|
||||
bnum = atoi (arg);
|
||||
}
|
||||
|
||||
ALL_BREAKPOINTS (b)
|
||||
if (b->number == bnum)
|
||||
@ -254,7 +262,10 @@ insert_breakpoints ()
|
||||
register struct breakpoint *b;
|
||||
int val;
|
||||
|
||||
/* printf ("Inserting breakpoints.\n"); */
|
||||
#ifdef BREAKPOINT_DEBUG
|
||||
printf ("Inserting breakpoints.\n");
|
||||
#endif /* BREAKPOINT_DEBUG */
|
||||
|
||||
ALL_BREAKPOINTS (b)
|
||||
if (b->enable != disabled && ! b->inserted && ! b->duplicate)
|
||||
{
|
||||
@ -262,8 +273,10 @@ insert_breakpoints ()
|
||||
val = write_memory (b->address, break_insn, sizeof break_insn);
|
||||
if (val)
|
||||
return val;
|
||||
/* printf ("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n",
|
||||
b->address, b->shadow_contents[0], b->shadow_contents[1]); */
|
||||
#ifdef BREAKPOINT_DEBUG
|
||||
printf ("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n",
|
||||
b->address, b->shadow_contents[0], b->shadow_contents[1]);
|
||||
#endif /* BREAKPOINT_DEBUG */
|
||||
b->inserted = 1;
|
||||
}
|
||||
return 0;
|
||||
@ -275,7 +288,10 @@ remove_breakpoints ()
|
||||
register struct breakpoint *b;
|
||||
int val;
|
||||
|
||||
/* printf ("Removing breakpoints.\n"); */
|
||||
#ifdef BREAKPOINT_DEBUG
|
||||
printf ("Removing breakpoints.\n");
|
||||
#endif /* BREAKPOINT_DEBUG */
|
||||
|
||||
ALL_BREAKPOINTS (b)
|
||||
if (b->inserted)
|
||||
{
|
||||
@ -283,8 +299,10 @@ remove_breakpoints ()
|
||||
if (val)
|
||||
return val;
|
||||
b->inserted = 0;
|
||||
/* printf ("Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n",
|
||||
b->address, b->shadow_contents[0], b->shadow_contents[1]); */
|
||||
#ifdef BREAKPOINT_DEBUG
|
||||
printf ("Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n",
|
||||
b->address, b->shadow_contents[0], b->shadow_contents[1]);
|
||||
#endif /* BREAKPOINT_DEBUG */
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -293,7 +311,7 @@ remove_breakpoints ()
|
||||
/* Clear the "inserted" flag in all breakpoints.
|
||||
This is done when the inferior is loaded. */
|
||||
|
||||
int
|
||||
void
|
||||
mark_breakpoints_out ()
|
||||
{
|
||||
register struct breakpoint *b;
|
||||
@ -334,12 +352,13 @@ breakpoint_cond_eval (exp)
|
||||
or -2 if breakpoint says it has deleted itself and don't stop,
|
||||
or -3 if hit a breakpoint number -3 (delete when program stops),
|
||||
or else the number of the breakpoint,
|
||||
with 0x1000000 added for a silent breakpoint. */
|
||||
with 0x1000000 added (or subtracted, for a negative return value) for
|
||||
a silent breakpoint. */
|
||||
|
||||
int
|
||||
breakpoint_stop_status (pc, frame)
|
||||
breakpoint_stop_status (pc, frame_address)
|
||||
CORE_ADDR pc;
|
||||
FRAME frame;
|
||||
FRAME_ADDR frame_address;
|
||||
{
|
||||
register struct breakpoint *b;
|
||||
register int cont = 0;
|
||||
@ -350,7 +369,7 @@ breakpoint_stop_status (pc, frame)
|
||||
ALL_BREAKPOINTS (b)
|
||||
if (b->enable != disabled && b->address == pc)
|
||||
{
|
||||
if (b->frame && b->frame != frame)
|
||||
if (b->frame && b->frame != frame_address)
|
||||
cont = -1;
|
||||
else
|
||||
{
|
||||
@ -376,11 +395,15 @@ breakpoint_stop_status (pc, frame)
|
||||
if (b->enable == temporary)
|
||||
b->enable = disabled;
|
||||
breakpoint_commands = b->commands;
|
||||
if (breakpoint_commands
|
||||
&& !strcmp ("silent", breakpoint_commands->line))
|
||||
if (b->silent
|
||||
|| (breakpoint_commands
|
||||
&& !strcmp ("silent", breakpoint_commands->line)))
|
||||
{
|
||||
breakpoint_commands = breakpoint_commands->next;
|
||||
return 0x1000000 + b->number;
|
||||
if (breakpoint_commands)
|
||||
breakpoint_commands = breakpoint_commands->next;
|
||||
return (b->number > 0 ?
|
||||
0x1000000 + b->number :
|
||||
b->number - 0x1000000);
|
||||
}
|
||||
return b->number;
|
||||
}
|
||||
@ -538,6 +561,7 @@ set_raw_breakpoint (sal)
|
||||
b->line_number = sal.line;
|
||||
b->enable = enabled;
|
||||
b->next = 0;
|
||||
b->silent = 0;
|
||||
|
||||
/* Add this breakpoint to the end of the chain
|
||||
so that a list of breakpoints will come out in order
|
||||
@ -571,7 +595,7 @@ set_momentary_breakpoint (sal, frame)
|
||||
b = set_raw_breakpoint (sal);
|
||||
b->number = -3;
|
||||
b->enable = delete;
|
||||
b->frame = frame;
|
||||
b->frame = (frame ? FRAME_FP (frame) : 0);
|
||||
}
|
||||
|
||||
void
|
||||
@ -622,14 +646,12 @@ set_breakpoint (s, line, tempflag)
|
||||
}
|
||||
|
||||
/* Set a breakpoint according to ARG (function, linenum or *address)
|
||||
and make it temporary if TEMPFLAG is nonzero.
|
||||
|
||||
LINE_NUM is for C++. */
|
||||
and make it temporary if TEMPFLAG is nonzero. */
|
||||
|
||||
static void
|
||||
break_command_1 (arg, tempflag, from_tty, line_num)
|
||||
break_command_1 (arg, tempflag, from_tty)
|
||||
char *arg;
|
||||
int tempflag, from_tty, line_num;
|
||||
int tempflag, from_tty;
|
||||
{
|
||||
struct symtabs_and_lines sals;
|
||||
struct symtab_and_line sal;
|
||||
@ -637,6 +659,7 @@ break_command_1 (arg, tempflag, from_tty, line_num)
|
||||
register struct breakpoint *b;
|
||||
char *save_arg;
|
||||
int i;
|
||||
CORE_ADDR pc;
|
||||
|
||||
sals.sals = NULL;
|
||||
sals.nelts = 0;
|
||||
@ -644,58 +667,64 @@ break_command_1 (arg, tempflag, from_tty, line_num)
|
||||
sal.line = sal.pc = sal.end = 0;
|
||||
sal.symtab = 0;
|
||||
|
||||
if (arg)
|
||||
{
|
||||
CORE_ADDR pc;
|
||||
sals = decode_line_1 (&arg, 1, 0, 0);
|
||||
/* If no arg given, or if first arg is 'if ', use the default breakpoint. */
|
||||
|
||||
if (! sals.nelts) return;
|
||||
save_arg = arg;
|
||||
for (i = 0; i < sals.nelts; i++)
|
||||
if (!arg || (arg[0] == 'i' && arg[1] == 'f'
|
||||
&& (arg[2] == ' ' || arg[2] == '\t')))
|
||||
{
|
||||
if (default_breakpoint_valid)
|
||||
{
|
||||
sal = sals.sals[i];
|
||||
if (sal.pc == 0 && sal.symtab != 0)
|
||||
{
|
||||
pc = find_line_pc (sal.symtab, sal.line);
|
||||
if (pc == 0)
|
||||
error ("No line %d in file \"%s\".",
|
||||
sal.line, sal.symtab->filename);
|
||||
}
|
||||
else pc = sal.pc;
|
||||
|
||||
while (*arg)
|
||||
{
|
||||
if (arg[0] == 'i' && arg[1] == 'f'
|
||||
&& (arg[2] == ' ' || arg[2] == '\t'))
|
||||
cond = (struct expression *) parse_c_1 ((arg += 2, &arg),
|
||||
block_for_pc (pc), 0);
|
||||
else
|
||||
error ("Junk at end of arguments.");
|
||||
}
|
||||
arg = save_arg;
|
||||
sals.sals[i].pc = pc;
|
||||
sals.sals = (struct symtab_and_line *)
|
||||
malloc (sizeof (struct symtab_and_line));
|
||||
sal.pc = default_breakpoint_address;
|
||||
sal.line = default_breakpoint_line;
|
||||
sal.symtab = default_breakpoint_symtab;
|
||||
sals.sals[0] = sal;
|
||||
sals.nelts = 1;
|
||||
}
|
||||
}
|
||||
else if (default_breakpoint_valid)
|
||||
{
|
||||
sals.sals = (struct symtab_and_line *) malloc (sizeof (struct symtab_and_line));
|
||||
sal.pc = default_breakpoint_address;
|
||||
sal.line = default_breakpoint_line;
|
||||
sal.symtab = default_breakpoint_symtab;
|
||||
sals.sals[0] = sal;
|
||||
sals.nelts = 1;
|
||||
else
|
||||
error ("No default breakpoint address now.");
|
||||
}
|
||||
else
|
||||
error ("No default breakpoint address now.");
|
||||
if (default_breakpoint_valid)
|
||||
sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
|
||||
default_breakpoint_line);
|
||||
else
|
||||
sals = decode_line_1 (&arg, 1, 0, 0);
|
||||
|
||||
if (! sals.nelts)
|
||||
return;
|
||||
|
||||
save_arg = arg;
|
||||
for (i = 0; i < sals.nelts; i++)
|
||||
{
|
||||
sal = sals.sals[i];
|
||||
if (sal.pc == 0 && sal.symtab != 0)
|
||||
{
|
||||
pc = find_line_pc (sal.symtab, sal.line);
|
||||
if (pc == 0)
|
||||
error ("No line %d in file \"%s\".",
|
||||
sal.line, sal.symtab->filename);
|
||||
}
|
||||
else
|
||||
pc = sal.pc;
|
||||
|
||||
while (arg && *arg)
|
||||
{
|
||||
if (arg[0] == 'i' && arg[1] == 'f'
|
||||
&& (arg[2] == ' ' || arg[2] == '\t'))
|
||||
cond = (struct expression *) parse_c_1 ((arg += 2, &arg),
|
||||
block_for_pc (pc), 0);
|
||||
else
|
||||
error ("Junk at end of arguments.");
|
||||
}
|
||||
arg = save_arg;
|
||||
sals.sals[i].pc = pc;
|
||||
}
|
||||
|
||||
for (i = 0; i < sals.nelts; i++)
|
||||
{
|
||||
sal = sals.sals[i];
|
||||
sal.line += line_num; /** C++ **/
|
||||
if (line_num != 0)
|
||||
{ /* get the pc for a particular line */
|
||||
sal.pc = find_line_pc (sal.symtab, sal.line);
|
||||
}
|
||||
|
||||
if (from_tty)
|
||||
describe_other_breakpoints (sal.pc);
|
||||
@ -711,6 +740,12 @@ break_command_1 (arg, tempflag, from_tty, line_num)
|
||||
printf (": file %s, line %d.", b->symtab->filename, b->line_number);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
if (sals.nelts > 1)
|
||||
{
|
||||
printf ("Multiple breakpoints were set.\n");
|
||||
printf ("Use the \"delete\" command to delete unwanted breakpoints.\n");
|
||||
}
|
||||
free (sals.sals);
|
||||
}
|
||||
|
||||
@ -719,7 +754,7 @@ break_command (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
break_command_1 (arg, 0, from_tty, 0);
|
||||
break_command_1 (arg, 0, from_tty);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -727,7 +762,62 @@ tbreak_command (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
break_command_1 (arg, 1, from_tty, 0);
|
||||
break_command_1 (arg, 1, from_tty);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper routine for the until_command routine in infcmd.c. Here
|
||||
* because it uses the mechanisms of breakpoints.
|
||||
*/
|
||||
void
|
||||
until_break_command(arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
struct symtabs_and_lines sals;
|
||||
struct symtab_and_line sal;
|
||||
FRAME frame = get_current_frame ();
|
||||
FRAME prev_frame = get_prev_frame (frame);
|
||||
|
||||
/* Set a breakpoint where the user wants it and at return from
|
||||
this function */
|
||||
|
||||
if (default_breakpoint_valid)
|
||||
sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
|
||||
default_breakpoint_line);
|
||||
else
|
||||
sals = decode_line_1 (&arg, 1, 0, 0);
|
||||
|
||||
if (sals.nelts != 1)
|
||||
error ("Couldn't get information on specified line.");
|
||||
|
||||
sal = sals.sals[0];
|
||||
free (sals.sals); /* malloc'd, so freed */
|
||||
|
||||
if (*arg)
|
||||
error ("Junk at end of arguments.");
|
||||
|
||||
if (sal.pc == 0 && sal.symtab != 0)
|
||||
sal.pc = find_line_pc (sal.symtab, sal.line);
|
||||
|
||||
if (sal.pc == 0)
|
||||
error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename);
|
||||
|
||||
set_momentary_breakpoint (sal, 0);
|
||||
|
||||
/* Keep within the current frame */
|
||||
|
||||
if (prev_frame)
|
||||
{
|
||||
struct frame_info *fi;
|
||||
|
||||
fi = get_frame_info (prev_frame);
|
||||
sal = find_pc_line (fi->pc, 0);
|
||||
sal.pc = fi->pc;
|
||||
set_momentary_breakpoint (sal, prev_frame);
|
||||
}
|
||||
|
||||
proceed (-1, -1, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -742,7 +832,9 @@ clear_command (arg, from_tty)
|
||||
int i;
|
||||
|
||||
if (arg)
|
||||
sals = decode_line_spec (arg, 1);
|
||||
{
|
||||
sals = decode_line_spec (arg, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sals.sals = (struct symtab_and_line *) malloc (sizeof (struct symtab_and_line));
|
||||
@ -801,7 +893,7 @@ clear_command (arg, from_tty)
|
||||
}
|
||||
free (sals.sals);
|
||||
}
|
||||
|
||||
|
||||
/* Delete breakpoint number BNUM if it is a `delete' breakpoint.
|
||||
This is called after breakpoint BNUM has been hit.
|
||||
Also delete any breakpoint numbered -3 unless there are breakpoint
|
||||
@ -851,7 +943,7 @@ delete_breakpoint (bpt)
|
||||
free (bpt);
|
||||
}
|
||||
|
||||
void map_breakpoint_numbers ();
|
||||
static void map_breakpoint_numbers ();
|
||||
|
||||
static void
|
||||
delete_command (arg, from_tty)
|
||||
@ -1048,19 +1140,41 @@ enable_delete_command (args)
|
||||
map_breakpoint_numbers (args, enable_delete_breakpoint);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use default_breakpoint_'s, or nothing if they aren't valid.
|
||||
*/
|
||||
struct symtabs_and_lines
|
||||
decode_line_spec_1 (string, funfirstline)
|
||||
char *string;
|
||||
int funfirstline;
|
||||
{
|
||||
struct symtabs_and_lines sals;
|
||||
if (string == 0)
|
||||
error ("Empty line specification.");
|
||||
if (default_breakpoint_valid)
|
||||
sals = decode_line_1 (&string, funfirstline,
|
||||
default_breakpoint_symtab, default_breakpoint_line);
|
||||
else
|
||||
sals = decode_line_1 (&string, funfirstline, 0, 0);
|
||||
if (*string)
|
||||
error ("Junk at end of line specification: %s", string);
|
||||
return sals;
|
||||
}
|
||||
|
||||
|
||||
/* Chain containing all defined enable commands. */
|
||||
|
||||
struct cmd_list_element *enablelist;
|
||||
extern struct cmd_list_element
|
||||
*enablelist, *disablelist,
|
||||
*deletelist, *enablebreaklist;
|
||||
|
||||
extern struct cmd_list_element *cmdlist;
|
||||
|
||||
static
|
||||
initialize ()
|
||||
void
|
||||
_initialize_breakpoint ()
|
||||
{
|
||||
breakpoint_chain = 0;
|
||||
breakpoint_count = 0;
|
||||
enablelist = 0;
|
||||
|
||||
add_com ("ignore", class_breakpoint, ignore_command,
|
||||
"Set ignore-count of breakpoint number N to COUNT.");
|
||||
@ -1068,6 +1182,7 @@ initialize ()
|
||||
add_com ("commands", class_breakpoint, commands_command,
|
||||
"Set commands to be executed when a breakpoint is hit.\n\
|
||||
Give breakpoint number as argument after \"commands\".\n\
|
||||
With no argument, the targeted breakpoint is the last one set.\n\
|
||||
The commands themselves follow starting on the next line.\n\
|
||||
Type a line containing \"end\" to indicate the end of them.\n\
|
||||
Give \"silent\" as the first line to make the breakpoint silent;\n\
|
||||
@ -1085,35 +1200,80 @@ so it will be disabled when hit. Equivalent to \"break\" followed\n\
|
||||
by using \"enable once\" on the breakpoint number.");
|
||||
|
||||
add_prefix_cmd ("enable", class_breakpoint, enable_command,
|
||||
"Enable some breakpoints. Give breakpoint numbers as arguments.\n\
|
||||
"Enable some breakpoints or auto-display expressions.\n\
|
||||
Give breakpoint numbers (separated by spaces) as arguments.\n\
|
||||
With no subcommand, breakpoints are enabled until you command otherwise.\n\
|
||||
This is used to cancel the effect of the \"disable\" command.\n\
|
||||
With a subcommand you can enable temporarily.",
|
||||
With a subcommand you can enable temporarily.\n\
|
||||
\n\
|
||||
The \"display\" subcommand applies to auto-displays instead of breakpoints.",
|
||||
&enablelist, "enable ", 1, &cmdlist);
|
||||
|
||||
add_cmd ("delete", 0, enable_delete_command,
|
||||
add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command,
|
||||
"Enable some breakpoints or auto-display expressions.\n\
|
||||
Give breakpoint numbers (separated by spaces) as arguments.\n\
|
||||
With no subcommand, breakpoints are enabled until you command otherwise.\n\
|
||||
This is used to cancel the effect of the \"disable\" command.\n\
|
||||
May be abbreviates to simply \"enable\".\n\
|
||||
With a subcommand you can enable temporarily.",
|
||||
&enablebreaklist, "enable breakpoints ", 1, &enablelist);
|
||||
|
||||
add_cmd ("once", no_class, enable_once_command,
|
||||
"Enable breakpoints for one hit. Give breakpoint numbers.\n\
|
||||
If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\
|
||||
See the \"tbreak\" command which sets a breakpoint and enables it once.",
|
||||
&enablebreaklist);
|
||||
|
||||
add_cmd ("delete", no_class, enable_delete_command,
|
||||
"Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
|
||||
If a breakpoint is hit while enabled in this fashion, it is deleted.",
|
||||
&enablebreaklist);
|
||||
|
||||
add_cmd ("delete", no_class, enable_delete_command,
|
||||
"Enable breakpoints and delete when hit. Give breakpoint numbers.\n\
|
||||
If a breakpoint is hit while enabled in this fashion, it is deleted.",
|
||||
&enablelist);
|
||||
|
||||
add_cmd ("once", 0, enable_once_command,
|
||||
add_cmd ("once", no_class, enable_once_command,
|
||||
"Enable breakpoints for one hit. Give breakpoint numbers.\n\
|
||||
If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\
|
||||
See the \"tbreak\" command which sets a breakpoint and enables it once.",
|
||||
&enablelist);
|
||||
|
||||
add_com ("disable", class_breakpoint, disable_command,
|
||||
"Disable some breakpoints. Give breakpoint numbers as arguments.\n\
|
||||
With no arguments, disable all breakpoints.\n\
|
||||
A disabled breakpoint is not forgotten,\n\
|
||||
but it has no effect until enabled again.");
|
||||
add_prefix_cmd ("disable", class_breakpoint, disable_command,
|
||||
"Disable some breakpoints or auto-display expressions.\n\
|
||||
Arguments are breakpoint numbers with spaces in between.\n\
|
||||
To disable all breakpoints, give no argument.\n\
|
||||
A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
|
||||
\n\
|
||||
The \"display\" subcommand applies to auto-displays instead of breakpoints.",
|
||||
&disablelist, "disable ", 1, &cmdlist);
|
||||
add_com_alias ("dis", "disable", class_breakpoint, 1);
|
||||
|
||||
add_com ("delete", class_breakpoint, delete_command,
|
||||
"Delete breakpoints, specifying breakpoint numbers; or all breakpoints.\n\
|
||||
add_abbrev_cmd ("breakpoints", class_breakpoint, disable_command,
|
||||
"Disable some breakpoints or auto-display expressions.\n\
|
||||
Arguments are breakpoint numbers with spaces in between.\n\
|
||||
To delete all breakpoints, give no argument.");
|
||||
To disable all breakpoints, give no argument.\n\
|
||||
A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
|
||||
This command may be abbreviated \"disable\".",
|
||||
&disablelist);
|
||||
|
||||
add_prefix_cmd ("delete", class_breakpoint, delete_command,
|
||||
"Delete some breakpoints or auto-display expressions.\n\
|
||||
Arguments are breakpoint numbers with spaces in between.\n\
|
||||
To delete all breakpoints, give no argument.\n\
|
||||
\n\
|
||||
The \"display\" subcommand applies to auto-displays instead of breakpoints.",
|
||||
&deletelist, "delete ", 1, &cmdlist);
|
||||
add_com_alias ("d", "delete", class_breakpoint, 1);
|
||||
add_com_alias ("unset", "delete", class_breakpoint, 1);
|
||||
|
||||
add_abbrev_cmd ("breakpoints", class_breakpoint, delete_command,
|
||||
"Delete some breakpoints or auto-display expressions.\n\
|
||||
Arguments are breakpoint numbers with spaces in between.\n\
|
||||
To delete all breakpoints, give no argument.\n\
|
||||
This command may be abbreviated \"delete\".",
|
||||
&deletelist);
|
||||
|
||||
add_com ("clear", class_breakpoint, clear_command,
|
||||
"Clear breakpoint at specified line or function.\n\
|
||||
@ -1152,4 +1312,3 @@ Convenience variable \"$_\" and default examine address for \"x\"\n\
|
||||
are set to the address of the last breakpoint listed.");
|
||||
}
|
||||
|
||||
END_FILE
|
||||
|
14
gdb/c.h
14
gdb/c.h
@ -1,14 +0,0 @@
|
||||
#include "b.h"
|
||||
|
||||
inline c ()
|
||||
{
|
||||
Foo x = 1;
|
||||
{
|
||||
Foo y = 2;
|
||||
{
|
||||
b ();
|
||||
}
|
||||
Foo z = 3;
|
||||
}
|
||||
Foo w = 4;
|
||||
}
|
319
gdb/coffread.c
319
gdb/coffread.c
@ -2,7 +2,7 @@
|
||||
Design and support routines derived from dbxread.c, and UMAX COFF
|
||||
specific routines written 9/1/87 by David D. Johnson, Brown University.
|
||||
Revised 11/27/87 ddj@cs.brown.edu
|
||||
Copyright (C) 1987, 1988 Free Software Foundation, Inc.
|
||||
Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
@ -24,15 +24,22 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#ifdef COFF_FORMAT
|
||||
#include "initialize.h"
|
||||
#include "symtab.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <a.out.h>
|
||||
#include <stdio.h>
|
||||
#include <obstack.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
/* Avoid problems with A/UX predefine */
|
||||
#undef aux
|
||||
|
||||
static void add_symbol_to_list ();
|
||||
static void read_coff_symtab ();
|
||||
static void patch_opaque_types ();
|
||||
@ -52,8 +59,8 @@ static int init_lineno ();
|
||||
static void enter_linenos ();
|
||||
|
||||
extern void free_all_symtabs ();
|
||||
extern void free_all_psymtabs ();
|
||||
|
||||
START_FILE
|
||||
|
||||
/* Name of source file whose symbol data we are now processing.
|
||||
This comes from a symbol named ".file". */
|
||||
@ -184,12 +191,17 @@ coff_lookup_type (index)
|
||||
{
|
||||
if (index >= type_vector_length)
|
||||
{
|
||||
int old_vector_length = type_vector_length;
|
||||
|
||||
type_vector_length *= 2;
|
||||
if (type_vector_length < index) {
|
||||
type_vector_length = index * 2;
|
||||
}
|
||||
type_vector = (struct typevector *)
|
||||
xrealloc (type_vector, sizeof (struct typevector)
|
||||
+ type_vector_length * sizeof (struct type *));
|
||||
bzero (&type_vector->type[type_vector_length / 2],
|
||||
type_vector_length * sizeof (struct type *) / 2);
|
||||
bzero (&type_vector->type[ old_vector_length ],
|
||||
(type_vector_length - old_vector_length) * sizeof(struct type *));
|
||||
}
|
||||
return &type_vector->type[index];
|
||||
}
|
||||
@ -359,6 +371,7 @@ record_line (line, pc)
|
||||
int line;
|
||||
CORE_ADDR pc;
|
||||
{
|
||||
struct linetable_entry *e;
|
||||
/* Make sure line vector is big enough. */
|
||||
|
||||
if (line_vector_index + 2 >= line_vector_length)
|
||||
@ -366,21 +379,12 @@ record_line (line, pc)
|
||||
line_vector_length *= 2;
|
||||
line_vector = (struct linetable *)
|
||||
xrealloc (line_vector, sizeof (struct linetable)
|
||||
+ line_vector_length * sizeof (int));
|
||||
+ (line_vector_length
|
||||
* sizeof (struct linetable_entry)));
|
||||
}
|
||||
|
||||
/* If this line is not continguous with previous one recorded,
|
||||
all lines between subsequent line and current one are same pc.
|
||||
Add one item to line vector, and if more than one line skipped,
|
||||
record a line-number entry for it. */
|
||||
if (prev_line_number > 0 && line != prev_line_number + 1)
|
||||
line_vector->item[line_vector_index++] = pc;
|
||||
if (prev_line_number < 0 || line > prev_line_number + 2)
|
||||
line_vector->item[line_vector_index++] = - line;
|
||||
prev_line_number = line;
|
||||
|
||||
/* Record the core address of the line. */
|
||||
line_vector->item[line_vector_index++] = pc;
|
||||
e = line_vector->item + line_vector_index++;
|
||||
e->line = line; e->pc = pc;
|
||||
}
|
||||
|
||||
/* Start a new symtab for a new source file.
|
||||
@ -402,7 +406,8 @@ start_symtab ()
|
||||
line_vector_length = 1000;
|
||||
prev_line_number = -2; /* Force first line number to be explicit */
|
||||
line_vector = (struct linetable *)
|
||||
xmalloc (sizeof (struct linetable) + line_vector_length * sizeof (int));
|
||||
xmalloc (sizeof (struct linetable)
|
||||
+ line_vector_length * sizeof (struct linetable_entry));
|
||||
}
|
||||
|
||||
/* Save the vital information for use when closing off the current file.
|
||||
@ -438,18 +443,31 @@ end_symtab ()
|
||||
if (context_stack)
|
||||
{
|
||||
cstk = context_stack;
|
||||
context_stack = 0;
|
||||
/* Make a block for the local symbols within. */
|
||||
finish_block (cstk->name, &local_symbols, cstk->old_blocks,
|
||||
cstk->start_addr, cur_src_end_addr);
|
||||
free (cstk);
|
||||
}
|
||||
|
||||
/* Ignore a file that has no functions with real debugging info. */
|
||||
if (pending_blocks == 0 && file_symbols == 0 && global_symbols == 0)
|
||||
{
|
||||
free (line_vector);
|
||||
line_vector = 0;
|
||||
line_vector_length = -1;
|
||||
last_source_file = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the two top-level blocks for this file. */
|
||||
finish_block (0, &file_symbols, 0, cur_src_start_addr, cur_src_end_addr);
|
||||
finish_block (0, &global_symbols, 0, cur_src_start_addr, cur_src_end_addr);
|
||||
|
||||
/* Create the blockvector that points to all the file's blocks. */
|
||||
blockvector = make_blockvector ();
|
||||
|
||||
/* Now create the symtab object this source file. */
|
||||
|
||||
/* Now create the symtab object for this source file. */
|
||||
symtab = (struct symtab *) xmalloc (sizeof (struct symtab));
|
||||
symtab->free_ptr = 0;
|
||||
|
||||
@ -460,7 +478,8 @@ end_symtab ()
|
||||
lv = line_vector;
|
||||
lv->nitems = line_vector_index;
|
||||
symtab->linetable = (struct linetable *)
|
||||
xrealloc (lv, sizeof (struct linetable) + lv->nitems * sizeof (int));
|
||||
xrealloc (lv, (sizeof (struct linetable)
|
||||
+ lv->nitems * sizeof (struct linetable_entry)));
|
||||
symtab->nlines = 0;
|
||||
symtab->line_charpos = 0;
|
||||
|
||||
@ -468,6 +487,7 @@ end_symtab ()
|
||||
symtab->next = symtab_list;
|
||||
symtab_list = symtab;
|
||||
|
||||
/* Reinitialize for beginning of new file. */
|
||||
line_vector = 0;
|
||||
line_vector_length = -1;
|
||||
last_source_file = 0;
|
||||
@ -525,6 +545,21 @@ record_misc_function (name, address)
|
||||
misc_count++;
|
||||
}
|
||||
|
||||
/* if we see a function symbol, we do record_misc_function.
|
||||
* however, if it turns out the next symbol is '.bf', then
|
||||
* we call here to undo the misc definition
|
||||
*/
|
||||
static void
|
||||
unrecord_misc_function ()
|
||||
{
|
||||
if (misc_bunch_index == 0)
|
||||
error ("Internal error processing symbol table, at symbol %d.",
|
||||
symnum);
|
||||
misc_bunch_index--;
|
||||
misc_count--;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
compare_misc_functions (fn1, fn2)
|
||||
struct misc_function *fn1, *fn2;
|
||||
@ -621,8 +656,9 @@ sort_syms ()
|
||||
for (i = 0; i < nbl; i++)
|
||||
{
|
||||
b = BLOCKVECTOR_BLOCK (bv, i);
|
||||
qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
|
||||
sizeof (struct symbol *), compare_symbols);
|
||||
if (BLOCK_SHOULD_SORT (b))
|
||||
qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
|
||||
sizeof (struct symbol *), compare_symbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -648,6 +684,9 @@ symbol_file_command (name)
|
||||
{
|
||||
if (symtab_list && !query ("Discard symbol table? ", 0))
|
||||
error ("Not confirmed.");
|
||||
if (symfile)
|
||||
free (symfile);
|
||||
symfile = 0;
|
||||
free_all_symtabs ();
|
||||
return;
|
||||
}
|
||||
@ -689,6 +728,8 @@ symbol_file_command (name)
|
||||
/* Throw away the old symbol table. */
|
||||
|
||||
free_all_symtabs ();
|
||||
free_all_psymtabs (); /* Make sure that partial_symtab_list */
|
||||
/* is 0 also. */
|
||||
|
||||
num_sections = file_hdr.f_nscns;
|
||||
symtab_offset = file_hdr.f_symptr;
|
||||
@ -783,23 +824,35 @@ read_coff_symtab (desc, nsyms)
|
||||
int desc;
|
||||
int nsyms;
|
||||
{
|
||||
FILE *stream = fdopen (desc, "r");
|
||||
int newfd; /* Avoid multiple closes on same desc */
|
||||
FILE *stream;
|
||||
register struct context_stack *new;
|
||||
struct coff_symbol coff_symbol;
|
||||
register struct coff_symbol *cs = &coff_symbol;
|
||||
static SYMENT main_sym;
|
||||
static AUXENT main_aux;
|
||||
struct coff_symbol fcn_cs_saved;
|
||||
static SYMENT fcn_sym_saved;
|
||||
static AUXENT fcn_aux_saved;
|
||||
|
||||
int num_object_files = 0;
|
||||
int next_file_symnum;
|
||||
int next_file_symnum = -1;
|
||||
char *filestring;
|
||||
int depth;
|
||||
int fcn_first_line;
|
||||
int fcn_last_line;
|
||||
int fcn_start_addr;
|
||||
long fcn_line_ptr;
|
||||
struct cleanup *old_chain;
|
||||
int fclose();
|
||||
|
||||
newfd = dup (desc);
|
||||
if (newfd == -1)
|
||||
fatal ("Too many open files");
|
||||
stream = fdopen (newfd, "r");
|
||||
|
||||
old_chain = make_cleanup (free_all_symtabs, 0);
|
||||
make_cleanup (fclose, stream);
|
||||
nlist_stream_global = stream;
|
||||
nlist_nsyms_global = nsyms;
|
||||
last_source_file = 0;
|
||||
@ -835,26 +888,19 @@ read_coff_symtab (desc, nsyms)
|
||||
if (!last_source_file && cs->c_type != T_NULL && cs->c_secnum == N_DEBUG)
|
||||
complete_symtab (filestring, 0, 0);
|
||||
|
||||
if (ISFCN (cs->c_type))
|
||||
/* Typedefs should not be treated as symbol definitions. */
|
||||
if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF)
|
||||
{
|
||||
/*
|
||||
* gdb expects all functions to also be in misc_function
|
||||
* list -- why not...
|
||||
/* record as misc function. if we get '.bf' next,
|
||||
* then we undo this step
|
||||
*/
|
||||
record_misc_function (cs->c_name, cs->c_value);
|
||||
|
||||
fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr;
|
||||
within_function = 1;
|
||||
|
||||
new = (struct context_stack *)
|
||||
xmalloc (sizeof (struct context_stack));
|
||||
new->depth = depth = 0;
|
||||
new->next = 0;
|
||||
context_stack = new;
|
||||
new->locals = 0;
|
||||
new->old_blocks = pending_blocks;
|
||||
new->start_addr = cs->c_value;
|
||||
new->name = process_coff_symbol (cs, &main_aux);
|
||||
fcn_start_addr = cs->c_value;
|
||||
fcn_cs_saved = *cs;
|
||||
fcn_sym_saved = main_sym;
|
||||
fcn_aux_saved = main_aux;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -889,79 +935,84 @@ read_coff_symtab (desc, nsyms)
|
||||
num_object_files++;
|
||||
break;
|
||||
|
||||
case C_STAT:
|
||||
if (cs->c_name[0] == '.') {
|
||||
if (strcmp (cs->c_name, _TEXT) == 0) {
|
||||
if (num_object_files == 1) {
|
||||
/* last address of startup file */
|
||||
first_object_file_end = cs->c_value +
|
||||
main_aux.x_scn.x_scnlen;
|
||||
}
|
||||
/* for some reason the old code didn't do
|
||||
* this if this section entry had
|
||||
* main_aux.x_scn.x_nlinno equal to 0
|
||||
*/
|
||||
complete_symtab (filestring, cs->c_value,
|
||||
main_aux.x_scn.x_scnlen);
|
||||
}
|
||||
/* flush rest of '.' symbols */
|
||||
break;
|
||||
}
|
||||
/* fall in for static symbols that don't start with '.' */
|
||||
case C_EXT:
|
||||
if (cs->c_secnum == N_ABS && strcmp (cs->c_name, _ETEXT) == 0)
|
||||
{
|
||||
end_of_text_addr = cs->c_value;
|
||||
}
|
||||
if (cs->c_type == T_NULL)
|
||||
{
|
||||
if (cs->c_secnum <= 1) /* text or abs */
|
||||
{
|
||||
record_misc_function (cs->c_name, cs->c_value);
|
||||
break;
|
||||
}
|
||||
else
|
||||
cs->c_type = T_INT;
|
||||
}
|
||||
(void) process_coff_symbol (cs, &main_aux);
|
||||
break;
|
||||
|
||||
case C_STAT:
|
||||
if (cs->c_type == T_NULL && cs->c_secnum > N_UNDEF)
|
||||
{
|
||||
if (strcmp (cs->c_name, _TEXT) == 0)
|
||||
{
|
||||
if (num_object_files == 1)
|
||||
{
|
||||
/* Record end address of first file, crt0.s */
|
||||
first_object_file_end =
|
||||
cs->c_value + main_aux.x_scn.x_scnlen;
|
||||
}
|
||||
/*
|
||||
* Fill in missing information for debugged
|
||||
* object file only if we have line number info.
|
||||
*/
|
||||
if (main_aux.x_scn.x_nlinno > 0)
|
||||
{
|
||||
complete_symtab (filestring, cs->c_value,
|
||||
main_aux.x_scn.x_scnlen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (strcmp (cs->c_name, _DATA) == 0)
|
||||
break;
|
||||
else if (strcmp (cs->c_name, _BSS) == 0)
|
||||
break;
|
||||
|
||||
/* get rid of assembly labels here */
|
||||
/* record_misc_function (cs->c_name, cs->c_value); */
|
||||
break;
|
||||
}
|
||||
if (cs->c_sclass == C_EXT &&
|
||||
cs->c_secnum == N_ABS &&
|
||||
strcmp (cs->c_name, _ETEXT) == 0)
|
||||
end_of_text_addr = cs->c_value;
|
||||
if (cs->c_type == T_NULL) {
|
||||
if (cs->c_secnum <= 1) { /* text or abs */
|
||||
record_misc_function (cs->c_name, cs->c_value);
|
||||
break;
|
||||
} else {
|
||||
cs->c_type = T_INT;
|
||||
}
|
||||
}
|
||||
(void) process_coff_symbol (cs, &main_aux);
|
||||
break;
|
||||
|
||||
case C_FCN:
|
||||
if (strcmp (cs->c_name, ".bf") == 0)
|
||||
{
|
||||
unrecord_misc_function ();
|
||||
|
||||
within_function = 1;
|
||||
|
||||
/* value contains address of first non-init type code */
|
||||
/* main_aux.x_sym.x_misc.x_lnsz.x_lnno
|
||||
contains line number of '{' } */
|
||||
fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
|
||||
|
||||
new = (struct context_stack *)
|
||||
xmalloc (sizeof (struct context_stack));
|
||||
new->depth = depth = 0;
|
||||
new->next = 0;
|
||||
context_stack = new;
|
||||
new->locals = 0;
|
||||
new->old_blocks = pending_blocks;
|
||||
new->start_addr = fcn_start_addr;
|
||||
fcn_cs_saved.c_name = getsymname (&fcn_sym_saved);
|
||||
new->name = process_coff_symbol (&fcn_cs_saved,
|
||||
&fcn_aux_saved);
|
||||
}
|
||||
else if (strcmp (cs->c_name, ".ef") == 0)
|
||||
{
|
||||
/* value contains address of exit/return from function */
|
||||
/* round it up to next multiple of 16 */
|
||||
cs->c_value = (cs->c_value + 15) & -16;
|
||||
/* the value of .ef is the address of epilogue code;
|
||||
* not useful for gdb
|
||||
*/
|
||||
/* { main_aux.x_sym.x_misc.x_lnsz.x_lnno
|
||||
contains number of lines to '}' */
|
||||
fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
|
||||
enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line);
|
||||
|
||||
new = context_stack;
|
||||
|
||||
if (new == 0)
|
||||
error ("Invalid symbol data; .bf/.ef/.bb/.eb symbol mismatch, at symbol %d.",
|
||||
symnum);
|
||||
|
||||
finish_block (new->name, &local_symbols, new->old_blocks,
|
||||
new->start_addr, cs->c_value);
|
||||
new->start_addr,
|
||||
fcn_cs_saved.c_value +
|
||||
fcn_aux_saved.x_sym.x_misc.x_fsize);
|
||||
context_stack = 0;
|
||||
within_function = 0;
|
||||
free (new);
|
||||
@ -987,7 +1038,8 @@ read_coff_symtab (desc, nsyms)
|
||||
{
|
||||
new = context_stack;
|
||||
if (new == 0 || depth != new->depth)
|
||||
error ("Invalid symbol data: .bb/.eb symbol mismatch.");
|
||||
error ("Invalid symbol data: .bb/.eb symbol mismatch at symbol %d.",
|
||||
symnum);
|
||||
if (local_symbols && context_stack->next)
|
||||
{
|
||||
/* Make a block for the local symbols within. */
|
||||
@ -1027,12 +1079,25 @@ read_file_hdr (chan, file_hdr)
|
||||
|
||||
switch (file_hdr->f_magic)
|
||||
{
|
||||
#ifdef NS32GMAGIC
|
||||
case NS32GMAGIC:
|
||||
case NS32SMAGIC:
|
||||
#endif
|
||||
#ifdef I386MAGIC
|
||||
case I386MAGIC:
|
||||
#endif
|
||||
return file_hdr->f_nsyms;
|
||||
|
||||
|
||||
default:
|
||||
#ifdef BADMAG
|
||||
if (BADMAG(file_hdr))
|
||||
return -1;
|
||||
else
|
||||
return file_hdr->f_nsyms;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1107,15 +1172,22 @@ init_stringtab (chan, offset)
|
||||
long buffer;
|
||||
int val;
|
||||
|
||||
if (stringtab)
|
||||
{
|
||||
free (stringtab);
|
||||
stringtab = NULL;
|
||||
}
|
||||
|
||||
if (lseek (chan, offset, 0) < 0)
|
||||
return -1;
|
||||
|
||||
val = myread (chan, (char *)&buffer, sizeof buffer);
|
||||
if (val != sizeof buffer)
|
||||
return -1;
|
||||
|
||||
if (stringtab)
|
||||
free (stringtab);
|
||||
/* If no string table is needed, then the file may end immediately
|
||||
after the symbols. Just return with `stringtab' set to null. */
|
||||
if (val != sizeof buffer || buffer == 0)
|
||||
return 0;
|
||||
|
||||
stringtab = (char *) xmalloc (buffer);
|
||||
if (stringtab == NULL)
|
||||
return -1;
|
||||
@ -1166,9 +1238,11 @@ getfilename (aux_entry)
|
||||
char *result;
|
||||
extern char *rindex ();
|
||||
|
||||
#ifndef COFF_NO_LONG_FILE_NAMES
|
||||
if (aux_entry->x_file.x_foff != 0)
|
||||
strcpy (buffer, stringtab + aux_entry->x_file.x_foff);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN);
|
||||
buffer[FILNMLEN] = '\0';
|
||||
@ -1365,8 +1439,8 @@ process_coff_symbol (cs, aux)
|
||||
|
||||
if (ISFCN (cs->c_type))
|
||||
{
|
||||
SYMBOL_TYPE (sym)
|
||||
= lookup_function_type (decode_function_type (cs, cs->c_type, aux));
|
||||
SYMBOL_TYPE (sym) =
|
||||
lookup_function_type (decode_function_type (cs, cs->c_type, aux));
|
||||
SYMBOL_CLASS (sym) = LOC_BLOCK;
|
||||
if (cs->c_sclass == C_STAT)
|
||||
add_symbol_to_list (sym, &file_symbols);
|
||||
@ -1571,8 +1645,8 @@ decode_base_type (cs, c_type, aux)
|
||||
switch (c_type)
|
||||
{
|
||||
case T_NULL:
|
||||
/* shouldn't show up here */
|
||||
break;
|
||||
/* shows up with "void (*foo)();" structure members */
|
||||
return builtin_type_void;
|
||||
|
||||
case T_ARG:
|
||||
/* shouldn't show up here */
|
||||
@ -1691,12 +1765,13 @@ read_struct_type (index, length, lastsym)
|
||||
register struct coff_symbol *ms = &member_sym;
|
||||
SYMENT sub_sym;
|
||||
AUXENT sub_aux;
|
||||
int done = 0;
|
||||
|
||||
type = coff_alloc_type (index);
|
||||
TYPE_CODE (type) = TYPE_CODE_STRUCT;
|
||||
TYPE_LENGTH (type) = length;
|
||||
|
||||
while (symnum < lastsym && symnum < nlist_nsyms_global)
|
||||
while (!done && symnum < lastsym && symnum < nlist_nsyms_global)
|
||||
{
|
||||
read_one_sym (ms, &sub_sym, &sub_aux);
|
||||
name = ms->c_name;
|
||||
@ -1736,6 +1811,7 @@ read_struct_type (index, length, lastsym)
|
||||
break;
|
||||
|
||||
case C_EOS:
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1829,23 +1905,48 @@ read_enum_type (index, length, lastsym)
|
||||
{
|
||||
SYMBOL_TYPE (syms->symbol) = type;
|
||||
TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (syms->symbol);
|
||||
TYPE_FIELD_VALUE (type, n) = SYMBOL_VALUE (syms->symbol);
|
||||
TYPE_FIELD_BITPOS (type, n) = 0;
|
||||
TYPE_FIELD_VALUE (type, n) = 0;
|
||||
TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (syms->symbol);
|
||||
TYPE_FIELD_BITSIZE (type, n) = 0;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static
|
||||
initialize ()
|
||||
/* This function is really horrible, but to avoid it, there would need
|
||||
to be more filling in of forward references. THIS SHOULD BE MOVED
|
||||
OUT OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED. */
|
||||
int
|
||||
fill_in_vptr_fieldno (type)
|
||||
struct type *type;
|
||||
{
|
||||
if (TYPE_VPTR_FIELDNO (type) < 0)
|
||||
TYPE_VPTR_FIELDNO (type) =
|
||||
fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1));
|
||||
return TYPE_VPTR_FIELDNO (type);
|
||||
}
|
||||
|
||||
/* partial symbol tables are not implemented in coff, therefore
|
||||
block_for_pc() (and others) will never decide to call this. */
|
||||
|
||||
extern struct symtab *
|
||||
psymtab_to_symtab ()
|
||||
{
|
||||
fatal ("error: Someone called psymtab_to_symtab\n");
|
||||
}
|
||||
|
||||
/* These will stay zero all the time */
|
||||
struct partial_symbol *global_psymbols, *static_psymbols;
|
||||
|
||||
_initialize_coff ()
|
||||
{
|
||||
symfile = 0;
|
||||
|
||||
static_psymbols = global_psymbols = (struct partial_symbol *) 0;
|
||||
|
||||
add_com ("symbol-file", class_files, symbol_file_command,
|
||||
"Load symbol table (in coff format) from executable file FILE.");
|
||||
}
|
||||
|
||||
END_FILE
|
||||
|
||||
#endif /* COFF_FORMAT */
|
||||
|
||||
|
354
gdb/command.c
354
gdb/command.c
@ -104,6 +104,7 @@ what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
|
||||
#include "command.h"
|
||||
#include "defs.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef sparc
|
||||
@ -112,8 +113,6 @@ what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
extern char *xmalloc ();
|
||||
|
||||
static char *savestring ();
|
||||
|
||||
/* Add element named NAME to command list *LIST.
|
||||
FUN should be the function to execute the command;
|
||||
it will get a character string as argument, with leading
|
||||
@ -149,6 +148,33 @@ add_cmd (name, class, fun, doc, list)
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Same as above, except that the abbrev_flag is set. */
|
||||
|
||||
struct cmd_list_element *
|
||||
add_abbrev_cmd (name, class, fun, doc, list)
|
||||
char *name;
|
||||
int class;
|
||||
void (*fun) ();
|
||||
char *doc;
|
||||
struct cmd_list_element **list;
|
||||
{
|
||||
register struct cmd_list_element *c
|
||||
= (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
|
||||
|
||||
delete_cmd (name, list);
|
||||
c->next = *list;
|
||||
c->name = savestring (name, strlen (name));
|
||||
c->class = class;
|
||||
c->function = fun;
|
||||
c->doc = doc;
|
||||
c->prefixlist = 0;
|
||||
c->allow_unknown = 0;
|
||||
c->abbrev_flag = 1;
|
||||
c->aux = 0;
|
||||
*list = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
struct cmd_list_element *
|
||||
add_alias_cmd (name, oldname, class, abbrev_flag, list)
|
||||
char *name;
|
||||
@ -180,7 +206,7 @@ add_alias_cmd (name, oldname, class, abbrev_flag, list)
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Like add_prefix_cmd but adds an element for a command prefix:
|
||||
/* Like add_cmd but adds an element for a command prefix:
|
||||
a name that should be followed by a subcommand to be looked up
|
||||
in another command list. PREFIXLIST should be the address
|
||||
of the variable containing that list. */
|
||||
@ -204,6 +230,28 @@ add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname,
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Like add_prefix_cmd butsets the abbrev_flag on the new command. */
|
||||
|
||||
struct cmd_list_element *
|
||||
add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname,
|
||||
allow_unknown, list)
|
||||
char *name;
|
||||
int class;
|
||||
void (*fun) ();
|
||||
char *doc;
|
||||
struct cmd_list_element **prefixlist;
|
||||
char *prefixname;
|
||||
int allow_unknown;
|
||||
struct cmd_list_element **list;
|
||||
{
|
||||
register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
|
||||
c->prefixlist = prefixlist;
|
||||
c->prefixname = prefixname;
|
||||
c->allow_unknown = allow_unknown;
|
||||
c->abbrev_flag = 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Remove the command named NAME from the command list. */
|
||||
|
||||
void
|
||||
@ -228,65 +276,86 @@ delete_cmd (name, list)
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement a help command on command list LIST.
|
||||
COMMAND is the argument given (a command from the list to document)
|
||||
or zero for no arg (describe briefly all the commands in the list).
|
||||
CMDTYPE is a string to use in the error message if command COMMAND
|
||||
is not found in the list. */
|
||||
void help_cmd (), help_list (), help_cmd_list ();
|
||||
|
||||
/* CLASS should be -1 to list all commands in LIST,
|
||||
or a nonnegative class number value to list just commands in that class,
|
||||
or -2 to list the classes themselves. */
|
||||
/* This command really has to deal with two things:
|
||||
* 1) I want documentation on *this string* (usually called by
|
||||
* "help commandname").
|
||||
* 2) I want documentation on *this list* (usually called by
|
||||
* giving a command that requires subcommands. Also called by saying
|
||||
* just "help".)
|
||||
*
|
||||
* I am going to split this into two seperate comamnds, help_cmd and
|
||||
* help_list.
|
||||
*/
|
||||
|
||||
void
|
||||
help_cmd (command, list, cmdtype, class, stream)
|
||||
help_cmd (command, stream)
|
||||
char *command;
|
||||
FILE *stream;
|
||||
{
|
||||
struct cmd_list_element *c;
|
||||
extern struct cmd_list_element *cmdlist;
|
||||
|
||||
if (!command)
|
||||
{
|
||||
help_list (cmdlist, "", -2, stream);
|
||||
return;
|
||||
}
|
||||
|
||||
c = lookup_cmd (&command, cmdlist, "", 0);
|
||||
|
||||
if (c == 0)
|
||||
return;
|
||||
|
||||
/* There are three cases here.
|
||||
If c->prefixlist is nonzer, we have a prefix command.
|
||||
Print its documentation, then list its subcommands.
|
||||
|
||||
If c->function is nonzero, we really have a command.
|
||||
Print its documentation and return.
|
||||
|
||||
If c->function is zero, we have a class name.
|
||||
Print its documentation (as if it were a command)
|
||||
and then set class to he number of this class
|
||||
so that the commands in the class will be listed. */
|
||||
|
||||
fprintf (stream, "%s\n", c->doc);
|
||||
if (c->prefixlist == 0 && c->function != 0)
|
||||
return;
|
||||
fputc ('\n', stream);
|
||||
|
||||
/* If this is a prefix command, print it's subcommands */
|
||||
if (c->prefixlist)
|
||||
help_list (*c->prefixlist, c->prefixname, -1, stream);
|
||||
|
||||
/* If this is a class name, print all of the commands in the class */
|
||||
if (c->function == 0)
|
||||
help_list (cmdlist, "", c->class, stream);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a specific kind of help on a command list.
|
||||
*
|
||||
* LIST is the list.
|
||||
* CMDTYPE is the prefix to use in the title string.
|
||||
* CLASS is the class with which to list the nodes of this list (see
|
||||
* documentation for help_cmd_list below), As usual, -1 for
|
||||
* everything, -2 for just classes, and non-negative for only things
|
||||
* in a specific class.
|
||||
* and STREAM is the output stream on which to print things.
|
||||
* If you call this routine with a class >= 0, it recurses.
|
||||
*/
|
||||
void
|
||||
help_list (list, cmdtype, class, stream)
|
||||
struct cmd_list_element *list;
|
||||
char *cmdtype;
|
||||
int class;
|
||||
FILE *stream;
|
||||
{
|
||||
register struct cmd_list_element *c;
|
||||
register char *p;
|
||||
register int ncmds;
|
||||
struct cmdvec { struct cmd_list_element *cmd; int class; };
|
||||
register struct cmdvec *cmdvec;
|
||||
char *cmdtype1, *cmdtype2;
|
||||
int len;
|
||||
|
||||
if (command)
|
||||
{
|
||||
c = lookup_cmd (&command, list, cmdtype, 0);
|
||||
if (c == 0)
|
||||
return;
|
||||
|
||||
/* There are three cases here.
|
||||
If c->prefixlist is nonzer, we have a prefix command.
|
||||
Print its documentation, then list its subcommands.
|
||||
|
||||
If c->function is nonzero, we really have a command.
|
||||
Print its documentation and return.
|
||||
|
||||
If c->function is zero, we have a class name.
|
||||
Print its documentation (as if it were a command)
|
||||
and then set class to he number of this class
|
||||
so that the commands in the class will be listed. */
|
||||
|
||||
p = c->doc;
|
||||
fprintf (stream, "%s\n", p);
|
||||
if (c->function != 0 && c->prefixlist == 0)
|
||||
return;
|
||||
fputc ('\n', stream);
|
||||
if (c->prefixlist)
|
||||
{
|
||||
list = *c->prefixlist;
|
||||
class = 0;
|
||||
cmdtype = c->prefixname;
|
||||
}
|
||||
else
|
||||
class = c->class;
|
||||
}
|
||||
|
||||
char *cmdtype1, *cmdtype2;
|
||||
|
||||
/* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */
|
||||
len = strlen (cmdtype);
|
||||
cmdtype1 = (char *) alloca (len + 1);
|
||||
@ -307,21 +376,7 @@ help_cmd (command, list, cmdtype, class, stream)
|
||||
else
|
||||
fprintf (stream, "List of %scommands:\n\n", cmdtype2);
|
||||
|
||||
for (c = list; c; c = c->next)
|
||||
{
|
||||
if (c->abbrev_flag == 0
|
||||
&& (class == -1 /* Listing all */
|
||||
|| (c->class == class && c->function != 0) /* Listing one class */
|
||||
|| (class == -2 && c->function == 0))) /* Listing the classes */
|
||||
{
|
||||
fprintf (stream, "%s -- ", c->name);
|
||||
/* Print just first line of documentation. */
|
||||
p = c->doc;
|
||||
while (*p && *p != '\n') p++;
|
||||
fwrite (c->doc, 1, p - c->doc, stream);
|
||||
fputc ('\n', stream);
|
||||
}
|
||||
}
|
||||
help_cmd_list (list, class, cmdtype, (class >= 0), stream);
|
||||
|
||||
if (class == -2)
|
||||
fprintf (stream, "\n\
|
||||
@ -333,6 +388,55 @@ Type \"help%s\" followed by %scommand name for full documentation.\n\
|
||||
Command name abbreviations are allowed if unambiguous.\n",
|
||||
cmdtype1, cmdtype2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement a help command on command list LIST.
|
||||
* RECURSE should be non-zero if this should be done recursively on
|
||||
* all sublists of LIST.
|
||||
* PREFIX is the prefix to print before each command name.
|
||||
* STREAM is the stream upon which the output should be written.
|
||||
* CLASS should be:
|
||||
* A non-negative class number to list only commands in that
|
||||
* class.
|
||||
* -1 to list all commands in list.
|
||||
* -2 to list all classes in list.
|
||||
*
|
||||
* Note that RECURSE will be active on *all* sublists, not just the
|
||||
* ones seclected by the criteria above (ie. the selection mechanism
|
||||
* is at the low level, not the high-level).
|
||||
*/
|
||||
void
|
||||
help_cmd_list (list, class, prefix, recurse, stream)
|
||||
struct cmd_list_element *list;
|
||||
int class;
|
||||
char *prefix;
|
||||
int recurse;
|
||||
FILE *stream;
|
||||
{
|
||||
register struct cmd_list_element *c;
|
||||
register char *p;
|
||||
|
||||
for (c = list; c; c = c->next)
|
||||
{
|
||||
if (c->abbrev_flag == 0 &&
|
||||
(class == -1
|
||||
|| (class == -2 && c->function == 0)
|
||||
|| (class == c->class && c->function != 0)))
|
||||
{
|
||||
fprintf (stream, "%s%s -- ", prefix, c->name);
|
||||
/* Print just the first line */
|
||||
p = c->doc;
|
||||
while (*p && *p != '\n') p++;
|
||||
fwrite (c->doc, 1, p - c->doc, stream);
|
||||
fputc('\n', stream);
|
||||
}
|
||||
if (recurse
|
||||
&& c->prefixlist != 0
|
||||
&& c->abbrev_flag == 0)
|
||||
help_cmd_list (*c->prefixlist, class, c->prefixname, 1, stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* Look up the contents of *LINE as a command in the command list LIST.
|
||||
LIST is a chain of struct cmd_list_element's.
|
||||
@ -355,6 +459,8 @@ lookup_cmd (line, list, cmdtype, allow_unknown)
|
||||
register struct cmd_list_element *c, *found;
|
||||
int nfound;
|
||||
char ambbuf[100];
|
||||
char *processed_cmd;
|
||||
int i, cmd_len;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
|
||||
@ -371,29 +477,53 @@ lookup_cmd (line, list, cmdtype, allow_unknown)
|
||||
/* Find end of command name. */
|
||||
|
||||
p = *line;
|
||||
while (*p == '-'
|
||||
|| (*p >= 'a' && *p <= 'z')
|
||||
|| (*p >= 'A' && *p <= 'Z')
|
||||
|| (*p >= '0' && *p <= '9'))
|
||||
{
|
||||
if (*p >= 'A' && *p <= 'Z')
|
||||
*p += 'a' - 'A';
|
||||
p++;
|
||||
}
|
||||
if (*p == '!')
|
||||
p++;
|
||||
else while (*p == '-'
|
||||
|| (*p >= 'a' && *p <= 'z')
|
||||
|| (*p >= 'A' && *p <= 'Z')
|
||||
|| (*p >= '0' && *p <= '9'))
|
||||
p++;
|
||||
|
||||
/* Look up the command name.
|
||||
If exact match, keep that.
|
||||
Otherwise, take command abbreviated, if unique. */
|
||||
Otherwise, take command abbreviated, if unique. Note that (in my
|
||||
opinion) a null string does *not* indicate ambiguity; simply the
|
||||
end of the argument. */
|
||||
|
||||
if (p == *line)
|
||||
{
|
||||
if (!allow_unknown)
|
||||
error ("Lack of needed %scommand", cmdtype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy over to a local buffer, converting to lowercase on the way.
|
||||
This is in case the command being parsed is a subcommand which
|
||||
doesn't match anything, and that's ok. We want the original
|
||||
untouched for the routine of the original command. */
|
||||
|
||||
processed_cmd = (char *) alloca (p - *line + 1);
|
||||
for (cmd_len = 0; cmd_len < p - *line; cmd_len++)
|
||||
{
|
||||
char x = (*line)[cmd_len];
|
||||
if (x >= 'A' && x <= 'Z')
|
||||
processed_cmd[cmd_len] = x - 'A' + 'a';
|
||||
else
|
||||
processed_cmd[cmd_len] = x;
|
||||
}
|
||||
processed_cmd[cmd_len] = '\0';
|
||||
|
||||
/* Check all possibilities in the current command list. */
|
||||
found = 0;
|
||||
nfound = 0;
|
||||
for (c = list; c; c = c->next)
|
||||
{
|
||||
if (!strncmp (*line, c->name, p - *line))
|
||||
if (!strncmp (processed_cmd, c->name, cmd_len))
|
||||
{
|
||||
found = c;
|
||||
nfound++;
|
||||
if (c->name[p - *line] == 0)
|
||||
if (c->name[cmd_len] == 0)
|
||||
{
|
||||
nfound = 1;
|
||||
break;
|
||||
@ -407,10 +537,9 @@ lookup_cmd (line, list, cmdtype, allow_unknown)
|
||||
{
|
||||
if (nfound > 1 && allow_unknown >= 0)
|
||||
{
|
||||
*p = 0;
|
||||
ambbuf[0] = 0;
|
||||
for (c = list; c; c = c->next)
|
||||
if (!strncmp (*line, c->name, p - *line))
|
||||
if (!strncmp (processed_cmd, c->name, cmd_len))
|
||||
{
|
||||
if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf)
|
||||
{
|
||||
@ -424,13 +553,11 @@ lookup_cmd (line, list, cmdtype, allow_unknown)
|
||||
break;
|
||||
}
|
||||
}
|
||||
error ("Ambiguous %scommand \"%s\": %s.", cmdtype, *line, ambbuf);
|
||||
error ("Ambiguous %scommand \"%s\": %s.", cmdtype,
|
||||
processed_cmd, ambbuf);
|
||||
}
|
||||
else if (!allow_unknown)
|
||||
{
|
||||
*p = 0;
|
||||
error ("Undefined %scommand: \"%s\".", cmdtype, *line);
|
||||
}
|
||||
error ("Undefined %scommand: \"%s\".", cmdtype, processed_cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -450,17 +577,48 @@ lookup_cmd (line, list, cmdtype, allow_unknown)
|
||||
return found;
|
||||
}
|
||||
|
||||
/* Make a copy of the string at PTR with SIZE characters
|
||||
(and add a null character at the end in the copy).
|
||||
Uses malloc to get the space. Returns the address of the copy. */
|
||||
|
||||
static char *
|
||||
savestring (ptr, size)
|
||||
char *ptr;
|
||||
int size;
|
||||
static void
|
||||
shell_escape (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
register char *p = (char *) xmalloc (size + 1);
|
||||
bcopy (ptr, p, size);
|
||||
p[size] = 0;
|
||||
return p;
|
||||
int rc, status, pid;
|
||||
char *p, *user_shell;
|
||||
extern char *rindex ();
|
||||
|
||||
if ((user_shell = (char *) getenv ("SHELL")) == NULL)
|
||||
user_shell = "/bin/sh";
|
||||
|
||||
/* Get the name of the shell for arg0 */
|
||||
if ((p = rindex (user_shell, '/')) == NULL)
|
||||
p = user_shell;
|
||||
else
|
||||
p++; /* Get past '/' */
|
||||
|
||||
if ((pid = fork()) == 0)
|
||||
{
|
||||
if (!arg)
|
||||
execl (user_shell, p, 0);
|
||||
else
|
||||
execl (user_shell, p, "-c", arg, 0);
|
||||
|
||||
fprintf (stderr, "Exec of shell failed\n");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (pid != -1)
|
||||
while ((rc = wait (&status)) != pid && rc != -1)
|
||||
;
|
||||
else
|
||||
error ("Fork failed");
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_command ()
|
||||
{
|
||||
add_com ("shell", class_support, shell_escape,
|
||||
"Execute the rest of the line as a shell command. \n\
|
||||
With no arguments, run an inferior shell.");
|
||||
|
||||
add_com_alias ("!", "shell", class_support, 1);
|
||||
}
|
||||
|
233
gdb/config.gdb
233
gdb/config.gdb
@ -4,7 +4,7 @@
|
||||
# Shell script to create proper links to machine-dependent files in
|
||||
# preparation for compiling gdb.
|
||||
#
|
||||
# Usage: config.gdb machine
|
||||
# Usage: config.gdb machine [operating-system]
|
||||
#
|
||||
# If config.gdb succeeds, it leaves its status in config.status.
|
||||
# If config.gdb fails after disturbing the status quo,
|
||||
@ -13,79 +13,159 @@
|
||||
|
||||
progname=$0
|
||||
|
||||
case $# in
|
||||
case $# in
|
||||
1)
|
||||
machine=$1
|
||||
paramfile=m-${machine}.h
|
||||
initfile=m-${machine}init.h
|
||||
pinsnfile=${machine}-pinsn.c
|
||||
opcodefile=${machine}-opcode.h
|
||||
os="none"
|
||||
;;
|
||||
2)
|
||||
machine=$1
|
||||
os=$2
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $progname machine [operating-system]"
|
||||
echo "Available machine types:"
|
||||
echo m-*.h | sed 's/m-//g' | sed 's/\.h//g'
|
||||
if [ -r config.status ]
|
||||
then
|
||||
cat config.status
|
||||
fi
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case $machine in
|
||||
hp9k320)
|
||||
initfile=m-sun3init.h
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
hp9k320bsd)
|
||||
initfile=m-sun3init.h
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
isi)
|
||||
# some version of m68k-pinsn.c should work here
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
merlin)
|
||||
# m-umaxinit.h?
|
||||
initfile=unknown-or-unavailable
|
||||
pinsnfile=ns32k-pinsn.c
|
||||
opcodefile=ns32k-opcode.h
|
||||
;;
|
||||
news)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
npl)
|
||||
pinsnfile=gld-pinsn.c
|
||||
;;
|
||||
pn)
|
||||
pinsnfile=gld-pinsn.c
|
||||
;;
|
||||
sun2)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun3)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun4)
|
||||
pinsnfile=sparc-pinsn.c
|
||||
opcodefile=sparc-opcode.h
|
||||
;;
|
||||
umax)
|
||||
pinsnfile=ns32k-pinsn.c
|
||||
opcodefile=ns32k-opcode.h
|
||||
;;
|
||||
test)
|
||||
paramfile=one
|
||||
initfile=two
|
||||
pinsnfile=three
|
||||
opcodefile=four
|
||||
paramfile=m-${machine}.h
|
||||
pinsnfile=${machine}-pinsn.c
|
||||
opcodefile=${machine}-opcode.h
|
||||
if [ -r ${machine}-dep.c ]
|
||||
then
|
||||
depfile=${machine}-dep.c
|
||||
else
|
||||
depfile=default-dep.c
|
||||
fi
|
||||
|
||||
#
|
||||
# Special cases.
|
||||
# If a file is not needed, set the filename to 'skip' and it will be
|
||||
# ignored.
|
||||
#
|
||||
case $machine in
|
||||
aux)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
vax)
|
||||
pinsnfile=vax-pinsn.c
|
||||
opcodefile=vax-opcode.h
|
||||
;;
|
||||
hp9k320)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
isi)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
i386)
|
||||
echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile"
|
||||
opcodefile=skip
|
||||
;;
|
||||
i386gas)
|
||||
echo "Note: i386 users need to modify \`CLIBS' & \`REGEX*' in the Makefile"
|
||||
echo "Use of the coff encapsulation features also requires the GNU binutils utilities"
|
||||
echo "to be ahead of their System V counterparts in your path."
|
||||
pinsnfile=i386-pinsn.c
|
||||
depfile=i386-dep.c
|
||||
opcodefile=skip
|
||||
;;
|
||||
merlin)
|
||||
pinsnfile=ns32k-pinsn.c
|
||||
opcodefile=ns32k-opcode.h
|
||||
;;
|
||||
news)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
npl)
|
||||
pinsnfile=gld-pinsn.c
|
||||
;;
|
||||
pn)
|
||||
pinsnfile=gld-pinsn.c
|
||||
;;
|
||||
sun2)
|
||||
case $os in
|
||||
os4|sunos4)
|
||||
paramfile=m-sun2os4.h
|
||||
;;
|
||||
os2|sunos2)
|
||||
paramfile=m-sun2os2.h
|
||||
esac
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun2os2)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun2os4)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun3)
|
||||
case $os in
|
||||
os4|sunos4)
|
||||
paramfile=m-sun3os4.h
|
||||
esac
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
;;
|
||||
sun3os4)
|
||||
pinsnfile=m68k-pinsn.c
|
||||
opcodefile=m68k-opcode.h
|
||||
depfile=sun3-dep.c
|
||||
;;
|
||||
sun4os4)
|
||||
pinsnfile=sparc-pinsn.c
|
||||
opcodefile=sparc-opcode.h
|
||||
depfile=sparc-dep.c
|
||||
;;
|
||||
umax)
|
||||
pinsnfile=ns32k-pinsn.c
|
||||
opcodefile=ns32k-opcode.h
|
||||
;;
|
||||
sparc|sun4)
|
||||
case $os in
|
||||
os4|sunos4)
|
||||
paramfile=m-sun4os4.h
|
||||
esac
|
||||
pinsnfile=sparc-pinsn.c
|
||||
opcodefile=sparc-opcode.h
|
||||
depfile=sparc-dep.c
|
||||
paramfile=m-sparc.h
|
||||
;;
|
||||
test)
|
||||
paramfile=one
|
||||
pinsnfile=three
|
||||
opcodefile=four
|
||||
;;
|
||||
*)
|
||||
echo "Unknown machine type: \`$machine'"
|
||||
echo "Available types:"
|
||||
echo m-*.h | sed 's/m-//g' | sed 's/\.h//g'
|
||||
exit 1
|
||||
esac
|
||||
|
||||
files="$paramfile $initfile $pinsnfile $opcodefile"
|
||||
links="param.h m-init.h pinsn.c opcode.h"
|
||||
files="$paramfile $pinsnfile $opcodefile $depfile"
|
||||
links="param.h pinsn.c opcode.h dep.c"
|
||||
|
||||
while [ -n "$files" ]
|
||||
do
|
||||
# set file to car of files, files to cdr of files
|
||||
set $files; file=$1; shift; files=$*
|
||||
set $links; link=$1; shift; links=$*
|
||||
while [ -n "$files" ]
|
||||
do
|
||||
# set file to car of files, files to cdr of files
|
||||
set $files; file=$1; shift; files=$*
|
||||
set $links; link=$1; shift; links=$*
|
||||
|
||||
if [ "$file" != skip ]
|
||||
then
|
||||
if [ ! -r $file ]
|
||||
then
|
||||
echo "$progname: cannot create a link \`$link',"
|
||||
@ -103,21 +183,10 @@ case $# in
|
||||
exit 1
|
||||
fi
|
||||
echo "Linked \`$link' to \`$file'."
|
||||
done
|
||||
|
||||
echo "Links are now set up for use with a $machine." \
|
||||
| tee config.status
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $progname machine"
|
||||
echo -n "Where \`machine' is something like "
|
||||
echo "\`vax', \`sun3', \`umax', etc."
|
||||
if [ -r config.status ]
|
||||
then
|
||||
cat config.status
|
||||
fi
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Links are now set up for use with a $machine." \
|
||||
| tee config.status
|
||||
exit 0
|
||||
|
||||
|
524
gdb/convex-dep.c
Normal file
524
gdb/convex-dep.c
Normal file
@ -0,0 +1,524 @@
|
||||
/* Low level interface to ptrace, for GDB when running under Unix.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <a.out.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
/* This function simply calls ptrace with the given arguments.
|
||||
It exists so that all calls to ptrace are isolated in this
|
||||
machine-dependent file. */
|
||||
int
|
||||
call_ptrace (request, pid, arg3, arg4)
|
||||
int request, pid, arg3, arg4;
|
||||
{
|
||||
return ptrace (request, pid, arg3, arg4);
|
||||
}
|
||||
|
||||
kill_inferior ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
/* Convex ptrace needs an extra 0 arg */
|
||||
ptrace (8, inferior_pid, 0, 0, 0);
|
||||
wait (0);
|
||||
inferior_died ();
|
||||
}
|
||||
|
||||
/* This is used when GDB is exiting. It gives less chance of error.*/
|
||||
|
||||
kill_inferior_fast ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
}
|
||||
|
||||
/* Resume execution of the inferior process.
|
||||
If STEP is nonzero, single-step it.
|
||||
If SIGNAL is nonzero, give it that signal. */
|
||||
|
||||
void
|
||||
resume (step, signal)
|
||||
int step;
|
||||
int signal;
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_resume (step, signal);
|
||||
else
|
||||
{
|
||||
extern char registers[];
|
||||
|
||||
/* Blam the trace bits in the stack's saved psws to match the
|
||||
desired step mode. This is required so that single-stepping a
|
||||
return doesn't restore a psw with a clear trace bit and fly away,
|
||||
and conversely, proceeding through a return in a routine that was
|
||||
stepped into doesn't cause a phantom break by restoring a psw
|
||||
with the trace bit set. */
|
||||
scan_stack (PSW_T_BIT, step);
|
||||
|
||||
/* Write the registers back now */
|
||||
ptrace (11, inferior_pid, 0, registers, REGISTER_BYTES);
|
||||
if (errno != 0) perror_with_name ("writing registers");
|
||||
|
||||
errno = 0;
|
||||
ptrace (step ? 9 : 7, inferior_pid, 1, &signal, sizeof signal);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers ()
|
||||
{
|
||||
extern char registers[];
|
||||
ptrace (10, inferior_pid, 0, registers, REGISTER_BYTES);
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
If REGNO is -1, do this for all registers.
|
||||
Otherwise, REGNO specifies which register (so we can save time). */
|
||||
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
/* do this only once, right before resuming inferior. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
|
||||
in the NEW_SUN_PTRACE case.
|
||||
It ought to be straightforward. But it appears that writing did
|
||||
not write the data that I specified. I cannot understand where
|
||||
it got the data that it actually did write. */
|
||||
|
||||
/* Copy LEN bytes from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR.
|
||||
On failure (cannot read from inferior, usually because address is out
|
||||
of bounds) returns the value of errno. */
|
||||
|
||||
int
|
||||
read_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (1, inferior_pid, memaddr, myaddr, len);
|
||||
if (errno)
|
||||
bzero (myaddr, len);
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Copy LEN bytes of data from debugger memnory at MYADDR
|
||||
to inferior's memory at MEMADDR.
|
||||
Returns errno on failure (cannot write the inferior) */
|
||||
|
||||
int
|
||||
write_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (4, inferior_pid, memaddr, myaddr, len);
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
This code would be in core.c if it weren't machine-dependent. */
|
||||
|
||||
/* Required by convex's SOFF format
|
||||
It may be desirable to remove the conditionals for SOFF_FORMAT, if
|
||||
Convex is the only machine which will ever make use of them. */
|
||||
#ifdef SOFF_FORMAT
|
||||
#include <convex/filehdr.h>
|
||||
#include <convex/opthdr.h>
|
||||
#include <convex/scnhdr.h>
|
||||
#include <convex/core.h>
|
||||
#endif /* SOFF_FORMAT */
|
||||
|
||||
/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
|
||||
#ifdef AOUTHDR
|
||||
#define COFF_FORMAT
|
||||
#endif
|
||||
|
||||
#ifndef N_TXTADDR
|
||||
#define N_TXTADDR(hdr) 0
|
||||
#endif /* no N_TXTADDR */
|
||||
|
||||
#ifndef N_DATADDR
|
||||
#define N_DATADDR(hdr) hdr.a_text
|
||||
#endif /* no N_DATADDR */
|
||||
|
||||
/* Make COFF and non-COFF names for things a little more compatible
|
||||
to reduce conditionals later. */
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
#define a_magic magic
|
||||
#endif
|
||||
|
||||
#ifndef COFF_FORMAT
|
||||
#define AOUTHDR struct exec
|
||||
#endif
|
||||
|
||||
extern char *sys_siglist[];
|
||||
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
extern void (*exec_file_display_hook) ();
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
extern char *corefile;
|
||||
extern char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
extern int corechan;
|
||||
extern int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
|
||||
extern int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
extern CORE_ADDR data_start;
|
||||
extern CORE_ADDR data_end;
|
||||
extern CORE_ADDR stack_start;
|
||||
extern CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
|
||||
extern CORE_ADDR text_start;
|
||||
extern CORE_ADDR text_end;
|
||||
|
||||
extern CORE_ADDR exec_data_start;
|
||||
extern CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
extern int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
extern int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
extern int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
extern int stack_offset;
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
/* various coff data structures */
|
||||
|
||||
extern FILHDR file_hdr;
|
||||
extern SCNHDR text_hdr;
|
||||
extern SCNHDR data_hdr;
|
||||
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
/* a.out header saved in core file. */
|
||||
|
||||
extern AOUTHDR core_aouthdr;
|
||||
|
||||
/* a.out header of exec file. */
|
||||
|
||||
extern AOUTHDR exec_aouthdr;
|
||||
|
||||
extern void validate_files ();
|
||||
|
||||
core_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
if (corefile)
|
||||
free (corefile);
|
||||
corefile = 0;
|
||||
|
||||
if (corechan >= 0)
|
||||
close (corechan);
|
||||
corechan = -1;
|
||||
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
/* Now, if a new core file was specified, open it and digest it. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
error ("To look at a core file, you must kill the inferior with \"kill\".");
|
||||
corechan = open (filename, O_RDONLY, 0);
|
||||
if (corechan < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
#ifdef SOFF_FORMAT
|
||||
{
|
||||
extern char *sys_errlist[], *sys_siglist[];
|
||||
extern int sys_nerr;
|
||||
int stop_signal;
|
||||
struct core_hdr corehdr;
|
||||
struct user u;
|
||||
|
||||
if (myread (corechan, &corehdr, sizeof corehdr) < 0)
|
||||
perror_with_name (filename);
|
||||
if (corehdr.c_magic != CH_MAGIC)
|
||||
error ("%s: not a core file.", filename);
|
||||
|
||||
lseek (corechan, corehdr.c_user, 0);
|
||||
if (myread (corechan, &u, sizeof u) < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
lseek (corechan, corehdr.c_syscall_context, 0);
|
||||
if (myread (corechan, registers, REGISTER_BYTES) < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
if (corehdr.c_vecst)
|
||||
{
|
||||
lseek (corechan, corehdr.c_vecst, 0);
|
||||
if (myread (corechan, vecst, sizeof vecst) < 0)
|
||||
perror_with_name (filename);
|
||||
}
|
||||
|
||||
data_offset = corehdr.c_data;
|
||||
data_start = exec_data_start;
|
||||
data_end = data_start + ctob (u.u_dsize);
|
||||
|
||||
stack_offset = corehdr.c_stack;
|
||||
stack_start = stack_end - ctob (u.u_ssize);
|
||||
|
||||
printf ("Program %s", u.u_comm );
|
||||
if (u.u_error >= sys_nerr)
|
||||
printf (", last error: %d (undocumented),\n", u.u_error);
|
||||
else if (u.u_error != 0)
|
||||
printf (", last error: %s,", sys_errlist[u.u_error]);
|
||||
|
||||
stop_signal = u.u_arg[0];
|
||||
printf (" received signal %d, %s\n", stop_signal,
|
||||
stop_signal < NSIG ? sys_siglist[stop_signal] : "(undocumented)");
|
||||
|
||||
core_aouthdr.a_magic = 0;
|
||||
}
|
||||
#ifdef SOFF_FORMAT
|
||||
|
||||
if (filename[0] == '/')
|
||||
corefile = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
corefile = concat (current_directory, "/", filename);
|
||||
}
|
||||
|
||||
/* Convex-specific code: remove the frame stored by a
|
||||
user-mode trap, if present */
|
||||
|
||||
if (read_register (PC_REGNUM) > STACK_END_ADDR)
|
||||
{
|
||||
POP_FRAME;
|
||||
}
|
||||
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
|
||||
read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No core file now.\n");
|
||||
}
|
||||
|
||||
exec_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
|
||||
/* Eliminate all traces of old exec file.
|
||||
Mark text segment as empty. */
|
||||
|
||||
if (execfile)
|
||||
free (execfile);
|
||||
execfile = 0;
|
||||
data_start = 0;
|
||||
data_end -= exec_data_start;
|
||||
text_start = 0;
|
||||
text_end = 0;
|
||||
exec_data_start = 0;
|
||||
exec_data_end = 0;
|
||||
if (execchan >= 0)
|
||||
close (execchan);
|
||||
execchan = -1;
|
||||
|
||||
/* Now open and digest the file the user requested, if any. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
|
||||
&execfile);
|
||||
if (execchan < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
{
|
||||
int aout_hdrsize;
|
||||
int num_sections;
|
||||
|
||||
if (read_file_hdr (execchan, &file_hdr) < 0)
|
||||
error ("\"%s\": not in executable format.", execfile);
|
||||
|
||||
aout_hdrsize = file_hdr.f_opthdr;
|
||||
num_sections = file_hdr.f_nscns;
|
||||
|
||||
if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
|
||||
error ("\"%s\": can't read optional aouthdr", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read text section header", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read data section header", execfile);
|
||||
|
||||
text_start = exec_aouthdr.text_start;
|
||||
text_end = text_start + exec_aouthdr.tsize;
|
||||
text_offset = text_hdr.s_scnptr;
|
||||
exec_data_start = exec_aouthdr.data_start;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.dsize;
|
||||
exec_data_offset = data_hdr.s_scnptr;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
exec_mtime = file_hdr.f_timdat;
|
||||
}
|
||||
#else /* not COFF_FORMAT */
|
||||
{
|
||||
struct stat st_exec;
|
||||
|
||||
val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
|
||||
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
/* Convex-specific SOFF-FORMAT */
|
||||
#ifdef SOFF_FORMAT
|
||||
if (IS_SOFF_MAGIC (exec_aouthdr.a_magic))
|
||||
{
|
||||
FILEHDR filhdr;
|
||||
OPTHDR opthdr;
|
||||
SCNHDR scnhdr;
|
||||
int n, gotem;
|
||||
|
||||
lseek (execchan, 0L, 0);
|
||||
if (myread (execchan, &filhdr, sizeof filhdr) < 0)
|
||||
perror_with_name (filename);
|
||||
if (myread (execchan, &opthdr, filhdr.h_opthdr) <= 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
lseek (execchan, (long) filhdr.h_scnptr, 0);
|
||||
n = -1;
|
||||
gotem = 0;
|
||||
while (++n < filhdr.h_nscns && gotem < 2)
|
||||
{
|
||||
if (myread (execchan, &scnhdr, SCNHSZ) < 0)
|
||||
perror_with_name (filename);
|
||||
if ((scnhdr.s_flags & S_TYPMASK) == S_TEXT)
|
||||
{
|
||||
text_start = scnhdr.s_vaddr;
|
||||
text_end = text_start + scnhdr.s_size;
|
||||
text_offset = scnhdr.s_scnptr;
|
||||
++gotem;
|
||||
}
|
||||
else if ((scnhdr.s_flags & S_TYPMASK) == S_DATA)
|
||||
{
|
||||
exec_data_start = scnhdr.s_vaddr;
|
||||
exec_data_end = exec_data_start + scnhdr.s_size;
|
||||
exec_data_offset = scnhdr.s_scnptr;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
++gotem;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif SOFF_FORMAT
|
||||
{
|
||||
text_start = N_TXTADDR (exec_aouthdr);
|
||||
text_end = text_start + exec_aouthdr.a_text;
|
||||
text_offset = N_TXTOFF (exec_aouthdr);
|
||||
exec_data_start = N_DATADDR (exec_aouthdr);
|
||||
exec_data_end = exec_data_start + exec_aouthdr.a_data;
|
||||
exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
}
|
||||
fstat (execchan, &st_exec);
|
||||
exec_mtime = st_exec.st_mtime;
|
||||
}
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No exec file now.\n");
|
||||
|
||||
/* Tell display code (if any) about the changed file name. */
|
||||
if (exec_file_display_hook)
|
||||
(*exec_file_display_hook) (filename);
|
||||
}
|
||||
|
534
gdb/core.c
534
gdb/core.c
@ -1,5 +1,5 @@
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
@ -18,11 +18,29 @@ In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "initialize.h"
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef COFF_ENCAPSULATE
|
||||
#include "a.out.encap.h"
|
||||
#else
|
||||
#include <a.out.h>
|
||||
#endif
|
||||
|
||||
#ifndef N_MAGIC
|
||||
#ifdef COFF_FORMAT
|
||||
#define N_MAGIC(exec) ((exec).magic)
|
||||
#else
|
||||
#define N_MAGIC(exec) ((exec).a_magic)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
@ -30,28 +48,21 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
|
||||
#ifdef AOUTHDR
|
||||
#define COFF_FORMAT
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
#define PMMU
|
||||
#define NEW_PMMU
|
||||
#include <sys/seg.h> /* Required for user.ps */
|
||||
#include <sys/time.h> /* '' */
|
||||
#include <sys/mmu.h> /* '' */
|
||||
#include <sys/reg.h>
|
||||
#define mc68881 /* Required to get float in user.ps */
|
||||
#endif
|
||||
|
||||
#ifdef NEW_SUN_CORE
|
||||
#include <sys/core.h>
|
||||
#else /* not NEW_SUN_CORE */
|
||||
#ifdef UMAX_CORE
|
||||
#include <sys/ptrace.h>
|
||||
#else /* not UMAX_CORE */
|
||||
#else
|
||||
#include <sys/user.h>
|
||||
#ifdef HP9K320
|
||||
#include <sys/reg.h>
|
||||
#include <sys/trap.h>
|
||||
#ifdef HPUX_VERSION_5
|
||||
#define e_PS e_regs[PS]
|
||||
#define e_PC e_regs[PC]
|
||||
#endif /* HPUX_VERSION_5 */
|
||||
#endif /* HP9K320 */
|
||||
#endif /* not UMAX_CORE */
|
||||
#endif /* not NEW_SUN_CORE */
|
||||
#endif
|
||||
|
||||
#ifndef N_TXTADDR
|
||||
#define N_TXTADDR(hdr) 0
|
||||
@ -61,20 +72,13 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
#define N_DATADDR(hdr) hdr.a_text
|
||||
#endif /* no N_DATADDR */
|
||||
|
||||
/* Make COFF and non-COFF names for things a little more compatible
|
||||
to reduce conditionals later. */
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
#define a_magic magic
|
||||
#endif
|
||||
|
||||
#ifndef COFF_FORMAT
|
||||
#define AOUTHDR struct exec
|
||||
#define AOUTHDR struct exec
|
||||
#endif
|
||||
|
||||
extern char *sys_siglist[];
|
||||
|
||||
START_FILE
|
||||
extern core_file_command (), exec_file_command ();
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
@ -82,15 +86,15 @@ void (*exec_file_display_hook) ();
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
static char *corefile;
|
||||
static char *execfile;
|
||||
char *corefile;
|
||||
char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
static int corechan;
|
||||
static int execchan;
|
||||
int corechan;
|
||||
int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
@ -99,10 +103,10 @@ int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
static CORE_ADDR data_start;
|
||||
static CORE_ADDR data_end;
|
||||
static CORE_ADDR stack_start;
|
||||
static CORE_ADDR stack_end;
|
||||
CORE_ADDR data_start;
|
||||
CORE_ADDR data_end;
|
||||
CORE_ADDR stack_start;
|
||||
CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
@ -110,361 +114,49 @@ static CORE_ADDR stack_end;
|
||||
CORE_ADDR text_start;
|
||||
CORE_ADDR text_end;
|
||||
|
||||
static CORE_ADDR exec_data_start;
|
||||
static CORE_ADDR exec_data_end;
|
||||
CORE_ADDR exec_data_start;
|
||||
CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
static int text_offset;
|
||||
int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
static int exec_data_offset;
|
||||
int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
static int data_offset;
|
||||
int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
static int stack_offset;
|
||||
int stack_offset;
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
/* various coff data structures */
|
||||
|
||||
static FILHDR file_hdr;
|
||||
static SCNHDR text_hdr;
|
||||
static SCNHDR data_hdr;
|
||||
FILHDR file_hdr;
|
||||
SCNHDR text_hdr;
|
||||
SCNHDR data_hdr;
|
||||
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
/* a.out header saved in core file. */
|
||||
|
||||
static AOUTHDR core_aouthdr;
|
||||
AOUTHDR core_aouthdr;
|
||||
|
||||
/* a.out header of exec file. */
|
||||
|
||||
static AOUTHDR exec_aouthdr;
|
||||
AOUTHDR exec_aouthdr;
|
||||
|
||||
static void validate_files ();
|
||||
void validate_files ();
|
||||
unsigned int register_addr ();
|
||||
|
||||
core_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
if (corefile)
|
||||
free (corefile);
|
||||
corefile = 0;
|
||||
|
||||
if (corechan >= 0)
|
||||
close (corechan);
|
||||
corechan = -1;
|
||||
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
/* Now, if a new core file was specified, open it and digest it. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
error ("To look at a core file, you must kill the inferior with \"kill\".");
|
||||
corechan = open (filename, O_RDONLY, 0);
|
||||
if (corechan < 0)
|
||||
perror_with_name (filename);
|
||||
#ifdef NEW_SUN_CORE
|
||||
{
|
||||
struct core corestr;
|
||||
|
||||
val = myread (corechan, &corestr, sizeof corestr);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
if (corestr.c_magic != CORE_MAGIC)
|
||||
error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)",
|
||||
filename, corestr.c_magic, (int) CORE_MAGIC);
|
||||
else if (sizeof (struct core) != corestr.c_len)
|
||||
error ("\"%s\" has an invalid struct core length (%d, expected %d)",
|
||||
filename, corestr.c_len, (int) sizeof (struct core));
|
||||
|
||||
data_start = exec_data_start;
|
||||
data_end = data_start + corestr.c_dsize;
|
||||
stack_start = stack_end - corestr.c_ssize;
|
||||
data_offset = sizeof corestr;
|
||||
stack_offset = sizeof corestr + corestr.c_dsize;
|
||||
|
||||
#if defined(sun2) || defined(sun3)
|
||||
bcopy (&corestr.c_regs, registers, 16 * 4);
|
||||
*(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps;
|
||||
*(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc;
|
||||
bcopy (corestr.c_fpstatus.fps_regs,
|
||||
®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
sizeof corestr.c_fpstatus.fps_regs);
|
||||
bcopy (&corestr.c_fpstatus.fps_control,
|
||||
®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
sizeof corestr.c_fpstatus - sizeof corestr.c_fpstatus.fps_regs);
|
||||
#endif
|
||||
#if defined(sun4)
|
||||
/* G0 *always* holds 0. */
|
||||
*(int *)®isters[REGISTER_BYTE (0)] = 0;
|
||||
/* The globals and output registers. I don't know where
|
||||
to get the locals and input registers from the core file. */
|
||||
bcopy (&corestr.c_regs.r_g1, registers, 15 * 4);
|
||||
*(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps;
|
||||
*(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc;
|
||||
*(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = corestr.c_regs.r_npc;
|
||||
*(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = corestr.c_regs.r_y;
|
||||
bcopy (corestr.c_fpu.fpu_regs,
|
||||
®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
sizeof corestr.c_fpu.fpu_regs);
|
||||
#ifdef FPU
|
||||
bcopy (&corestr.c_fpu.fpu_fsr,
|
||||
®isters[REGISTER_BYTE (FPS_REGNUM)],
|
||||
sizeof (FPU_FSR_TYPE));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec));
|
||||
|
||||
printf ("Core file is from \"%s\".\n", corestr.c_cmdname);
|
||||
if (corestr.c_signo > 0)
|
||||
printf ("Program terminated with signal %d, %s.\n",
|
||||
corestr.c_signo,
|
||||
corestr.c_signo < NSIG
|
||||
? sys_siglist[corestr.c_signo]
|
||||
: "(undocumented)");
|
||||
}
|
||||
#else /* not NEW_SUN_CORE */
|
||||
/* 4.2-style (and perhaps also sysV-style) core dump file. */
|
||||
{
|
||||
#ifdef UMAX_CORE
|
||||
struct ptrace_user u;
|
||||
#else
|
||||
struct user u;
|
||||
#endif
|
||||
int reg_offset;
|
||||
|
||||
val = myread (corechan, &u, sizeof u);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
data_start = exec_data_start;
|
||||
|
||||
#ifdef UMAX_CORE
|
||||
data_end = data_start + u.pt_dsize;
|
||||
stack_start = stack_end - u.pt_ssize;
|
||||
data_offset = sizeof u;
|
||||
stack_offset = data_offset + u.pt_dsize;
|
||||
reg_offset = 0;
|
||||
|
||||
bcopy (&u.pt_aouthdr, &core_aouthdr, sizeof (AOUTHDR));
|
||||
printf ("Core file is from \"%s\".\n", u.pt_comm);
|
||||
if (u.pt_signal > 0)
|
||||
printf ("Program terminated with signal %d, %s.\n",
|
||||
u.pt_signal,
|
||||
u.pt_signal < NSIG
|
||||
? sys_siglist[u.pt_signal]
|
||||
: "(undocumented)");
|
||||
#else /* not UMAX_CORE */
|
||||
data_end = data_start + NBPG * u.u_dsize;
|
||||
stack_start = stack_end - NBPG * u.u_ssize;
|
||||
data_offset = NBPG * UPAGES;
|
||||
stack_offset = NBPG * (UPAGES + u.u_dsize);
|
||||
reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
|
||||
|
||||
/* I don't know where to find this info.
|
||||
So, for now, mark it as not available. */
|
||||
core_aouthdr.a_magic = 0;
|
||||
#endif /* not UMAX_CORE */
|
||||
|
||||
/* Read the register values out of the core file and store
|
||||
them where `read_register' will find them. */
|
||||
|
||||
#ifdef HP9K320
|
||||
{
|
||||
register int regno;
|
||||
struct exception_stack es;
|
||||
int val;
|
||||
|
||||
val = lseek (corechan, (REGISTER_ADDR (reg_offset, 0)), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
val = myread (corechan, es,
|
||||
((char *) &es.e_regs[R0] - (char *) &es.e_offset));
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
for (regno = 0; (regno < PS_REGNUM); regno++)
|
||||
supply_register (regno, &es.e_regs[regno + R0]);
|
||||
val = es.e_PS;
|
||||
supply_register (regno++, &val);
|
||||
supply_register (regno++, &es.e_PC);
|
||||
for (; (regno < NUM_REGS); regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
val = lseek (corechan, (FP_REGISTER_ADDR (u, regno)), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
val = myread (corechan, buf, sizeof buf);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
#else /* not HP9K320 */
|
||||
{
|
||||
register int regno;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
val = lseek (corechan, register_addr (regno, reg_offset), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
val = myread (corechan, buf, sizeof buf);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
#endif /* not HP9K320 */
|
||||
}
|
||||
#endif /* not NEW_SUN_CORE */
|
||||
if (filename[0] == '/')
|
||||
corefile = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
corefile = concat (current_directory, "/", filename);
|
||||
}
|
||||
|
||||
set_current_frame (read_register (FP_REGNUM));
|
||||
select_frame (get_current_frame (), 0);
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No core file now.\n");
|
||||
}
|
||||
|
||||
exec_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
|
||||
/* Eliminate all traces of old exec file.
|
||||
Mark text segment as empty. */
|
||||
|
||||
if (execfile)
|
||||
free (execfile);
|
||||
execfile = 0;
|
||||
data_start = 0;
|
||||
data_end -= exec_data_start;
|
||||
text_start = 0;
|
||||
text_end = 0;
|
||||
exec_data_start = 0;
|
||||
exec_data_end = 0;
|
||||
if (execchan >= 0)
|
||||
close (execchan);
|
||||
execchan = -1;
|
||||
|
||||
/* Now open and digest the file the user requested, if any. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
|
||||
&execfile);
|
||||
if (execchan < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
{
|
||||
int aout_hdrsize;
|
||||
int num_sections;
|
||||
|
||||
if (read_file_hdr (execchan, &file_hdr) < 0)
|
||||
error ("\"%s\": not in executable format.", execfile);
|
||||
|
||||
aout_hdrsize = file_hdr.f_opthdr;
|
||||
num_sections = file_hdr.f_nscns;
|
||||
|
||||
if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
|
||||
error ("\"%s\": can't read optional aouthdr", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read text section header", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read data section header", execfile);
|
||||
|
||||
text_start = exec_aouthdr.text_start;
|
||||
text_end = text_start + exec_aouthdr.tsize;
|
||||
text_offset = text_hdr.s_scnptr;
|
||||
exec_data_start = exec_aouthdr.data_start;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.dsize;
|
||||
exec_data_offset = data_hdr.s_scnptr;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
exec_mtime = file_hdr.f_timdat;
|
||||
}
|
||||
#else /* not COFF_FORMAT */
|
||||
{
|
||||
struct stat st_exec;
|
||||
|
||||
#ifdef gould
|
||||
FILHDR exec_coffhdr;
|
||||
|
||||
val = myread (execchan, &exec_coffhdr, sizeof exec_coffhdr);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
#endif
|
||||
val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
|
||||
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
text_start = N_TXTADDR (exec_aouthdr);
|
||||
exec_data_start = N_DATADDR (exec_aouthdr);
|
||||
#ifdef gould
|
||||
text_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr);
|
||||
exec_data_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr)
|
||||
+ exec_aouthdr.a_text;
|
||||
#else
|
||||
text_offset = N_TXTOFF (exec_aouthdr);
|
||||
exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
|
||||
#endif
|
||||
text_end = text_start + exec_aouthdr.a_text;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.a_data;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
|
||||
fstat (execchan, &st_exec);
|
||||
exec_mtime = st_exec.st_mtime;
|
||||
}
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No exec file now.\n");
|
||||
|
||||
/* Tell display code (if any) about the changed file name. */
|
||||
if (exec_file_display_hook)
|
||||
(*exec_file_display_hook) (filename);
|
||||
}
|
||||
|
||||
/* Call this to specify the hook for exec_file_command to call back.
|
||||
This is called from the x-window display code. */
|
||||
|
||||
void
|
||||
specify_exec_file_hook (hook)
|
||||
void (*hook) ();
|
||||
{
|
||||
@ -475,6 +167,7 @@ specify_exec_file_hook (hook)
|
||||
If it is needed again after the inferior dies, it must
|
||||
be reopened. */
|
||||
|
||||
void
|
||||
close_exec_file ()
|
||||
{
|
||||
if (execchan >= 0)
|
||||
@ -482,6 +175,7 @@ close_exec_file ()
|
||||
execchan = -1;
|
||||
}
|
||||
|
||||
void
|
||||
reopen_exec_file ()
|
||||
{
|
||||
if (execchan < 0 && execfile != 0)
|
||||
@ -497,7 +191,7 @@ reopen_exec_file ()
|
||||
This should really check that the core file came
|
||||
from that exec file, but I don't know how to do it. */
|
||||
|
||||
static void
|
||||
void
|
||||
validate_files ()
|
||||
{
|
||||
if (execfile != 0 && corefile != 0)
|
||||
@ -506,7 +200,7 @@ validate_files ()
|
||||
|
||||
fstat (corechan, &st_core);
|
||||
|
||||
if (core_aouthdr.a_magic != 0
|
||||
if (N_MAGIC (core_aouthdr) != 0
|
||||
&& bcmp (&core_aouthdr, &exec_aouthdr, sizeof core_aouthdr))
|
||||
printf ("Warning: core file does not match specified executable file.\n");
|
||||
else if (exec_mtime > st_core.st_mtime)
|
||||
@ -544,49 +238,54 @@ files_info ()
|
||||
printf ("Executable file \"%s\".\n", execfile);
|
||||
else
|
||||
printf ("No executable file\n");
|
||||
if (corefile == 0)
|
||||
printf ("No core dump file\n");
|
||||
|
||||
if (corefile)
|
||||
printf ("Core dump file \"%s\".\n", corefile);
|
||||
else
|
||||
printf ("Core dump file \"%s\".\n", corefile);
|
||||
printf ("No core dump file\n");
|
||||
|
||||
if (have_inferior_p ())
|
||||
printf ("Using the running image of the program, rather than these files.\n");
|
||||
|
||||
symfile = get_sym_file ();
|
||||
if (symfile != 0)
|
||||
printf ("Symbols loaded from \"%s\".\n", symfile);
|
||||
printf ("Symbols from \"%s\".\n", symfile);
|
||||
|
||||
if (! have_inferior_p ())
|
||||
{
|
||||
if (execfile)
|
||||
{
|
||||
printf ("Text segment from 0x%x to 0x%x.\n",
|
||||
printf ("Text segment in executable from 0x%x to 0x%x.\n",
|
||||
text_start, text_end);
|
||||
printf ("Data segment in executable from 0x%x to 0x%x.\n",
|
||||
exec_data_start, exec_data_end);
|
||||
if (corefile)
|
||||
printf("(But since we have a core file, we're using...)\n");
|
||||
}
|
||||
if (corefile)
|
||||
{
|
||||
printf ("Data segment from 0x%x to 0x%x.\nStack segment from 0x%x to 0x%x.\n",
|
||||
data_start, data_end, stack_start, stack_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Data segment in executable from 0x%x to 0x%x.\n",
|
||||
exec_data_start, exec_data_end);
|
||||
printf ("Data segment in core file from 0x%x to 0x%x.\n",
|
||||
data_start, data_end);
|
||||
printf ("Stack segment in core file from 0x%x to 0x%x.\n",
|
||||
stack_start, stack_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read "memory data" from core file and/or executable file */
|
||||
/* Read "memory data" from core file and/or executable file.
|
||||
Returns zero if successful, 1 if xfer_core_file failed, errno value if
|
||||
ptrace failed. */
|
||||
|
||||
int
|
||||
read_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
read_inferior_memory (memaddr, myaddr, len);
|
||||
return read_inferior_memory (memaddr, myaddr, len);
|
||||
else
|
||||
xfer_core_file (memaddr, myaddr, len, 0);
|
||||
return xfer_core_file (memaddr, myaddr, len);
|
||||
}
|
||||
|
||||
/* Write LEN bytes of data starting at address MYADDR
|
||||
@ -605,6 +304,15 @@ write_memory (memaddr, myaddr, len)
|
||||
error ("Can write memory only when program being debugged is running.");
|
||||
}
|
||||
|
||||
/* Read from the program's memory (except for inferior processes).
|
||||
This function is misnamed, since it only reads, never writes; and
|
||||
since it will use the core file and/or executable file as necessary.
|
||||
|
||||
It should be extended to write as well as read, FIXME, for patching files.
|
||||
|
||||
Return 0 if address could be read, 1 if not. */
|
||||
|
||||
int
|
||||
xfer_core_file (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
@ -615,6 +323,7 @@ xfer_core_file (memaddr, myaddr, len)
|
||||
int xferchan;
|
||||
char **xferfile;
|
||||
int fileptr;
|
||||
int returnval = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
@ -625,30 +334,17 @@ xfer_core_file (memaddr, myaddr, len)
|
||||
and where in the file. Set the file's read/write pointer
|
||||
to point at the proper place for the desired address
|
||||
and set xferfile and xferchan for the correct file.
|
||||
If desired address is nonexistent, leave them zero.
|
||||
i is set to the number of bytes that can be handled
|
||||
along with the next address. */
|
||||
|
||||
if (memaddr < text_start)
|
||||
{
|
||||
i = min (len, text_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= text_end && memaddr < data_start)
|
||||
{
|
||||
i = min (len, data_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end)
|
||||
&& memaddr < stack_start)
|
||||
{
|
||||
i = min (len, stack_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= stack_end && stack_end != 0)
|
||||
{
|
||||
i = min (len, - memaddr);
|
||||
}
|
||||
If desired address is nonexistent, leave them zero.
|
||||
|
||||
i is set to the number of bytes that can be handled
|
||||
along with the next address.
|
||||
|
||||
We put the most likely tests first for efficiency. */
|
||||
|
||||
/* Note that if there is no core file
|
||||
data_start and data_end are equal. */
|
||||
else if (memaddr >= data_start && memaddr < data_end)
|
||||
if (memaddr >= data_start && memaddr < data_end)
|
||||
{
|
||||
i = min (len, data_end - memaddr);
|
||||
fileptr = memaddr - data_start + data_offset;
|
||||
@ -679,6 +375,31 @@ xfer_core_file (memaddr, myaddr, len)
|
||||
xferfile = &execfile;
|
||||
xferchan = execchan;
|
||||
}
|
||||
else if (memaddr < text_start)
|
||||
{
|
||||
i = min (len, text_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= text_end
|
||||
&& memaddr < (corechan >= 0? data_start : exec_data_start))
|
||||
{
|
||||
i = min (len, data_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end)
|
||||
&& memaddr < stack_start)
|
||||
{
|
||||
i = min (len, stack_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= stack_end && stack_end != 0)
|
||||
{
|
||||
i = min (len, - memaddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Address did not classify into one of the known ranges.
|
||||
This could be because data_start != exec_data_start
|
||||
or data_end similarly. */
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Now we know which file to use.
|
||||
Set up its pointer and transfer the data. */
|
||||
@ -697,19 +418,25 @@ xfer_core_file (memaddr, myaddr, len)
|
||||
perror_with_name (*xferfile);
|
||||
}
|
||||
/* If this address is for nonexistent memory,
|
||||
read zeros if reading, or do nothing if writing. */
|
||||
read zeros if reading, or do nothing if writing.
|
||||
(FIXME we never write.) */
|
||||
else
|
||||
bzero (myaddr, i);
|
||||
{
|
||||
bzero (myaddr, i);
|
||||
returnval = 1;
|
||||
}
|
||||
|
||||
memaddr += i;
|
||||
myaddr += i;
|
||||
len -= i;
|
||||
}
|
||||
return returnval;
|
||||
}
|
||||
|
||||
/* My replacement for the read system call.
|
||||
Used like `read' but keeps going if `read' returns too soon. */
|
||||
|
||||
int
|
||||
myread (desc, addr, len)
|
||||
int desc;
|
||||
char *addr;
|
||||
@ -753,8 +480,8 @@ register_addr (regno, blockend)
|
||||
|
||||
#endif /* REGISTER_U_ADDR */
|
||||
|
||||
static
|
||||
initialize ()
|
||||
void
|
||||
_initialize_core()
|
||||
{
|
||||
corechan = -1;
|
||||
execchan = -1;
|
||||
@ -782,4 +509,3 @@ No arg means have no executable file.");
|
||||
add_info ("files", files_info, "Names of files being debugged.");
|
||||
}
|
||||
|
||||
END_FILE
|
||||
|
36
gdb/createtags
Executable file
36
gdb/createtags
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Here we check to see if we are compiling in a directory that contains
|
||||
# symlinks to the source files instead of the actual files. If this is so,
|
||||
# we setup the TAGS entries to point to the actual source directory.
|
||||
#
|
||||
filelist=""
|
||||
if test -h main.c ; then
|
||||
prefix=`ls -l main.c | awk '{print $11}' | sed 's;main.c$;;'`
|
||||
echo path 1
|
||||
else
|
||||
prefix=""
|
||||
fi
|
||||
for i in $@ ; do
|
||||
filelist="$prefix$i $filelist"
|
||||
done
|
||||
#
|
||||
# Here we simply make sure that the actual machine dependent files being used
|
||||
# (if any) are ahead of all of the other machine dependent files in the list.
|
||||
# This means that M-. will (almost) always give you exactly the routine
|
||||
# you want.
|
||||
#
|
||||
if test -f param.h ; then
|
||||
if `grep '^#define[ ]*COFF_FORMAT' param.h > /dev/null 2>&1`; then
|
||||
frmatfile=${prefix}coffread.c
|
||||
else
|
||||
frmatfile=${prefix}dbxread.c
|
||||
fi
|
||||
hfile=$prefix`ls -l param.h | awk '{print $11}'`
|
||||
dfile=$prefix`ls -l dep.c | awk '{print $11}'`
|
||||
ofile=$prefix`ls -l opcode.h | awk '{print $11}'`
|
||||
pfile=$prefix`ls -l pinsn.c | awk '{print $11}'`
|
||||
etags $hfile $dfile $ofile $pfile $frmatfile $filelist
|
||||
else
|
||||
etags $filelist
|
||||
fi
|
2136
gdb/dbxread.c
2136
gdb/dbxread.c
File diff suppressed because it is too large
Load Diff
601
gdb/default-dep.c
Normal file
601
gdb/default-dep.c
Normal file
@ -0,0 +1,601 @@
|
||||
/* Low level interface to ptrace, for GDB when running under Unix.
|
||||
Copyright (C) 1988 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
#define PMMU
|
||||
#define NEW_PMMU
|
||||
#define mc68881 /* Needed to get float in user.h!!! */
|
||||
#include <sys/seg.h> /* For user.h */
|
||||
#include <sys/mmu.h>
|
||||
#include <sys/time.h>
|
||||
/* Things Unisoft defined differently from every other Unix system */
|
||||
#define NBPG PAGESIZE
|
||||
#define UPAGES USIZE
|
||||
#define KERNEL_U_ADDR UDOT
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef COFF_ENCAPSULATE
|
||||
#include "a.out.encap.h"
|
||||
#else
|
||||
#include <a.out.h>
|
||||
#endif
|
||||
#ifndef N_SET_MAGIC
|
||||
#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
|
||||
#endif
|
||||
|
||||
#include <sys/user.h> /* After a.out.h */
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
/* This function simply calls ptrace with the given arguments.
|
||||
It exists so that all calls to ptrace are isolated in this
|
||||
machine-dependent file.
|
||||
|
||||
If you are having trouble debugging ptrace calls, turn on DEBUG
|
||||
and every call to ptrace, in this module or elsewhere, will be
|
||||
logged to stderr. */
|
||||
int
|
||||
call_ptrace (request, pid, arg3, arg4)
|
||||
int request, pid, arg3, arg4;
|
||||
{
|
||||
#ifdef DEBUG
|
||||
int result;
|
||||
|
||||
fprintf(stderr, "ptrace(%x,,%x, %x) = ", request, arg3, arg4);
|
||||
result=ptrace (request, pid, arg3, arg4);
|
||||
fprintf(stderr, "%x\n", result);
|
||||
return result;
|
||||
|
||||
#define ptrace call_ptrace
|
||||
|
||||
#else
|
||||
return ptrace (request, pid, arg3, arg4);
|
||||
#endif
|
||||
}
|
||||
|
||||
kill_inferior ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
inferior_died ();
|
||||
}
|
||||
|
||||
/* This is used when GDB is exiting. It gives less chance of error.*/
|
||||
|
||||
kill_inferior_fast ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
}
|
||||
|
||||
/* Resume execution of the inferior process.
|
||||
If STEP is nonzero, single-step it.
|
||||
If SIGNAL is nonzero, give it that signal. */
|
||||
|
||||
void
|
||||
resume (step, signal)
|
||||
int step;
|
||||
int signal;
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_resume (step, signal);
|
||||
else
|
||||
{
|
||||
ptrace (step ? 9 : 7, inferior_pid, 1, signal);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers ()
|
||||
{
|
||||
register int regno;
|
||||
register unsigned int regaddr;
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
*(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
If REGNO is -1, do this for all registers.
|
||||
Otherwise, REGNO specifies which register (so we can save time). */
|
||||
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[80];
|
||||
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
|
||||
|
||||
if (regno >= 0)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
errno = 0;
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
/* You can't write the PC with ptrace 6, only with ptrace 11! */
|
||||
if (regno == PC_REGNUM)
|
||||
ptrace(11, inferior_pid, 16, read_register(regno));
|
||||
else
|
||||
#endif
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
else for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
errno = 0;
|
||||
#ifdef UNISOFT_ASSHOLES
|
||||
if (regno == PC_REGNUM)
|
||||
ptrace(11, inferior_pid, 16, read_register(regno));
|
||||
else
|
||||
#endif
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing all regs, number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy LEN bytes from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR.
|
||||
On failure (cannot read from inferior, usually because address is out
|
||||
of bounds) returns the value of errno. */
|
||||
|
||||
int
|
||||
read_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
buffer[i] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[i] = ptrace (1, inferior_pid, addr, 0);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy LEN bytes of data from debugger memory at MYADDR
|
||||
to inferior's memory at MEMADDR.
|
||||
On failure (cannot write the inferior)
|
||||
returns the value of errno. */
|
||||
|
||||
int
|
||||
write_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Fill start and end extra bytes of buffer with existing memory data. */
|
||||
|
||||
if (remote_debugging)
|
||||
buffer[0] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[0] = ptrace (1, inferior_pid, addr, 0);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
if (remote_debugging)
|
||||
buffer[count - 1]
|
||||
= remote_fetch_word (addr + (count - 1) * sizeof (int));
|
||||
else
|
||||
buffer[count - 1]
|
||||
= ptrace (1, inferior_pid,
|
||||
addr + (count - 1) * sizeof (int), 0);
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_store_word (addr, buffer[i]);
|
||||
else
|
||||
ptrace (4, inferior_pid, addr, buffer[i]);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
This code would be in core.c if it weren't machine-dependent. */
|
||||
|
||||
/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
|
||||
#ifdef AOUTHDR
|
||||
#define COFF_FORMAT
|
||||
#endif
|
||||
|
||||
#ifndef N_TXTADDR
|
||||
#define N_TXTADDR(hdr) 0
|
||||
#endif /* no N_TXTADDR */
|
||||
|
||||
#ifndef N_DATADDR
|
||||
#define N_DATADDR(hdr) hdr.a_text
|
||||
#endif /* no N_DATADDR */
|
||||
|
||||
/* Make COFF and non-COFF names for things a little more compatible
|
||||
to reduce conditionals later. */
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
#define a_magic magic
|
||||
#endif
|
||||
|
||||
#ifndef COFF_FORMAT
|
||||
#define AOUTHDR struct exec
|
||||
#endif
|
||||
|
||||
extern char *sys_siglist[];
|
||||
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
extern void (*exec_file_display_hook) ();
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
extern char *corefile;
|
||||
extern char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
extern int corechan;
|
||||
extern int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
|
||||
extern int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
extern CORE_ADDR data_start;
|
||||
extern CORE_ADDR data_end;
|
||||
extern CORE_ADDR stack_start;
|
||||
extern CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
|
||||
extern CORE_ADDR text_start;
|
||||
extern CORE_ADDR text_end;
|
||||
|
||||
extern CORE_ADDR exec_data_start;
|
||||
extern CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
extern int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
extern int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
extern int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
extern int stack_offset;
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
/* various coff data structures */
|
||||
|
||||
extern FILHDR file_hdr;
|
||||
extern SCNHDR text_hdr;
|
||||
extern SCNHDR data_hdr;
|
||||
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
/* a.out header saved in core file. */
|
||||
|
||||
extern AOUTHDR core_aouthdr;
|
||||
|
||||
/* a.out header of exec file. */
|
||||
|
||||
extern AOUTHDR exec_aouthdr;
|
||||
|
||||
extern void validate_files ();
|
||||
|
||||
core_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
if (corefile)
|
||||
free (corefile);
|
||||
corefile = 0;
|
||||
|
||||
if (corechan >= 0)
|
||||
close (corechan);
|
||||
corechan = -1;
|
||||
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
/* Now, if a new core file was specified, open it and digest it. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
error ("To look at a core file, you must kill the inferior with \"kill\".");
|
||||
corechan = open (filename, O_RDONLY, 0);
|
||||
if (corechan < 0)
|
||||
perror_with_name (filename);
|
||||
/* 4.2-style (and perhaps also sysV-style) core dump file. */
|
||||
{
|
||||
struct user u;
|
||||
|
||||
int reg_offset;
|
||||
|
||||
val = myread (corechan, &u, sizeof u);
|
||||
if (val < 0)
|
||||
perror_with_name ("Not a core file: reading upage");
|
||||
if (val != sizeof u)
|
||||
error ("Not a core file: could only read %d bytes", val);
|
||||
data_start = exec_data_start;
|
||||
|
||||
data_end = data_start + NBPG * u.u_dsize;
|
||||
stack_start = stack_end - NBPG * u.u_ssize;
|
||||
data_offset = NBPG * UPAGES;
|
||||
stack_offset = NBPG * (UPAGES + u.u_dsize);
|
||||
|
||||
/* Some machines put an absolute address in here; Unisoft
|
||||
seems to put the offset in the upage of the regs. Sigh. */
|
||||
reg_offset = (int) u.u_ar0;
|
||||
if (reg_offset > NBPG * UPAGES)
|
||||
reg_offset -= KERNEL_U_ADDR;
|
||||
|
||||
/* I don't know where to find this info.
|
||||
So, for now, mark it as not available. */
|
||||
N_SET_MAGIC (core_aouthdr, 0);
|
||||
|
||||
/* Read the register values out of the core file and store
|
||||
them where `read_register' will find them. */
|
||||
|
||||
{
|
||||
register int regno;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
val = lseek (corechan, register_addr (regno, reg_offset), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (reg_names[regno]);
|
||||
|
||||
val = myread (corechan, buf, sizeof buf);
|
||||
if (val < 0)
|
||||
perror_with_name (reg_names[regno]);
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filename[0] == '/')
|
||||
corefile = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
corefile = concat (current_directory, "/", filename);
|
||||
}
|
||||
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
|
||||
read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No core file now.\n");
|
||||
}
|
||||
|
||||
exec_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
|
||||
/* Eliminate all traces of old exec file.
|
||||
Mark text segment as empty. */
|
||||
|
||||
if (execfile)
|
||||
free (execfile);
|
||||
execfile = 0;
|
||||
data_start = 0;
|
||||
data_end -= exec_data_start;
|
||||
text_start = 0;
|
||||
text_end = 0;
|
||||
exec_data_start = 0;
|
||||
exec_data_end = 0;
|
||||
if (execchan >= 0)
|
||||
close (execchan);
|
||||
execchan = -1;
|
||||
|
||||
/* Now open and digest the file the user requested, if any. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
|
||||
&execfile);
|
||||
if (execchan < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
{
|
||||
int aout_hdrsize;
|
||||
int num_sections;
|
||||
|
||||
if (read_file_hdr (execchan, &file_hdr) < 0)
|
||||
error ("\"%s\": not in executable format.", execfile);
|
||||
|
||||
aout_hdrsize = file_hdr.f_opthdr;
|
||||
num_sections = file_hdr.f_nscns;
|
||||
|
||||
if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
|
||||
error ("\"%s\": can't read optional aouthdr", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read text section header", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read data section header", execfile);
|
||||
|
||||
text_start = exec_aouthdr.text_start;
|
||||
text_end = text_start + exec_aouthdr.tsize;
|
||||
text_offset = text_hdr.s_scnptr;
|
||||
exec_data_start = exec_aouthdr.data_start;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.dsize;
|
||||
exec_data_offset = data_hdr.s_scnptr;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
exec_mtime = file_hdr.f_timdat;
|
||||
}
|
||||
#else /* not COFF_FORMAT */
|
||||
{
|
||||
struct stat st_exec;
|
||||
|
||||
#ifdef HEADER_SEEK_FD
|
||||
HEADER_SEEK_FD (execchan);
|
||||
#endif
|
||||
|
||||
val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
|
||||
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
text_start = N_TXTADDR (exec_aouthdr);
|
||||
exec_data_start = N_DATADDR (exec_aouthdr);
|
||||
|
||||
text_offset = N_TXTOFF (exec_aouthdr);
|
||||
exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
|
||||
|
||||
text_end = text_start + exec_aouthdr.a_text;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.a_data;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
|
||||
fstat (execchan, &st_exec);
|
||||
exec_mtime = st_exec.st_mtime;
|
||||
}
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No exec file now.\n");
|
||||
|
||||
/* Tell display code (if any) about the changed file name. */
|
||||
if (exec_file_display_hook)
|
||||
(*exec_file_display_hook) (filename);
|
||||
}
|
@ -26,6 +26,7 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
extern char *savestring ();
|
||||
extern char *concat ();
|
||||
extern char *xmalloc (), *xrealloc ();
|
||||
extern char *alloca ();
|
||||
extern int parse_escape ();
|
||||
extern char *reg_names[];
|
||||
|
||||
@ -37,8 +38,9 @@ extern int immediate_quit;
|
||||
|
||||
enum command_class
|
||||
{
|
||||
class_run, class_vars, class_stack, class_files, class_support, class_info,
|
||||
class_breakpoint, class_alias, class_obscure, class_user,
|
||||
no_class = -1, class_run = 0, class_vars, class_stack,
|
||||
class_files, class_support, class_info, class_breakpoint,
|
||||
class_alias, class_obscure, class_user,
|
||||
};
|
||||
|
||||
/* the cleanup list records things that have to be undone
|
||||
@ -61,6 +63,8 @@ struct cleanup
|
||||
extern void do_cleanups ();
|
||||
extern void discard_cleanups ();
|
||||
extern struct cleanup *make_cleanup ();
|
||||
extern struct cleanup *save_cleanups ();
|
||||
extern void restore_cleanups ();
|
||||
extern void free_current_contents ();
|
||||
|
||||
/* Structure for saved commands lines
|
||||
@ -81,3 +85,4 @@ char *current_directory;
|
||||
#ifdef sparc
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
|
166
gdb/eval.c
166
gdb/eval.c
@ -19,12 +19,11 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "initialize.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "value.h"
|
||||
#include "expression.h"
|
||||
|
||||
START_FILE
|
||||
|
||||
/* Parse the string EXP as a C expression, evaluate it,
|
||||
and return the result as a number. */
|
||||
@ -38,7 +37,7 @@ parse_and_eval_address (exp)
|
||||
register struct cleanup *old_chain
|
||||
= make_cleanup (free_current_contents, &expr);
|
||||
|
||||
addr = value_as_long (evaluate_expression (expr));
|
||||
addr = (CORE_ADDR) value_as_long (evaluate_expression (expr));
|
||||
do_cleanups (old_chain);
|
||||
return addr;
|
||||
}
|
||||
@ -104,9 +103,11 @@ static value evaluate_subexp_with_coercion ();
|
||||
|
||||
/* Values of NOSIDE argument to eval_subexp. */
|
||||
enum noside
|
||||
{ EVAL_NORMAL,
|
||||
EVAL_SKIP,
|
||||
EVAL_AVOID_SIDE_EFFECTS,
|
||||
{ EVAL_NORMAL,
|
||||
EVAL_SKIP, /* Only effect is to increment pos. */
|
||||
EVAL_AVOID_SIDE_EFFECTS, /* Don't modify any variables or
|
||||
call any functions. Correct type
|
||||
is returned. */
|
||||
};
|
||||
|
||||
value
|
||||
@ -137,7 +138,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
{
|
||||
enum exp_opcode op;
|
||||
int tem;
|
||||
register int pc, pc2, *oldpos;
|
||||
register int pc, pc2, oldpos;
|
||||
register value arg1, arg2, arg3;
|
||||
int nargs;
|
||||
value *argvec;
|
||||
@ -171,16 +172,38 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
|
||||
case OP_LAST:
|
||||
(*pos) += 2;
|
||||
return access_value_history (exp->elts[pc + 1].longconst);
|
||||
return access_value_history ((int) exp->elts[pc + 1].longconst);
|
||||
|
||||
case OP_REGISTER:
|
||||
(*pos) += 2;
|
||||
return value_of_register (exp->elts[pc + 1].longconst);
|
||||
return value_of_register ((int) exp->elts[pc + 1].longconst);
|
||||
|
||||
case OP_INTERNALVAR:
|
||||
(*pos) += 2;
|
||||
return value_of_internalvar (exp->elts[pc + 1].internalvar);
|
||||
|
||||
case OP_STRING:
|
||||
tem = strlen (&exp->elts[pc + 1].string);
|
||||
(*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
|
||||
if (noside == EVAL_SKIP)
|
||||
goto nosideret;
|
||||
return value_string (&exp->elts[pc + 1].string, tem);
|
||||
|
||||
case TERNOP_COND:
|
||||
/* Skip third and second args to evaluate the first one. */
|
||||
arg1 = evaluate_subexp (0, exp, pos, noside);
|
||||
if (value_zerop (arg1))
|
||||
{
|
||||
evaluate_subexp (0, exp, pos, EVAL_SKIP);
|
||||
return evaluate_subexp (0, exp, pos, noside);
|
||||
}
|
||||
else
|
||||
{
|
||||
arg2 = evaluate_subexp (0, exp, pos, noside);
|
||||
evaluate_subexp (0, exp, pos, EVAL_SKIP);
|
||||
return arg2;
|
||||
}
|
||||
|
||||
case OP_FUNCALL:
|
||||
(*pos) += 2;
|
||||
op = exp->elts[*pos].opcode;
|
||||
@ -189,7 +212,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
int fnptr;
|
||||
int tem2;
|
||||
|
||||
nargs = exp->elts[pc + 1].longconst + 1;
|
||||
nargs = (int) exp->elts[pc + 1].longconst + 1;
|
||||
/* First, evaluate the structure into arg2 */
|
||||
pc2 = (*pos)++;
|
||||
|
||||
@ -213,7 +236,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
|
||||
arg1 = evaluate_subexp (0, exp, pos, noside);
|
||||
|
||||
fnptr = value_as_long (arg1);
|
||||
fnptr = (int) value_as_long (arg1);
|
||||
if (fnptr < 128)
|
||||
{
|
||||
struct type *basetype;
|
||||
@ -262,7 +285,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
/* Hair for method invocations */
|
||||
int tem2;
|
||||
|
||||
nargs = exp->elts[pc + 1].longconst + 1;
|
||||
nargs = (int) exp->elts[pc + 1].longconst + 1;
|
||||
/* First, evaluate the structure into arg2 */
|
||||
pc2 = (*pos)++;
|
||||
tem2 = strlen (&exp->elts[pc2 + 1].string);
|
||||
@ -283,7 +306,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
}
|
||||
else
|
||||
{
|
||||
nargs = exp->elts[pc + 1].longconst;
|
||||
nargs = (int) exp->elts[pc + 1].longconst;
|
||||
tem = 0;
|
||||
}
|
||||
argvec = (value *) alloca (sizeof (value) * (nargs + 2));
|
||||
@ -311,31 +334,24 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
if (noside == EVAL_SKIP)
|
||||
goto nosideret;
|
||||
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
||||
return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])));
|
||||
{
|
||||
/* If the return type doesn't look like a function type, call an
|
||||
error. This can happen if somebody tries to turn a variable into
|
||||
a function call. This is here because people often want to
|
||||
call, eg, strcmp, which gdb doesn't know is a function. If
|
||||
gdb isn't asked for it's opinion (ie. through "whatis"),
|
||||
it won't offer it. */
|
||||
|
||||
struct type *ftype =
|
||||
TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]));
|
||||
|
||||
if (ftype)
|
||||
return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])));
|
||||
else
|
||||
error ("Expression of type other than \"Function returning ...\" used as function");
|
||||
}
|
||||
return call_function (argvec[0], nargs, argvec + 1);
|
||||
|
||||
case OP_STRING:
|
||||
tem = strlen (&exp->elts[pc + 1].string);
|
||||
(*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
|
||||
if (noside == EVAL_SKIP)
|
||||
goto nosideret;
|
||||
return value_string (&exp->elts[pc + 1].string, tem);
|
||||
|
||||
case TERNOP_COND:
|
||||
/* Skip third and second args to evaluate the first one. */
|
||||
arg1 = evaluate_subexp (0, exp, pos, noside);
|
||||
if (value_zerop (arg1))
|
||||
{
|
||||
evaluate_subexp (0, exp, pos, EVAL_SKIP);
|
||||
return evaluate_subexp (0, exp, pos, noside);
|
||||
}
|
||||
else
|
||||
{
|
||||
arg2 = evaluate_subexp (0, exp, pos, noside);
|
||||
evaluate_subexp (0, exp, pos, EVAL_SKIP);
|
||||
return arg2;
|
||||
}
|
||||
|
||||
case STRUCTOP_STRUCT:
|
||||
tem = strlen (&exp->elts[pc + 1].string);
|
||||
(*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
|
||||
@ -452,6 +468,16 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
|
||||
case BINOP_AND:
|
||||
arg1 = evaluate_subexp (0, exp, pos, noside);
|
||||
if (noside == EVAL_SKIP)
|
||||
{
|
||||
arg2 = evaluate_subexp (0, exp, pos, noside);
|
||||
goto nosideret;
|
||||
}
|
||||
|
||||
oldpos = *pos;
|
||||
arg2 = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
|
||||
*pos = oldpos;
|
||||
|
||||
if (binop_user_defined_p (op, arg1, arg2))
|
||||
{
|
||||
arg2 = evaluate_subexp (0, exp, pos, noside);
|
||||
@ -463,11 +489,21 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
arg2 = evaluate_subexp (0, exp, pos,
|
||||
(tem ? EVAL_SKIP : noside));
|
||||
return value_from_long (builtin_type_int,
|
||||
!tem && !value_zerop (arg2));
|
||||
(LONGEST) (!tem && !value_zerop (arg2)));
|
||||
}
|
||||
|
||||
case BINOP_OR:
|
||||
arg1 = evaluate_subexp (0, exp, pos, noside);
|
||||
if (noside == EVAL_SKIP)
|
||||
{
|
||||
arg2 = evaluate_subexp (0, exp, pos, noside);
|
||||
goto nosideret;
|
||||
}
|
||||
|
||||
oldpos = *pos;
|
||||
arg2 = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
|
||||
*pos = oldpos;
|
||||
|
||||
if (binop_user_defined_p (op, arg1, arg2))
|
||||
{
|
||||
arg2 = evaluate_subexp (0, exp, pos, noside);
|
||||
@ -479,7 +515,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
arg2 = evaluate_subexp (0, exp, pos,
|
||||
(!tem ? EVAL_SKIP : noside));
|
||||
return value_from_long (builtin_type_int,
|
||||
!tem || !value_zerop (arg2));
|
||||
(LONGEST) (!tem || !value_zerop (arg2)));
|
||||
}
|
||||
|
||||
case BINOP_EQUAL:
|
||||
@ -494,7 +530,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
else
|
||||
{
|
||||
tem = value_equal (arg1, arg2);
|
||||
return value_from_long (builtin_type_int, tem);
|
||||
return value_from_long (builtin_type_int, (LONGEST) tem);
|
||||
}
|
||||
|
||||
case BINOP_NOTEQUAL:
|
||||
@ -509,7 +545,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
else
|
||||
{
|
||||
tem = value_equal (arg1, arg2);
|
||||
return value_from_long (builtin_type_int, ! tem);
|
||||
return value_from_long (builtin_type_int, (LONGEST) ! tem);
|
||||
}
|
||||
|
||||
case BINOP_LESS:
|
||||
@ -524,7 +560,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
else
|
||||
{
|
||||
tem = value_less (arg1, arg2);
|
||||
return value_from_long (builtin_type_int, tem);
|
||||
return value_from_long (builtin_type_int, (LONGEST) tem);
|
||||
}
|
||||
|
||||
case BINOP_GTR:
|
||||
@ -539,7 +575,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
else
|
||||
{
|
||||
tem = value_less (arg2, arg1);
|
||||
return value_from_long (builtin_type_int, tem);
|
||||
return value_from_long (builtin_type_int, (LONGEST) tem);
|
||||
}
|
||||
|
||||
case BINOP_GEQ:
|
||||
@ -554,7 +590,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
else
|
||||
{
|
||||
tem = value_less (arg1, arg2);
|
||||
return value_from_long (builtin_type_int, ! tem);
|
||||
return value_from_long (builtin_type_int, (LONGEST) ! tem);
|
||||
}
|
||||
|
||||
case BINOP_LEQ:
|
||||
@ -569,7 +605,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
else
|
||||
{
|
||||
tem = value_less (arg2, arg1);
|
||||
return value_from_long (builtin_type_int, ! tem);
|
||||
return value_from_long (builtin_type_int, (LONGEST) ! tem);
|
||||
}
|
||||
|
||||
case BINOP_REPEAT:
|
||||
@ -577,7 +613,7 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
arg2 = evaluate_subexp (0, exp, pos, noside);
|
||||
if (noside == EVAL_SKIP)
|
||||
goto nosideret;
|
||||
return value_repeat (arg1, value_as_long (arg2));
|
||||
return value_repeat (arg1, (int) value_as_long (arg2));
|
||||
|
||||
case BINOP_COMMA:
|
||||
evaluate_subexp (0, exp, pos, noside);
|
||||
@ -608,7 +644,8 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
if (unop_user_defined_p (op, arg1))
|
||||
return value_x_unop (arg1, op, 0);
|
||||
else
|
||||
return value_from_long (builtin_type_int, value_zerop (arg1));
|
||||
return value_from_long (builtin_type_int,
|
||||
(LONGEST) value_zerop (arg1));
|
||||
|
||||
case UNOP_IND:
|
||||
if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
|
||||
@ -670,7 +707,8 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
arg1 = evaluate_subexp (expect_type, exp, pos, noside);
|
||||
if (noside == EVAL_SKIP)
|
||||
goto nosideret;
|
||||
return value_at (exp->elts[pc + 1].type, value_as_long (arg1));
|
||||
return value_at (exp->elts[pc + 1].type,
|
||||
(CORE_ADDR) value_as_long (arg1));
|
||||
|
||||
case UNOP_PREINCREMENT:
|
||||
arg1 = evaluate_subexp (expect_type, exp, pos, noside);
|
||||
@ -682,7 +720,8 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
}
|
||||
else
|
||||
{
|
||||
arg2 = value_add (arg1, value_from_long (builtin_type_char, 1));
|
||||
arg2 = value_add (arg1, value_from_long (builtin_type_char,
|
||||
(LONGEST) 1));
|
||||
return value_assign (arg1, arg2);
|
||||
}
|
||||
|
||||
@ -696,7 +735,8 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
}
|
||||
else
|
||||
{
|
||||
arg2 = value_sub (arg1, value_from_long (builtin_type_char, 1));
|
||||
arg2 = value_sub (arg1, value_from_long (builtin_type_char,
|
||||
(LONGEST) 1));
|
||||
return value_assign (arg1, arg2);
|
||||
}
|
||||
|
||||
@ -710,7 +750,8 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
}
|
||||
else
|
||||
{
|
||||
arg2 = value_add (arg1, value_from_long (builtin_type_char, 1));
|
||||
arg2 = value_add (arg1, value_from_long (builtin_type_char,
|
||||
(LONGEST) 1));
|
||||
value_assign (arg1, arg2);
|
||||
return arg1;
|
||||
}
|
||||
@ -725,7 +766,8 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
}
|
||||
else
|
||||
{
|
||||
arg2 = value_sub (arg1, value_from_long (builtin_type_char, 1));
|
||||
arg2 = value_sub (arg1, value_from_long (builtin_type_char,
|
||||
(LONGEST) 1));
|
||||
value_assign (arg1, arg2);
|
||||
return arg1;
|
||||
}
|
||||
@ -735,11 +777,11 @@ evaluate_subexp (expect_type, exp, pos, noside)
|
||||
return value_of_this (1);
|
||||
|
||||
default:
|
||||
error ("internal error: I dont know how to evaluation what you gave me");
|
||||
error ("internal error: I do not know how to evaluate what you gave me");
|
||||
}
|
||||
|
||||
nosideret:
|
||||
return value_from_long (builtin_type_long, 1);
|
||||
return value_from_long (builtin_type_long, (LONGEST) 1);
|
||||
}
|
||||
|
||||
/* Evaluate a subexpression of EXP, at index *POS,
|
||||
@ -839,28 +881,22 @@ evaluate_subexp_for_sizeof (exp, pos)
|
||||
case UNOP_IND:
|
||||
(*pos)++;
|
||||
val = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
|
||||
return value_from_long (builtin_type_int,
|
||||
TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val))));
|
||||
return value_from_long (builtin_type_int, (LONGEST)
|
||||
TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val))));
|
||||
|
||||
case UNOP_MEMVAL:
|
||||
(*pos) += 3;
|
||||
return value_from_long (builtin_type_int,
|
||||
TYPE_LENGTH (exp->elts[pc + 1].type));
|
||||
return value_from_long (builtin_type_int,
|
||||
(LONGEST) TYPE_LENGTH (exp->elts[pc + 1].type));
|
||||
|
||||
case OP_VAR_VALUE:
|
||||
(*pos) += 3;
|
||||
return value_from_long (builtin_type_int,
|
||||
TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 1].symbol)));
|
||||
(LONGEST) TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 1].symbol)));
|
||||
|
||||
default:
|
||||
val = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
|
||||
return value_from_long (builtin_type_int,
|
||||
TYPE_LENGTH (VALUE_TYPE (val)));
|
||||
(LONGEST) TYPE_LENGTH (VALUE_TYPE (val)));
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
initialize ()
|
||||
{ }
|
||||
|
||||
END_FILE
|
||||
|
@ -20,6 +20,7 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
#include "defs.h"
|
||||
#include "symtab.h"
|
||||
#include "param.h"
|
||||
#include "expression.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -79,7 +80,9 @@ static struct op_print op_print_tab[] =
|
||||
{"&", UNOP_ADDR, PREC_PREFIX, 0},
|
||||
{"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
|
||||
{"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
|
||||
{"--", UNOP_PREDECREMENT, PREC_PREFIX, 0}
|
||||
{"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
|
||||
/* C++ */
|
||||
{"::", BINOP_SCOPE, PREC_PREFIX, 0},
|
||||
};
|
||||
|
||||
static void print_subexp ();
|
||||
@ -119,6 +122,18 @@ print_subexp (exp, pos, stream, prec)
|
||||
opcode = exp->elts[pc].opcode;
|
||||
switch (opcode)
|
||||
{
|
||||
case OP_SCOPE:
|
||||
myprec = PREC_PREFIX;
|
||||
assoc = 0;
|
||||
(*pos) += 2;
|
||||
print_subexp (exp, pos, stream, (int) myprec + assoc);
|
||||
fprintf (stream, " :: ");
|
||||
nargs = strlen (&exp->elts[pc + 2].string);
|
||||
(*pos) += 1 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element);
|
||||
|
||||
fprintf (stream, &exp->elts[pc + 2].string);
|
||||
return;
|
||||
|
||||
case OP_LONG:
|
||||
(*pos) += 3;
|
||||
value_print (value_from_long (exp->elts[pc + 1].type,
|
||||
|
@ -13,9 +13,8 @@ static int expout_size;
|
||||
static int expout_ptr;
|
||||
|
||||
static int yylex ();
|
||||
static yyerror ();
|
||||
static void yyerror ();
|
||||
static void write_exp_elt ();
|
||||
static void write_exp_elt2 ();
|
||||
static void write_exp_string ();
|
||||
static void start_arglist ();
|
||||
static int end_arglist ();
|
||||
@ -27,6 +26,13 @@ static char *copy_name ();
|
||||
|
||||
static struct block *expression_context_block;
|
||||
|
||||
/* The innermost context required by the stack and register variables
|
||||
we've encountered so far. */
|
||||
struct block *innermost_block;
|
||||
|
||||
/* The block in which the most recently discovered symbol was found. */
|
||||
struct block *block_found;
|
||||
|
||||
/* Number of arguments seen so far in innermost function call. */
|
||||
static int arglist_len;
|
||||
|
||||
@ -50,7 +56,7 @@ struct stoken
|
||||
int length;
|
||||
};
|
||||
|
||||
# line 86 "expread.y"
|
||||
# line 92 "expread.y"
|
||||
typedef union
|
||||
{
|
||||
long lval;
|
||||
@ -106,7 +112,7 @@ extern short yyerrflag;
|
||||
YYSTYPE yylval, yyval;
|
||||
# define YYERRCODE 256
|
||||
|
||||
# line 625 "expread.y"
|
||||
# line 630 "expread.y"
|
||||
|
||||
|
||||
/* Begin counting arguments for a function call,
|
||||
@ -157,16 +163,13 @@ free_funcalls ()
|
||||
|
||||
/* Add one element to the end of the expression. */
|
||||
|
||||
/* To avoid a bug in the Sun 4 compiler, we pass only things that
|
||||
can fit into a single register through here. */
|
||||
/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into
|
||||
a register through here */
|
||||
|
||||
static void
|
||||
write_exp_elt (expelt)
|
||||
/* union exp_element expelt; */
|
||||
long expelt;
|
||||
union exp_element expelt;
|
||||
{
|
||||
union exp_element temp;
|
||||
temp.longconst = expelt;
|
||||
|
||||
if (expout_ptr >= expout_size)
|
||||
{
|
||||
expout_size *= 2;
|
||||
@ -174,25 +177,73 @@ write_exp_elt (expelt)
|
||||
sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
}
|
||||
expout->elts[expout_ptr++] = /* expelt */ temp;
|
||||
expout->elts[expout_ptr++] = expelt;
|
||||
}
|
||||
|
||||
/* Things that take more space must come through here. */
|
||||
static void
|
||||
write_exp_elt2 (expelt)
|
||||
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 temp;
|
||||
temp.doubleconst = expelt;
|
||||
union exp_element tmp;
|
||||
|
||||
if (expout_ptr >= expout_size)
|
||||
{
|
||||
expout_size *= 2;
|
||||
expout = (struct expression *) xrealloc (expout,
|
||||
sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
}
|
||||
expout->elts[expout_ptr++] = temp;
|
||||
tmp.doubleconst = expelt;
|
||||
|
||||
write_exp_elt (tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
write_exp_elt_type (expelt)
|
||||
struct type *expelt;
|
||||
{
|
||||
union exp_element tmp;
|
||||
|
||||
tmp.type = expelt;
|
||||
|
||||
write_exp_elt (tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
write_exp_elt_intern (expelt)
|
||||
struct internalvar *expelt;
|
||||
{
|
||||
union exp_element tmp;
|
||||
|
||||
tmp.internalvar = expelt;
|
||||
|
||||
write_exp_elt (tmp);
|
||||
}
|
||||
|
||||
/* Add a string constant to the end of the expression.
|
||||
@ -211,13 +262,13 @@ write_exp_string (str)
|
||||
if (expout_ptr >= expout_size)
|
||||
{
|
||||
expout_size = max (expout_size * 2, expout_ptr + 10);
|
||||
expout = (struct expression *) xrealloc (expout,
|
||||
sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
expout = (struct expression *)
|
||||
xrealloc (expout, (sizeof (struct expression)
|
||||
+ (expout_size * sizeof (union exp_element))));
|
||||
}
|
||||
bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len);
|
||||
((char *) &expout->elts[expout_ptr - lenelt])[len] = 0;
|
||||
write_exp_elt (len);
|
||||
write_exp_elt_longcst (len);
|
||||
}
|
||||
|
||||
/* During parsing of a C expression, the pointer to the next character
|
||||
@ -284,12 +335,13 @@ parse_number (olen)
|
||||
while (len-- > 0)
|
||||
{
|
||||
c = *p++;
|
||||
n *= base;
|
||||
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
|
||||
if (c != 'l')
|
||||
n *= base;
|
||||
if (c >= '0' && c <= '9')
|
||||
n += c - '0';
|
||||
else
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
|
||||
if (base == 16 && c >= 'a' && c <= 'f')
|
||||
n += c - 'a' + 10;
|
||||
else if (len == 0 && c == 'l')
|
||||
@ -346,6 +398,29 @@ static struct token tokentab2[] =
|
||||
{">=", GEQ, BINOP_END}
|
||||
};
|
||||
|
||||
/* assign machine-independent names to certain registers
|
||||
* (unless overridden by the REGISTER_NAMES table)
|
||||
*/
|
||||
struct std_regs {
|
||||
char *name;
|
||||
int regnum;
|
||||
} std_regs[] = {
|
||||
#ifdef PC_REGNUM
|
||||
{ "pc", PC_REGNUM },
|
||||
#endif
|
||||
#ifdef FP_REGNUM
|
||||
{ "fp", FP_REGNUM },
|
||||
#endif
|
||||
#ifdef SP_REGNUM
|
||||
{ "sp", SP_REGNUM },
|
||||
#endif
|
||||
#ifdef PS_REGNUM
|
||||
{ "ps", PS_REGNUM },
|
||||
#endif
|
||||
};
|
||||
|
||||
#define NUM_STD_REGS (sizeof std_regs / sizeof std_regs[0])
|
||||
|
||||
/* Read one token, getting characters through lexptr. */
|
||||
|
||||
static int
|
||||
@ -529,7 +604,7 @@ yylex ()
|
||||
/* Handle tokens that refer to machine registers:
|
||||
$ followed by a register name. */
|
||||
|
||||
if (*tokstart == '$')
|
||||
if (*tokstart == '$') {
|
||||
for (c = 0; c < NUM_REGS; c++)
|
||||
if (namelen - 1 == strlen (reg_names[c])
|
||||
&& !strncmp (tokstart + 1, reg_names[c], namelen - 1))
|
||||
@ -537,7 +612,14 @@ yylex ()
|
||||
yylval.lval = c;
|
||||
return REGNAME;
|
||||
}
|
||||
|
||||
for (c = 0; c < NUM_STD_REGS; c++)
|
||||
if (namelen - 1 == strlen (std_regs[c].name)
|
||||
&& !strncmp (tokstart + 1, std_regs[c].name, namelen - 1))
|
||||
{
|
||||
yylval.lval = std_regs[c].regnum;
|
||||
return REGNAME;
|
||||
}
|
||||
}
|
||||
if (namelen == 6 && !strncmp (tokstart, "struct", 6))
|
||||
{
|
||||
return STRUCT;
|
||||
@ -555,10 +637,10 @@ yylex ()
|
||||
{
|
||||
return ENUM;
|
||||
}
|
||||
if (!strncmp (tokstart, "this", 4))
|
||||
{
|
||||
return THIS;
|
||||
}
|
||||
if (!strncmp (tokstart, "this", 4)
|
||||
&& lookup_symbol ("$this", expression_context_block,
|
||||
VAR_NAMESPACE, 0))
|
||||
return THIS;
|
||||
}
|
||||
if (namelen == 6 && !strncmp (tokstart, "sizeof", 6))
|
||||
{
|
||||
@ -587,7 +669,7 @@ yylex ()
|
||||
return NAME;
|
||||
}
|
||||
|
||||
static
|
||||
static void
|
||||
yyerror ()
|
||||
{
|
||||
error ("Invalid syntax in expression.");
|
||||
@ -846,6 +928,8 @@ parse_c_1 (stringptr, block, comma)
|
||||
|
||||
lexptr = *stringptr;
|
||||
|
||||
paren_depth = 0;
|
||||
|
||||
comma_terminates = comma;
|
||||
|
||||
if (lexptr == 0 || *lexptr == 0)
|
||||
@ -859,8 +943,9 @@ parse_c_1 (stringptr, block, comma)
|
||||
namecopy = (char *) alloca (strlen (lexptr) + 1);
|
||||
expout_size = 10;
|
||||
expout_ptr = 0;
|
||||
expout = (struct expression *) xmalloc (sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
expout = (struct expression *)
|
||||
xmalloc (sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
make_cleanup (free_current_contents, &expout);
|
||||
if (yyparse ())
|
||||
yyerror ();
|
||||
@ -1054,7 +1139,7 @@ short yydef[]={
|
||||
0, 23, 0, 69, 0, 70, 0, 77, 71, 0,
|
||||
78 };
|
||||
#ifndef lint
|
||||
static char yaccpar_sccsid[] = "@(#)yaccpar 1.6 88/02/08 SMI"; /* from UCB 4.1 83/02/11 */
|
||||
static char yaccpar_sccsid[] = "@(#)yaccpar 1.5 86/08/27 SMI"; /* from UCB 4.1 83/02/11 */
|
||||
#endif
|
||||
|
||||
#
|
||||
@ -1203,202 +1288,202 @@ yyparse() {
|
||||
switch(yym){
|
||||
|
||||
case 3:
|
||||
# line 159 "expread.y"
|
||||
{ write_exp_elt (BINOP_COMMA); } break;
|
||||
# line 165 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_COMMA); } break;
|
||||
case 4:
|
||||
# line 164 "expread.y"
|
||||
{ write_exp_elt (UNOP_IND); } break;
|
||||
case 5:
|
||||
# line 167 "expread.y"
|
||||
{ write_exp_elt (UNOP_ADDR); } break;
|
||||
case 6:
|
||||
# line 170 "expread.y"
|
||||
{ write_exp_elt (UNOP_NEG); } break;
|
||||
{ write_exp_elt_opcode (UNOP_IND); } break;
|
||||
case 5:
|
||||
# line 173 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_ADDR); } break;
|
||||
case 6:
|
||||
# line 176 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_NEG); } break;
|
||||
case 7:
|
||||
# line 174 "expread.y"
|
||||
{ write_exp_elt (UNOP_ZEROP); } break;
|
||||
# line 180 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_ZEROP); } break;
|
||||
case 8:
|
||||
# line 178 "expread.y"
|
||||
{ write_exp_elt (UNOP_LOGNOT); } break;
|
||||
# line 184 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_LOGNOT); } break;
|
||||
case 9:
|
||||
# line 182 "expread.y"
|
||||
{ write_exp_elt (UNOP_PREINCREMENT); } break;
|
||||
# line 188 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_PREINCREMENT); } break;
|
||||
case 10:
|
||||
# line 186 "expread.y"
|
||||
{ write_exp_elt (UNOP_PREDECREMENT); } break;
|
||||
# line 192 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_PREDECREMENT); } break;
|
||||
case 11:
|
||||
# line 190 "expread.y"
|
||||
{ write_exp_elt (UNOP_POSTINCREMENT); } break;
|
||||
# line 196 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_POSTINCREMENT); } break;
|
||||
case 12:
|
||||
# line 194 "expread.y"
|
||||
{ write_exp_elt (UNOP_POSTDECREMENT); } break;
|
||||
# line 200 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_POSTDECREMENT); } break;
|
||||
case 13:
|
||||
# line 198 "expread.y"
|
||||
{ write_exp_elt (UNOP_SIZEOF); } break;
|
||||
# line 204 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_SIZEOF); } break;
|
||||
case 14:
|
||||
# line 202 "expread.y"
|
||||
{ write_exp_elt (STRUCTOP_PTR);
|
||||
write_exp_string (yypvt[-0].sval);
|
||||
write_exp_elt (STRUCTOP_PTR); } break;
|
||||
case 15:
|
||||
# line 208 "expread.y"
|
||||
{ write_exp_elt (STRUCTOP_MPTR); } break;
|
||||
case 16:
|
||||
# line 212 "expread.y"
|
||||
{ write_exp_elt (STRUCTOP_STRUCT);
|
||||
{ write_exp_elt_opcode (STRUCTOP_PTR);
|
||||
write_exp_string (yypvt[-0].sval);
|
||||
write_exp_elt (STRUCTOP_STRUCT); } break;
|
||||
case 17:
|
||||
write_exp_elt_opcode (STRUCTOP_PTR); } break;
|
||||
case 15:
|
||||
# line 214 "expread.y"
|
||||
{ write_exp_elt_opcode (STRUCTOP_MPTR); } break;
|
||||
case 16:
|
||||
# line 218 "expread.y"
|
||||
{ write_exp_elt (STRUCTOP_MEMBER); } break;
|
||||
{ write_exp_elt_opcode (STRUCTOP_STRUCT);
|
||||
write_exp_string (yypvt[-0].sval);
|
||||
write_exp_elt_opcode (STRUCTOP_STRUCT); } break;
|
||||
case 17:
|
||||
# line 224 "expread.y"
|
||||
{ write_exp_elt_opcode (STRUCTOP_MEMBER); } break;
|
||||
case 18:
|
||||
# line 222 "expread.y"
|
||||
{ write_exp_elt (BINOP_SUBSCRIPT); } break;
|
||||
case 19:
|
||||
# line 228 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_SUBSCRIPT); } break;
|
||||
case 19:
|
||||
# line 234 "expread.y"
|
||||
{ start_arglist (); } break;
|
||||
case 20:
|
||||
# line 230 "expread.y"
|
||||
{ write_exp_elt (OP_FUNCALL);
|
||||
write_exp_elt (end_arglist ());
|
||||
write_exp_elt (OP_FUNCALL); } break;
|
||||
# line 236 "expread.y"
|
||||
{ write_exp_elt_opcode (OP_FUNCALL);
|
||||
write_exp_elt_longcst (end_arglist ());
|
||||
write_exp_elt_opcode (OP_FUNCALL); } break;
|
||||
case 22:
|
||||
# line 239 "expread.y"
|
||||
# line 245 "expread.y"
|
||||
{ arglist_len = 1; } break;
|
||||
case 23:
|
||||
# line 243 "expread.y"
|
||||
# line 249 "expread.y"
|
||||
{ arglist_len++; } break;
|
||||
case 24:
|
||||
# line 247 "expread.y"
|
||||
{ write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt (yypvt[-2].tval);
|
||||
write_exp_elt (UNOP_MEMVAL); } break;
|
||||
case 25:
|
||||
# line 253 "expread.y"
|
||||
{ write_exp_elt (UNOP_CAST);
|
||||
write_exp_elt (yypvt[-2].tval);
|
||||
write_exp_elt (UNOP_CAST); } break;
|
||||
case 26:
|
||||
{ write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
write_exp_elt_type (yypvt[-2].tval);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL); } break;
|
||||
case 25:
|
||||
# line 259 "expread.y"
|
||||
{ write_exp_elt_opcode (UNOP_CAST);
|
||||
write_exp_elt_type (yypvt[-2].tval);
|
||||
write_exp_elt_opcode (UNOP_CAST); } break;
|
||||
case 26:
|
||||
# line 265 "expread.y"
|
||||
{ } break;
|
||||
case 27:
|
||||
# line 265 "expread.y"
|
||||
{ write_exp_elt (BINOP_REPEAT); } break;
|
||||
# line 271 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_REPEAT); } break;
|
||||
case 28:
|
||||
# line 269 "expread.y"
|
||||
{ write_exp_elt (BINOP_MUL); } break;
|
||||
# line 275 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_MUL); } break;
|
||||
case 29:
|
||||
# line 273 "expread.y"
|
||||
{ write_exp_elt (BINOP_DIV); } break;
|
||||
# line 279 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_DIV); } break;
|
||||
case 30:
|
||||
# line 277 "expread.y"
|
||||
{ write_exp_elt (BINOP_REM); } break;
|
||||
# line 283 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_REM); } break;
|
||||
case 31:
|
||||
# line 281 "expread.y"
|
||||
{ write_exp_elt (BINOP_ADD); } break;
|
||||
# line 287 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_ADD); } break;
|
||||
case 32:
|
||||
# line 285 "expread.y"
|
||||
{ write_exp_elt (BINOP_SUB); } break;
|
||||
# line 291 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_SUB); } break;
|
||||
case 33:
|
||||
# line 289 "expread.y"
|
||||
{ write_exp_elt (BINOP_LSH); } break;
|
||||
# line 295 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_LSH); } break;
|
||||
case 34:
|
||||
# line 293 "expread.y"
|
||||
{ write_exp_elt (BINOP_RSH); } break;
|
||||
# line 299 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_RSH); } break;
|
||||
case 35:
|
||||
# line 297 "expread.y"
|
||||
{ write_exp_elt (BINOP_EQUAL); } break;
|
||||
# line 303 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_EQUAL); } break;
|
||||
case 36:
|
||||
# line 301 "expread.y"
|
||||
{ write_exp_elt (BINOP_NOTEQUAL); } break;
|
||||
# line 307 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_NOTEQUAL); } break;
|
||||
case 37:
|
||||
# line 305 "expread.y"
|
||||
{ write_exp_elt (BINOP_LEQ); } break;
|
||||
# line 311 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_LEQ); } break;
|
||||
case 38:
|
||||
# line 309 "expread.y"
|
||||
{ write_exp_elt (BINOP_GEQ); } break;
|
||||
# line 315 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_GEQ); } break;
|
||||
case 39:
|
||||
# line 313 "expread.y"
|
||||
{ write_exp_elt (BINOP_LESS); } break;
|
||||
# line 319 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_LESS); } break;
|
||||
case 40:
|
||||
# line 317 "expread.y"
|
||||
{ write_exp_elt (BINOP_GTR); } break;
|
||||
# line 323 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_GTR); } break;
|
||||
case 41:
|
||||
# line 321 "expread.y"
|
||||
{ write_exp_elt (BINOP_LOGAND); } break;
|
||||
# line 327 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_LOGAND); } break;
|
||||
case 42:
|
||||
# line 325 "expread.y"
|
||||
{ write_exp_elt (BINOP_LOGXOR); } break;
|
||||
# line 331 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_LOGXOR); } break;
|
||||
case 43:
|
||||
# line 329 "expread.y"
|
||||
{ write_exp_elt (BINOP_LOGIOR); } break;
|
||||
# line 335 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_LOGIOR); } break;
|
||||
case 44:
|
||||
# line 333 "expread.y"
|
||||
{ write_exp_elt (BINOP_AND); } break;
|
||||
# line 339 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_AND); } break;
|
||||
case 45:
|
||||
# line 337 "expread.y"
|
||||
{ write_exp_elt (BINOP_OR); } break;
|
||||
# line 343 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_OR); } break;
|
||||
case 46:
|
||||
# line 341 "expread.y"
|
||||
{ write_exp_elt (TERNOP_COND); } break;
|
||||
# line 347 "expread.y"
|
||||
{ write_exp_elt_opcode (TERNOP_COND); } break;
|
||||
case 47:
|
||||
# line 345 "expread.y"
|
||||
{ write_exp_elt (BINOP_ASSIGN); } break;
|
||||
# line 351 "expread.y"
|
||||
{ write_exp_elt_opcode (BINOP_ASSIGN); } break;
|
||||
case 48:
|
||||
# line 349 "expread.y"
|
||||
{ write_exp_elt (BINOP_ASSIGN_MODIFY);
|
||||
write_exp_elt (yypvt[-1].opcode);
|
||||
write_exp_elt (BINOP_ASSIGN_MODIFY); } break;
|
||||
case 49:
|
||||
# line 355 "expread.y"
|
||||
{ write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_long);
|
||||
write_exp_elt (yypvt[-0].lval);
|
||||
write_exp_elt (OP_LONG); } break;
|
||||
{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
|
||||
write_exp_elt_opcode (yypvt[-1].opcode);
|
||||
write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); } break;
|
||||
case 49:
|
||||
# line 361 "expread.y"
|
||||
{ write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_long);
|
||||
write_exp_elt_longcst (yypvt[-0].lval);
|
||||
write_exp_elt_opcode (OP_LONG); } break;
|
||||
case 50:
|
||||
# line 362 "expread.y"
|
||||
{ write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_char);
|
||||
write_exp_elt (yypvt[-0].lval);
|
||||
write_exp_elt (OP_LONG); } break;
|
||||
# line 368 "expread.y"
|
||||
{ write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_char);
|
||||
write_exp_elt_longcst (yypvt[-0].lval);
|
||||
write_exp_elt_opcode (OP_LONG); } break;
|
||||
case 51:
|
||||
# line 369 "expread.y"
|
||||
{ write_exp_elt (OP_DOUBLE);
|
||||
write_exp_elt (builtin_type_double);
|
||||
write_exp_elt2 (yypvt[-0].dval);
|
||||
write_exp_elt (OP_DOUBLE); } break;
|
||||
# line 375 "expread.y"
|
||||
{ write_exp_elt_opcode (OP_DOUBLE);
|
||||
write_exp_elt_type (builtin_type_double);
|
||||
write_exp_elt_dblcst (yypvt[-0].dval);
|
||||
write_exp_elt_opcode (OP_DOUBLE); } break;
|
||||
case 53:
|
||||
# line 379 "expread.y"
|
||||
{ write_exp_elt (OP_LAST);
|
||||
write_exp_elt (yypvt[-0].lval);
|
||||
write_exp_elt (OP_LAST); } break;
|
||||
case 54:
|
||||
# line 385 "expread.y"
|
||||
{ write_exp_elt (OP_REGISTER);
|
||||
write_exp_elt (yypvt[-0].lval);
|
||||
write_exp_elt (OP_REGISTER); } break;
|
||||
case 55:
|
||||
{ write_exp_elt_opcode (OP_LAST);
|
||||
write_exp_elt_longcst (yypvt[-0].lval);
|
||||
write_exp_elt_opcode (OP_LAST); } break;
|
||||
case 54:
|
||||
# line 391 "expread.y"
|
||||
{ write_exp_elt (OP_INTERNALVAR);
|
||||
write_exp_elt (yypvt[-0].ivar);
|
||||
write_exp_elt (OP_INTERNALVAR); } break;
|
||||
case 56:
|
||||
{ write_exp_elt_opcode (OP_REGISTER);
|
||||
write_exp_elt_longcst (yypvt[-0].lval);
|
||||
write_exp_elt_opcode (OP_REGISTER); } break;
|
||||
case 55:
|
||||
# line 397 "expread.y"
|
||||
{ write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_int);
|
||||
write_exp_elt ((long) TYPE_LENGTH (yypvt[-1].tval));
|
||||
write_exp_elt (OP_LONG); } break;
|
||||
{ write_exp_elt_opcode (OP_INTERNALVAR);
|
||||
write_exp_elt_intern (yypvt[-0].ivar);
|
||||
write_exp_elt_opcode (OP_INTERNALVAR); } break;
|
||||
case 56:
|
||||
# line 403 "expread.y"
|
||||
{ write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_int);
|
||||
write_exp_elt_longcst ((long) TYPE_LENGTH (yypvt[-1].tval));
|
||||
write_exp_elt_opcode (OP_LONG); } break;
|
||||
case 57:
|
||||
# line 404 "expread.y"
|
||||
{ write_exp_elt (OP_STRING);
|
||||
# line 410 "expread.y"
|
||||
{ write_exp_elt_opcode (OP_STRING);
|
||||
write_exp_string (yypvt[-0].sval);
|
||||
write_exp_elt (OP_STRING); } break;
|
||||
write_exp_elt_opcode (OP_STRING); } break;
|
||||
case 58:
|
||||
# line 411 "expread.y"
|
||||
{ write_exp_elt (OP_THIS);
|
||||
write_exp_elt (OP_THIS); } break;
|
||||
# line 417 "expread.y"
|
||||
{ write_exp_elt_opcode (OP_THIS);
|
||||
write_exp_elt_opcode (OP_THIS); } break;
|
||||
case 59:
|
||||
# line 418 "expread.y"
|
||||
# line 424 "expread.y"
|
||||
{
|
||||
struct symtab *tem = lookup_symtab (copy_name (yypvt[-0].sval));
|
||||
struct symbol *sym;
|
||||
@ -1409,7 +1494,7 @@ case 59:
|
||||
{
|
||||
sym = lookup_symbol (copy_name (yypvt[-0].sval),
|
||||
expression_context_block,
|
||||
VAR_NAMESPACE);
|
||||
VAR_NAMESPACE, 0);
|
||||
if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
|
||||
yyval.bval = SYMBOL_BLOCK_VALUE (sym);
|
||||
else
|
||||
@ -1418,29 +1503,25 @@ case 59:
|
||||
}
|
||||
} break;
|
||||
case 60:
|
||||
# line 439 "expread.y"
|
||||
{
|
||||
struct symbol *tem
|
||||
= lookup_symbol (copy_name (yypvt[-0].sval), yypvt[-2].bval, VAR_NAMESPACE);
|
||||
# line 445 "expread.y"
|
||||
{ struct symbol *tem
|
||||
= lookup_symbol (copy_name (yypvt[-0].sval), yypvt[-2].bval, VAR_NAMESPACE, 0);
|
||||
if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
|
||||
error ("No function \"%s\" in specified context.",
|
||||
copy_name (yypvt[-0].sval));
|
||||
yyval.bval = SYMBOL_BLOCK_VALUE (tem);
|
||||
} break;
|
||||
yyval.bval = SYMBOL_BLOCK_VALUE (tem); } break;
|
||||
case 61:
|
||||
# line 450 "expread.y"
|
||||
{
|
||||
struct symbol *sym;
|
||||
sym = lookup_symbol (copy_name (yypvt[-0].sval), yypvt[-2].bval, VAR_NAMESPACE);
|
||||
# line 454 "expread.y"
|
||||
{ struct symbol *sym;
|
||||
sym = lookup_symbol (copy_name (yypvt[-0].sval), yypvt[-2].bval, VAR_NAMESPACE, 0);
|
||||
if (sym == 0)
|
||||
error ("No symbol \"%s\" in specified context.",
|
||||
copy_name (yypvt[-0].sval));
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt (sym);
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
} break;
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
write_exp_elt_sym (sym);
|
||||
write_exp_elt_opcode (OP_VAR_VALUE); } break;
|
||||
case 62:
|
||||
# line 463 "expread.y"
|
||||
# line 465 "expread.y"
|
||||
{
|
||||
struct type *type = yypvt[-2].tval;
|
||||
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
|
||||
@ -1448,24 +1529,24 @@ case 62:
|
||||
error ("`%s' is not defined as an aggregate type.",
|
||||
TYPE_NAME (type));
|
||||
|
||||
write_exp_elt (OP_SCOPE);
|
||||
write_exp_elt (type);
|
||||
write_exp_elt_opcode (OP_SCOPE);
|
||||
write_exp_elt_type (type);
|
||||
write_exp_string (yypvt[-0].sval);
|
||||
write_exp_elt (OP_SCOPE);
|
||||
write_exp_elt_opcode (OP_SCOPE);
|
||||
} break;
|
||||
case 63:
|
||||
# line 476 "expread.y"
|
||||
# line 478 "expread.y"
|
||||
{
|
||||
char *name = copy_name (yypvt[-0].sval);
|
||||
struct symbol *sym;
|
||||
int i;
|
||||
|
||||
sym = lookup_symbol_2 (name, 0, VAR_NAMESPACE);
|
||||
sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0);
|
||||
if (sym)
|
||||
{
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt (sym);
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
write_exp_elt_sym (sym);
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < misc_function_count; i++)
|
||||
@ -1474,130 +1555,133 @@ case 63:
|
||||
|
||||
if (i < misc_function_count)
|
||||
{
|
||||
write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_int);
|
||||
write_exp_elt (misc_function_vector[i].address);
|
||||
write_exp_elt (OP_LONG);
|
||||
write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt (builtin_type_char);
|
||||
write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_int);
|
||||
write_exp_elt_longcst (misc_function_vector[i].address);
|
||||
write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
write_exp_elt_type (builtin_type_char);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
}
|
||||
else
|
||||
if (symtab_list == 0)
|
||||
if (symtab_list == 0
|
||||
&& partial_symtab_list == 0)
|
||||
error ("No symbol table is loaded. Use the \"symbol-file\" command.");
|
||||
else
|
||||
error ("No symbol \"%s\" in current context.", name);
|
||||
} break;
|
||||
case 64:
|
||||
# line 512 "expread.y"
|
||||
# line 515 "expread.y"
|
||||
{ struct symbol *sym;
|
||||
sym = lookup_symbol_1 (copy_name (yypvt[-0].sval),
|
||||
expression_context_block,
|
||||
VAR_NAMESPACE);
|
||||
int is_a_field_of_this;
|
||||
|
||||
sym = lookup_symbol (copy_name (yypvt[-0].sval),
|
||||
expression_context_block,
|
||||
VAR_NAMESPACE,
|
||||
&is_a_field_of_this);
|
||||
if (sym)
|
||||
{
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt (sym);
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
switch (sym->class)
|
||||
{
|
||||
case LOC_REGISTER:
|
||||
case LOC_ARG:
|
||||
case LOC_LOCAL:
|
||||
if (innermost_block == 0 ||
|
||||
contained_in (block_found,
|
||||
innermost_block))
|
||||
innermost_block = block_found;
|
||||
}
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
write_exp_elt_sym (sym);
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
}
|
||||
else if (is_a_field_of_this)
|
||||
{
|
||||
/* C++: it hangs off of `this'. Must
|
||||
not inadvertently convert from a method call
|
||||
to data ref. */
|
||||
if (innermost_block == 0 ||
|
||||
contained_in (block_found, innermost_block))
|
||||
innermost_block = block_found;
|
||||
write_exp_elt_opcode (OP_THIS);
|
||||
write_exp_elt_opcode (OP_THIS);
|
||||
write_exp_elt_opcode (STRUCTOP_PTR);
|
||||
write_exp_string (yypvt[-0].sval);
|
||||
write_exp_elt_opcode (STRUCTOP_PTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
register char *arg = copy_name (yypvt[-0].sval);
|
||||
register int i;
|
||||
int v, val;
|
||||
/* C++: see if it hangs off of `this'. Must
|
||||
not inadvertently convert from a method call
|
||||
to data ref. */
|
||||
v = (int)value_of_this (0);
|
||||
if (v)
|
||||
{
|
||||
val = check_field (v, arg);
|
||||
if (val)
|
||||
{
|
||||
write_exp_elt (OP_THIS);
|
||||
write_exp_elt (OP_THIS);
|
||||
write_exp_elt (STRUCTOP_PTR);
|
||||
write_exp_string (yypvt[-0].sval);
|
||||
write_exp_elt (STRUCTOP_PTR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
sym = lookup_symbol_2 (arg, 0, VAR_NAMESPACE);
|
||||
if (sym)
|
||||
{
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt (sym);
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
break; /* YACC-dependent */
|
||||
}
|
||||
register char *arg = copy_name (yypvt[-0].sval);
|
||||
|
||||
for (i = 0; i < misc_function_count; i++)
|
||||
if (!strcmp (misc_function_vector[i].name, arg))
|
||||
break;
|
||||
|
||||
if (i < misc_function_count)
|
||||
{
|
||||
write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_int);
|
||||
write_exp_elt (misc_function_vector[i].address);
|
||||
write_exp_elt (OP_LONG);
|
||||
write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt (builtin_type_char);
|
||||
write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_int);
|
||||
write_exp_elt_longcst (misc_function_vector[i].address);
|
||||
write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
write_exp_elt_type (builtin_type_char);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
}
|
||||
else if (symtab_list == 0
|
||||
&& partial_symtab_list == 0)
|
||||
error ("No symbol table is loaded. Use the \"symbol-file\" command.");
|
||||
else
|
||||
if (symtab_list == 0)
|
||||
error ("No symbol table is loaded. Use the \"symbol-file\" command.");
|
||||
else
|
||||
error ("No symbol \"%s\" in current context.",
|
||||
copy_name (yypvt[-0].sval));
|
||||
error ("No symbol \"%s\" in current context.",
|
||||
copy_name (yypvt[-0].sval));
|
||||
}
|
||||
} break;
|
||||
case 66:
|
||||
# line 578 "expread.y"
|
||||
# line 583 "expread.y"
|
||||
{ yyval.tval = lookup_pointer_type (yypvt[-1].tval); } break;
|
||||
case 67:
|
||||
# line 580 "expread.y"
|
||||
# line 585 "expread.y"
|
||||
{ yyval.tval = lookup_reference_type (yypvt[-1].tval); } break;
|
||||
case 68:
|
||||
# line 582 "expread.y"
|
||||
# line 587 "expread.y"
|
||||
{ yyval.tval = lookup_member_type (builtin_type_int, yypvt[-2].tval); } break;
|
||||
case 69:
|
||||
# line 584 "expread.y"
|
||||
# line 589 "expread.y"
|
||||
{ yyval.tval = lookup_member_type (yypvt[-5].tval, yypvt[-3].tval); } break;
|
||||
case 70:
|
||||
# line 586 "expread.y"
|
||||
{ yyval.tval = lookup_member_type (lookup_function_type (yypvt[-7].tval, 0), yypvt[-5].tval); } break;
|
||||
# line 591 "expread.y"
|
||||
{ yyval.tval = lookup_member_type (lookup_function_type (yypvt[-7].tval)); } break;
|
||||
case 71:
|
||||
# line 588 "expread.y"
|
||||
{ yyval.tval = lookup_member_type (lookup_function_type (yypvt[-8].tval, yypvt[-1].tvec), yypvt[-6].tval);
|
||||
# line 593 "expread.y"
|
||||
{ yyval.tval = lookup_member_type (lookup_function_type (yypvt[-8].tval));
|
||||
free (yypvt[-1].tvec); } break;
|
||||
case 72:
|
||||
# line 594 "expread.y"
|
||||
# line 599 "expread.y"
|
||||
{ yyval.tval = lookup_typename (copy_name (yypvt[-0].sval),
|
||||
expression_context_block, 0); } break;
|
||||
case 73:
|
||||
# line 597 "expread.y"
|
||||
# line 602 "expread.y"
|
||||
{ yyval.tval = lookup_struct (copy_name (yypvt[-0].sval),
|
||||
expression_context_block); } break;
|
||||
case 74:
|
||||
# line 600 "expread.y"
|
||||
# line 605 "expread.y"
|
||||
{ yyval.tval = lookup_union (copy_name (yypvt[-0].sval),
|
||||
expression_context_block); } break;
|
||||
case 75:
|
||||
# line 603 "expread.y"
|
||||
# line 608 "expread.y"
|
||||
{ yyval.tval = lookup_enum (copy_name (yypvt[-0].sval),
|
||||
expression_context_block); } break;
|
||||
case 76:
|
||||
# line 606 "expread.y"
|
||||
# line 611 "expread.y"
|
||||
{ yyval.tval = lookup_unsigned_typename (copy_name (yypvt[-0].sval)); } break;
|
||||
case 77:
|
||||
# line 611 "expread.y"
|
||||
# line 616 "expread.y"
|
||||
{ yyval.tvec = (struct type **)xmalloc (sizeof (struct type *) * 2);
|
||||
yyval.tvec[0] = (struct type *)0;
|
||||
yyval.tvec[1] = yypvt[-0].tval;
|
||||
} break;
|
||||
case 78:
|
||||
# line 616 "expread.y"
|
||||
# line 621 "expread.y"
|
||||
{ int len = sizeof (struct type *) * ++(yypvt[-2].ivec[0]);
|
||||
yyval.tvec = (struct type **)xrealloc (yypvt[-2].tvec, len);
|
||||
yyval.tvec[yyval.ivec[0]] = yypvt[-0].tval;
|
||||
|
468
gdb/expread.y
468
gdb/expread.y
@ -41,9 +41,8 @@ static int expout_size;
|
||||
static int expout_ptr;
|
||||
|
||||
static int yylex ();
|
||||
static yyerror ();
|
||||
static void yyerror ();
|
||||
static void write_exp_elt ();
|
||||
static void write_exp_elt2 ();
|
||||
static void write_exp_string ();
|
||||
static void start_arglist ();
|
||||
static int end_arglist ();
|
||||
@ -55,6 +54,13 @@ static char *copy_name ();
|
||||
|
||||
static struct block *expression_context_block;
|
||||
|
||||
/* The innermost context required by the stack and register variables
|
||||
we've encountered so far. */
|
||||
struct block *innermost_block;
|
||||
|
||||
/* The block in which the most recently discovered symbol was found. */
|
||||
struct block *block_found;
|
||||
|
||||
/* Number of arguments seen so far in innermost function call. */
|
||||
static int arglist_len;
|
||||
|
||||
@ -156,70 +162,70 @@ start : exp1
|
||||
/* Expressions, including the comma operator. */
|
||||
exp1 : exp
|
||||
| exp1 ',' exp
|
||||
{ write_exp_elt (BINOP_COMMA); }
|
||||
{ write_exp_elt_opcode (BINOP_COMMA); }
|
||||
;
|
||||
|
||||
/* Expressions, not including the comma operator. */
|
||||
exp : '*' exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_IND); }
|
||||
{ write_exp_elt_opcode (UNOP_IND); }
|
||||
|
||||
exp : '&' exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_ADDR); }
|
||||
{ write_exp_elt_opcode (UNOP_ADDR); }
|
||||
|
||||
exp : '-' exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_NEG); }
|
||||
{ write_exp_elt_opcode (UNOP_NEG); }
|
||||
;
|
||||
|
||||
exp : '!' exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_ZEROP); }
|
||||
{ write_exp_elt_opcode (UNOP_ZEROP); }
|
||||
;
|
||||
|
||||
exp : '~' exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_LOGNOT); }
|
||||
{ write_exp_elt_opcode (UNOP_LOGNOT); }
|
||||
;
|
||||
|
||||
exp : INCREMENT exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_PREINCREMENT); }
|
||||
{ write_exp_elt_opcode (UNOP_PREINCREMENT); }
|
||||
;
|
||||
|
||||
exp : DECREMENT exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_PREDECREMENT); }
|
||||
{ write_exp_elt_opcode (UNOP_PREDECREMENT); }
|
||||
;
|
||||
|
||||
exp : exp INCREMENT %prec UNARY
|
||||
{ write_exp_elt (UNOP_POSTINCREMENT); }
|
||||
{ write_exp_elt_opcode (UNOP_POSTINCREMENT); }
|
||||
;
|
||||
|
||||
exp : exp DECREMENT %prec UNARY
|
||||
{ write_exp_elt (UNOP_POSTDECREMENT); }
|
||||
{ write_exp_elt_opcode (UNOP_POSTDECREMENT); }
|
||||
;
|
||||
|
||||
exp : SIZEOF exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_SIZEOF); }
|
||||
{ write_exp_elt_opcode (UNOP_SIZEOF); }
|
||||
;
|
||||
|
||||
exp : exp ARROW name
|
||||
{ write_exp_elt (STRUCTOP_PTR);
|
||||
{ write_exp_elt_opcode (STRUCTOP_PTR);
|
||||
write_exp_string ($3);
|
||||
write_exp_elt (STRUCTOP_PTR); }
|
||||
write_exp_elt_opcode (STRUCTOP_PTR); }
|
||||
;
|
||||
|
||||
exp : exp ARROW '*' exp
|
||||
{ write_exp_elt (STRUCTOP_MPTR); }
|
||||
{ write_exp_elt_opcode (STRUCTOP_MPTR); }
|
||||
;
|
||||
|
||||
exp : exp '.' name
|
||||
{ write_exp_elt (STRUCTOP_STRUCT);
|
||||
{ write_exp_elt_opcode (STRUCTOP_STRUCT);
|
||||
write_exp_string ($3);
|
||||
write_exp_elt (STRUCTOP_STRUCT); }
|
||||
write_exp_elt_opcode (STRUCTOP_STRUCT); }
|
||||
;
|
||||
|
||||
exp : exp '.' '*' exp
|
||||
{ write_exp_elt (STRUCTOP_MEMBER); }
|
||||
{ write_exp_elt_opcode (STRUCTOP_MEMBER); }
|
||||
;
|
||||
|
||||
exp : exp '[' exp1 ']'
|
||||
{ write_exp_elt (BINOP_SUBSCRIPT); }
|
||||
{ write_exp_elt_opcode (BINOP_SUBSCRIPT); }
|
||||
;
|
||||
|
||||
exp : exp '('
|
||||
@ -227,9 +233,9 @@ exp : exp '('
|
||||
being accumulated by an outer function call. */
|
||||
{ start_arglist (); }
|
||||
arglist ')'
|
||||
{ write_exp_elt (OP_FUNCALL);
|
||||
write_exp_elt (end_arglist ());
|
||||
write_exp_elt (OP_FUNCALL); }
|
||||
{ write_exp_elt_opcode (OP_FUNCALL);
|
||||
write_exp_elt_longcst (end_arglist ());
|
||||
write_exp_elt_opcode (OP_FUNCALL); }
|
||||
;
|
||||
|
||||
arglist :
|
||||
@ -244,15 +250,15 @@ arglist : arglist ',' exp %prec ABOVE_COMMA
|
||||
;
|
||||
|
||||
exp : '{' type '}' exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt ($2);
|
||||
write_exp_elt (UNOP_MEMVAL); }
|
||||
{ write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
write_exp_elt_type ($2);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL); }
|
||||
;
|
||||
|
||||
exp : '(' type ')' exp %prec UNARY
|
||||
{ write_exp_elt (UNOP_CAST);
|
||||
write_exp_elt ($2);
|
||||
write_exp_elt (UNOP_CAST); }
|
||||
{ write_exp_elt_opcode (UNOP_CAST);
|
||||
write_exp_elt_type ($2);
|
||||
write_exp_elt_opcode (UNOP_CAST); }
|
||||
;
|
||||
|
||||
exp : '(' exp1 ')'
|
||||
@ -262,154 +268,154 @@ exp : '(' exp1 ')'
|
||||
/* Binary operators in order of decreasing precedence. */
|
||||
|
||||
exp : exp '@' exp
|
||||
{ write_exp_elt (BINOP_REPEAT); }
|
||||
{ write_exp_elt_opcode (BINOP_REPEAT); }
|
||||
;
|
||||
|
||||
exp : exp '*' exp
|
||||
{ write_exp_elt (BINOP_MUL); }
|
||||
{ write_exp_elt_opcode (BINOP_MUL); }
|
||||
;
|
||||
|
||||
exp : exp '/' exp
|
||||
{ write_exp_elt (BINOP_DIV); }
|
||||
{ write_exp_elt_opcode (BINOP_DIV); }
|
||||
;
|
||||
|
||||
exp : exp '%' exp
|
||||
{ write_exp_elt (BINOP_REM); }
|
||||
{ write_exp_elt_opcode (BINOP_REM); }
|
||||
;
|
||||
|
||||
exp : exp '+' exp
|
||||
{ write_exp_elt (BINOP_ADD); }
|
||||
{ write_exp_elt_opcode (BINOP_ADD); }
|
||||
;
|
||||
|
||||
exp : exp '-' exp
|
||||
{ write_exp_elt (BINOP_SUB); }
|
||||
{ write_exp_elt_opcode (BINOP_SUB); }
|
||||
;
|
||||
|
||||
exp : exp LSH exp
|
||||
{ write_exp_elt (BINOP_LSH); }
|
||||
{ write_exp_elt_opcode (BINOP_LSH); }
|
||||
;
|
||||
|
||||
exp : exp RSH exp
|
||||
{ write_exp_elt (BINOP_RSH); }
|
||||
{ write_exp_elt_opcode (BINOP_RSH); }
|
||||
;
|
||||
|
||||
exp : exp EQUAL exp
|
||||
{ write_exp_elt (BINOP_EQUAL); }
|
||||
{ write_exp_elt_opcode (BINOP_EQUAL); }
|
||||
;
|
||||
|
||||
exp : exp NOTEQUAL exp
|
||||
{ write_exp_elt (BINOP_NOTEQUAL); }
|
||||
{ write_exp_elt_opcode (BINOP_NOTEQUAL); }
|
||||
;
|
||||
|
||||
exp : exp LEQ exp
|
||||
{ write_exp_elt (BINOP_LEQ); }
|
||||
{ write_exp_elt_opcode (BINOP_LEQ); }
|
||||
;
|
||||
|
||||
exp : exp GEQ exp
|
||||
{ write_exp_elt (BINOP_GEQ); }
|
||||
{ write_exp_elt_opcode (BINOP_GEQ); }
|
||||
;
|
||||
|
||||
exp : exp '<' exp
|
||||
{ write_exp_elt (BINOP_LESS); }
|
||||
{ write_exp_elt_opcode (BINOP_LESS); }
|
||||
;
|
||||
|
||||
exp : exp '>' exp
|
||||
{ write_exp_elt (BINOP_GTR); }
|
||||
{ write_exp_elt_opcode (BINOP_GTR); }
|
||||
;
|
||||
|
||||
exp : exp '&' exp
|
||||
{ write_exp_elt (BINOP_LOGAND); }
|
||||
{ write_exp_elt_opcode (BINOP_LOGAND); }
|
||||
;
|
||||
|
||||
exp : exp '^' exp
|
||||
{ write_exp_elt (BINOP_LOGXOR); }
|
||||
{ write_exp_elt_opcode (BINOP_LOGXOR); }
|
||||
;
|
||||
|
||||
exp : exp '|' exp
|
||||
{ write_exp_elt (BINOP_LOGIOR); }
|
||||
{ write_exp_elt_opcode (BINOP_LOGIOR); }
|
||||
;
|
||||
|
||||
exp : exp AND exp
|
||||
{ write_exp_elt (BINOP_AND); }
|
||||
{ write_exp_elt_opcode (BINOP_AND); }
|
||||
;
|
||||
|
||||
exp : exp OR exp
|
||||
{ write_exp_elt (BINOP_OR); }
|
||||
{ write_exp_elt_opcode (BINOP_OR); }
|
||||
;
|
||||
|
||||
exp : exp '?' exp ':' exp
|
||||
{ write_exp_elt (TERNOP_COND); }
|
||||
{ write_exp_elt_opcode (TERNOP_COND); }
|
||||
;
|
||||
|
||||
exp : exp '=' exp
|
||||
{ write_exp_elt (BINOP_ASSIGN); }
|
||||
{ write_exp_elt_opcode (BINOP_ASSIGN); }
|
||||
;
|
||||
|
||||
exp : exp ASSIGN_MODIFY exp
|
||||
{ write_exp_elt (BINOP_ASSIGN_MODIFY);
|
||||
write_exp_elt ($2);
|
||||
write_exp_elt (BINOP_ASSIGN_MODIFY); }
|
||||
{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
|
||||
write_exp_elt_opcode ($2);
|
||||
write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
|
||||
;
|
||||
|
||||
exp : INT
|
||||
{ write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_long);
|
||||
write_exp_elt ($1);
|
||||
write_exp_elt (OP_LONG); }
|
||||
{ write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_long);
|
||||
write_exp_elt_longcst ($1);
|
||||
write_exp_elt_opcode (OP_LONG); }
|
||||
;
|
||||
|
||||
exp : CHAR
|
||||
{ write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_char);
|
||||
write_exp_elt ($1);
|
||||
write_exp_elt (OP_LONG); }
|
||||
{ write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_char);
|
||||
write_exp_elt_longcst ($1);
|
||||
write_exp_elt_opcode (OP_LONG); }
|
||||
;
|
||||
|
||||
exp : FLOAT
|
||||
{ write_exp_elt (OP_DOUBLE);
|
||||
write_exp_elt (builtin_type_double);
|
||||
write_exp_elt2 ($1);
|
||||
write_exp_elt (OP_DOUBLE); }
|
||||
{ write_exp_elt_opcode (OP_DOUBLE);
|
||||
write_exp_elt_type (builtin_type_double);
|
||||
write_exp_elt_dblcst ($1);
|
||||
write_exp_elt_opcode (OP_DOUBLE); }
|
||||
;
|
||||
|
||||
exp : variable
|
||||
;
|
||||
|
||||
exp : LAST
|
||||
{ write_exp_elt (OP_LAST);
|
||||
write_exp_elt ($1);
|
||||
write_exp_elt (OP_LAST); }
|
||||
{ write_exp_elt_opcode (OP_LAST);
|
||||
write_exp_elt_longcst ($1);
|
||||
write_exp_elt_opcode (OP_LAST); }
|
||||
;
|
||||
|
||||
exp : REGNAME
|
||||
{ write_exp_elt (OP_REGISTER);
|
||||
write_exp_elt ($1);
|
||||
write_exp_elt (OP_REGISTER); }
|
||||
{ write_exp_elt_opcode (OP_REGISTER);
|
||||
write_exp_elt_longcst ($1);
|
||||
write_exp_elt_opcode (OP_REGISTER); }
|
||||
;
|
||||
|
||||
exp : VARIABLE
|
||||
{ write_exp_elt (OP_INTERNALVAR);
|
||||
write_exp_elt ($1);
|
||||
write_exp_elt (OP_INTERNALVAR); }
|
||||
{ write_exp_elt_opcode (OP_INTERNALVAR);
|
||||
write_exp_elt_intern ($1);
|
||||
write_exp_elt_opcode (OP_INTERNALVAR); }
|
||||
;
|
||||
|
||||
exp : SIZEOF '(' type ')'
|
||||
{ write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_int);
|
||||
write_exp_elt ((long) TYPE_LENGTH ($3));
|
||||
write_exp_elt (OP_LONG); }
|
||||
{ write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_int);
|
||||
write_exp_elt_longcst ((long) TYPE_LENGTH ($3));
|
||||
write_exp_elt_opcode (OP_LONG); }
|
||||
;
|
||||
|
||||
exp : STRING
|
||||
{ write_exp_elt (OP_STRING);
|
||||
{ write_exp_elt_opcode (OP_STRING);
|
||||
write_exp_string ($1);
|
||||
write_exp_elt (OP_STRING); }
|
||||
write_exp_elt_opcode (OP_STRING); }
|
||||
;
|
||||
|
||||
/* C++. */
|
||||
exp : THIS
|
||||
{ write_exp_elt (OP_THIS);
|
||||
write_exp_elt (OP_THIS); }
|
||||
{ write_exp_elt_opcode (OP_THIS);
|
||||
write_exp_elt_opcode (OP_THIS); }
|
||||
;
|
||||
|
||||
/* end of C++. */
|
||||
@ -425,7 +431,7 @@ block : name
|
||||
{
|
||||
sym = lookup_symbol (copy_name ($1),
|
||||
expression_context_block,
|
||||
VAR_NAMESPACE);
|
||||
VAR_NAMESPACE, 0);
|
||||
if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
|
||||
$$ = SYMBOL_BLOCK_VALUE (sym);
|
||||
else
|
||||
@ -436,27 +442,23 @@ block : name
|
||||
;
|
||||
|
||||
block : block COLONCOLON name
|
||||
{
|
||||
struct symbol *tem
|
||||
= lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE);
|
||||
{ struct symbol *tem
|
||||
= lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE, 0);
|
||||
if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
|
||||
error ("No function \"%s\" in specified context.",
|
||||
copy_name ($3));
|
||||
$$ = SYMBOL_BLOCK_VALUE (tem);
|
||||
}
|
||||
$$ = SYMBOL_BLOCK_VALUE (tem); }
|
||||
;
|
||||
|
||||
variable: block COLONCOLON name
|
||||
{
|
||||
struct symbol *sym;
|
||||
sym = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE);
|
||||
{ struct symbol *sym;
|
||||
sym = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE, 0);
|
||||
if (sym == 0)
|
||||
error ("No symbol \"%s\" in specified context.",
|
||||
copy_name ($3));
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt (sym);
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
}
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
write_exp_elt_sym (sym);
|
||||
write_exp_elt_opcode (OP_VAR_VALUE); }
|
||||
;
|
||||
|
||||
variable: typebase COLONCOLON name
|
||||
@ -467,10 +469,10 @@ variable: typebase COLONCOLON name
|
||||
error ("`%s' is not defined as an aggregate type.",
|
||||
TYPE_NAME (type));
|
||||
|
||||
write_exp_elt (OP_SCOPE);
|
||||
write_exp_elt (type);
|
||||
write_exp_elt_opcode (OP_SCOPE);
|
||||
write_exp_elt_type (type);
|
||||
write_exp_string ($3);
|
||||
write_exp_elt (OP_SCOPE);
|
||||
write_exp_elt_opcode (OP_SCOPE);
|
||||
}
|
||||
| COLONCOLON name
|
||||
{
|
||||
@ -478,12 +480,12 @@ variable: typebase COLONCOLON name
|
||||
struct symbol *sym;
|
||||
int i;
|
||||
|
||||
sym = lookup_symbol_2 (name, 0, VAR_NAMESPACE);
|
||||
sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0);
|
||||
if (sym)
|
||||
{
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt (sym);
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
write_exp_elt_sym (sym);
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < misc_function_count; i++)
|
||||
@ -492,16 +494,17 @@ variable: typebase COLONCOLON name
|
||||
|
||||
if (i < misc_function_count)
|
||||
{
|
||||
write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_int);
|
||||
write_exp_elt (misc_function_vector[i].address);
|
||||
write_exp_elt (OP_LONG);
|
||||
write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt (builtin_type_char);
|
||||
write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_int);
|
||||
write_exp_elt_longcst (misc_function_vector[i].address);
|
||||
write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
write_exp_elt_type (builtin_type_char);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
}
|
||||
else
|
||||
if (symtab_list == 0)
|
||||
if (symtab_list == 0
|
||||
&& partial_symtab_list == 0)
|
||||
error ("No symbol table is loaded. Use the \"symbol-file\" command.");
|
||||
else
|
||||
error ("No symbol \"%s\" in current context.", name);
|
||||
@ -510,65 +513,67 @@ variable: typebase COLONCOLON name
|
||||
|
||||
variable: NAME
|
||||
{ struct symbol *sym;
|
||||
sym = lookup_symbol_1 (copy_name ($1),
|
||||
expression_context_block,
|
||||
VAR_NAMESPACE);
|
||||
int is_a_field_of_this;
|
||||
|
||||
sym = lookup_symbol (copy_name ($1),
|
||||
expression_context_block,
|
||||
VAR_NAMESPACE,
|
||||
&is_a_field_of_this);
|
||||
if (sym)
|
||||
{
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt (sym);
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
switch (sym->class)
|
||||
{
|
||||
case LOC_REGISTER:
|
||||
case LOC_ARG:
|
||||
case LOC_LOCAL:
|
||||
if (innermost_block == 0 ||
|
||||
contained_in (block_found,
|
||||
innermost_block))
|
||||
innermost_block = block_found;
|
||||
}
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
write_exp_elt_sym (sym);
|
||||
write_exp_elt_opcode (OP_VAR_VALUE);
|
||||
}
|
||||
else if (is_a_field_of_this)
|
||||
{
|
||||
/* C++: it hangs off of `this'. Must
|
||||
not inadvertently convert from a method call
|
||||
to data ref. */
|
||||
if (innermost_block == 0 ||
|
||||
contained_in (block_found, innermost_block))
|
||||
innermost_block = block_found;
|
||||
write_exp_elt_opcode (OP_THIS);
|
||||
write_exp_elt_opcode (OP_THIS);
|
||||
write_exp_elt_opcode (STRUCTOP_PTR);
|
||||
write_exp_string ($1);
|
||||
write_exp_elt_opcode (STRUCTOP_PTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
register char *arg = copy_name ($1);
|
||||
register int i;
|
||||
int v, val;
|
||||
/* C++: see if it hangs off of `this'. Must
|
||||
not inadvertently convert from a method call
|
||||
to data ref. */
|
||||
v = (int)value_of_this (0);
|
||||
if (v)
|
||||
{
|
||||
val = check_field (v, arg);
|
||||
if (val)
|
||||
{
|
||||
write_exp_elt (OP_THIS);
|
||||
write_exp_elt (OP_THIS);
|
||||
write_exp_elt (STRUCTOP_PTR);
|
||||
write_exp_string ($1);
|
||||
write_exp_elt (STRUCTOP_PTR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
sym = lookup_symbol_2 (arg, 0, VAR_NAMESPACE);
|
||||
if (sym)
|
||||
{
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
write_exp_elt (sym);
|
||||
write_exp_elt (OP_VAR_VALUE);
|
||||
break; /* YACC-dependent */
|
||||
}
|
||||
register char *arg = copy_name ($1);
|
||||
|
||||
for (i = 0; i < misc_function_count; i++)
|
||||
if (!strcmp (misc_function_vector[i].name, arg))
|
||||
break;
|
||||
|
||||
if (i < misc_function_count)
|
||||
{
|
||||
write_exp_elt (OP_LONG);
|
||||
write_exp_elt (builtin_type_int);
|
||||
write_exp_elt (misc_function_vector[i].address);
|
||||
write_exp_elt (OP_LONG);
|
||||
write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt (builtin_type_char);
|
||||
write_exp_elt (UNOP_MEMVAL);
|
||||
write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_type (builtin_type_int);
|
||||
write_exp_elt_longcst (misc_function_vector[i].address);
|
||||
write_exp_elt_opcode (OP_LONG);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
write_exp_elt_type (builtin_type_char);
|
||||
write_exp_elt_opcode (UNOP_MEMVAL);
|
||||
}
|
||||
else if (symtab_list == 0
|
||||
&& partial_symtab_list == 0)
|
||||
error ("No symbol table is loaded. Use the \"symbol-file\" command.");
|
||||
else
|
||||
if (symtab_list == 0)
|
||||
error ("No symbol table is loaded. Use the \"symbol-file\" command.");
|
||||
else
|
||||
error ("No symbol \"%s\" in current context.",
|
||||
copy_name ($1));
|
||||
error ("No symbol \"%s\" in current context.",
|
||||
copy_name ($1));
|
||||
}
|
||||
}
|
||||
;
|
||||
@ -583,9 +588,9 @@ type : typebase
|
||||
| type '(' typebase COLONCOLON '*' ')'
|
||||
{ $$ = lookup_member_type ($1, $3); }
|
||||
| type '(' typebase COLONCOLON '*' ')' '(' ')'
|
||||
{ $$ = lookup_member_type (lookup_function_type ($1, 0), $3); }
|
||||
{ $$ = lookup_member_type (lookup_function_type ($1)); }
|
||||
| type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'
|
||||
{ $$ = lookup_member_type (lookup_function_type ($1, $8), $3);
|
||||
{ $$ = lookup_member_type (lookup_function_type ($1));
|
||||
free ($8); }
|
||||
;
|
||||
|
||||
@ -672,16 +677,13 @@ free_funcalls ()
|
||||
|
||||
/* Add one element to the end of the expression. */
|
||||
|
||||
/* To avoid a bug in the Sun 4 compiler, we pass only things that
|
||||
can fit into a single register through here. */
|
||||
/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into
|
||||
a register through here */
|
||||
|
||||
static void
|
||||
write_exp_elt (expelt)
|
||||
/* union exp_element expelt; */
|
||||
long expelt;
|
||||
union exp_element expelt;
|
||||
{
|
||||
union exp_element temp;
|
||||
temp.longconst = expelt;
|
||||
|
||||
if (expout_ptr >= expout_size)
|
||||
{
|
||||
expout_size *= 2;
|
||||
@ -689,25 +691,73 @@ write_exp_elt (expelt)
|
||||
sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
}
|
||||
expout->elts[expout_ptr++] = /* expelt */ temp;
|
||||
expout->elts[expout_ptr++] = expelt;
|
||||
}
|
||||
|
||||
/* Things that take more space must come through here. */
|
||||
static void
|
||||
write_exp_elt2 (expelt)
|
||||
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 temp;
|
||||
temp.doubleconst = expelt;
|
||||
union exp_element tmp;
|
||||
|
||||
if (expout_ptr >= expout_size)
|
||||
{
|
||||
expout_size *= 2;
|
||||
expout = (struct expression *) xrealloc (expout,
|
||||
sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
}
|
||||
expout->elts[expout_ptr++] = temp;
|
||||
tmp.doubleconst = expelt;
|
||||
|
||||
write_exp_elt (tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
write_exp_elt_type (expelt)
|
||||
struct type *expelt;
|
||||
{
|
||||
union exp_element tmp;
|
||||
|
||||
tmp.type = expelt;
|
||||
|
||||
write_exp_elt (tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
write_exp_elt_intern (expelt)
|
||||
struct internalvar *expelt;
|
||||
{
|
||||
union exp_element tmp;
|
||||
|
||||
tmp.internalvar = expelt;
|
||||
|
||||
write_exp_elt (tmp);
|
||||
}
|
||||
|
||||
/* Add a string constant to the end of the expression.
|
||||
@ -726,13 +776,13 @@ write_exp_string (str)
|
||||
if (expout_ptr >= expout_size)
|
||||
{
|
||||
expout_size = max (expout_size * 2, expout_ptr + 10);
|
||||
expout = (struct expression *) xrealloc (expout,
|
||||
sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
expout = (struct expression *)
|
||||
xrealloc (expout, (sizeof (struct expression)
|
||||
+ (expout_size * sizeof (union exp_element))));
|
||||
}
|
||||
bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len);
|
||||
((char *) &expout->elts[expout_ptr - lenelt])[len] = 0;
|
||||
write_exp_elt (len);
|
||||
write_exp_elt_longcst (len);
|
||||
}
|
||||
|
||||
/* During parsing of a C expression, the pointer to the next character
|
||||
@ -799,12 +849,13 @@ parse_number (olen)
|
||||
while (len-- > 0)
|
||||
{
|
||||
c = *p++;
|
||||
n *= base;
|
||||
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
|
||||
if (c != 'l')
|
||||
n *= base;
|
||||
if (c >= '0' && c <= '9')
|
||||
n += c - '0';
|
||||
else
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
|
||||
if (base == 16 && c >= 'a' && c <= 'f')
|
||||
n += c - 'a' + 10;
|
||||
else if (len == 0 && c == 'l')
|
||||
@ -861,6 +912,29 @@ static struct token tokentab2[] =
|
||||
{">=", GEQ, BINOP_END}
|
||||
};
|
||||
|
||||
/* assign machine-independent names to certain registers
|
||||
* (unless overridden by the REGISTER_NAMES table)
|
||||
*/
|
||||
struct std_regs {
|
||||
char *name;
|
||||
int regnum;
|
||||
} std_regs[] = {
|
||||
#ifdef PC_REGNUM
|
||||
{ "pc", PC_REGNUM },
|
||||
#endif
|
||||
#ifdef FP_REGNUM
|
||||
{ "fp", FP_REGNUM },
|
||||
#endif
|
||||
#ifdef SP_REGNUM
|
||||
{ "sp", SP_REGNUM },
|
||||
#endif
|
||||
#ifdef PS_REGNUM
|
||||
{ "ps", PS_REGNUM },
|
||||
#endif
|
||||
};
|
||||
|
||||
#define NUM_STD_REGS (sizeof std_regs / sizeof std_regs[0])
|
||||
|
||||
/* Read one token, getting characters through lexptr. */
|
||||
|
||||
static int
|
||||
@ -1044,7 +1118,7 @@ yylex ()
|
||||
/* Handle tokens that refer to machine registers:
|
||||
$ followed by a register name. */
|
||||
|
||||
if (*tokstart == '$')
|
||||
if (*tokstart == '$') {
|
||||
for (c = 0; c < NUM_REGS; c++)
|
||||
if (namelen - 1 == strlen (reg_names[c])
|
||||
&& !strncmp (tokstart + 1, reg_names[c], namelen - 1))
|
||||
@ -1052,7 +1126,14 @@ yylex ()
|
||||
yylval.lval = c;
|
||||
return REGNAME;
|
||||
}
|
||||
|
||||
for (c = 0; c < NUM_STD_REGS; c++)
|
||||
if (namelen - 1 == strlen (std_regs[c].name)
|
||||
&& !strncmp (tokstart + 1, std_regs[c].name, namelen - 1))
|
||||
{
|
||||
yylval.lval = std_regs[c].regnum;
|
||||
return REGNAME;
|
||||
}
|
||||
}
|
||||
if (namelen == 6 && !strncmp (tokstart, "struct", 6))
|
||||
{
|
||||
return STRUCT;
|
||||
@ -1070,10 +1151,10 @@ yylex ()
|
||||
{
|
||||
return ENUM;
|
||||
}
|
||||
if (!strncmp (tokstart, "this", 4))
|
||||
{
|
||||
return THIS;
|
||||
}
|
||||
if (!strncmp (tokstart, "this", 4)
|
||||
&& lookup_symbol ("$this", expression_context_block,
|
||||
VAR_NAMESPACE, 0))
|
||||
return THIS;
|
||||
}
|
||||
if (namelen == 6 && !strncmp (tokstart, "sizeof", 6))
|
||||
{
|
||||
@ -1102,7 +1183,7 @@ yylex ()
|
||||
return NAME;
|
||||
}
|
||||
|
||||
static
|
||||
static void
|
||||
yyerror ()
|
||||
{
|
||||
error ("Invalid syntax in expression.");
|
||||
@ -1361,6 +1442,8 @@ parse_c_1 (stringptr, block, comma)
|
||||
|
||||
lexptr = *stringptr;
|
||||
|
||||
paren_depth = 0;
|
||||
|
||||
comma_terminates = comma;
|
||||
|
||||
if (lexptr == 0 || *lexptr == 0)
|
||||
@ -1374,8 +1457,9 @@ parse_c_1 (stringptr, block, comma)
|
||||
namecopy = (char *) alloca (strlen (lexptr) + 1);
|
||||
expout_size = 10;
|
||||
expout_ptr = 0;
|
||||
expout = (struct expression *) xmalloc (sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
expout = (struct expression *)
|
||||
xmalloc (sizeof (struct expression)
|
||||
+ expout_size * sizeof (union exp_element));
|
||||
make_cleanup (free_current_contents, &expout);
|
||||
if (yyparse ())
|
||||
yyerror ();
|
||||
|
@ -175,7 +175,7 @@ union exp_element
|
||||
{
|
||||
enum exp_opcode opcode;
|
||||
struct symbol *symbol;
|
||||
long longconst;
|
||||
LONGEST longconst;
|
||||
double doubleconst;
|
||||
char string;
|
||||
struct type *type;
|
||||
|
308
gdb/findvar.c
308
gdb/findvar.c
@ -19,7 +19,6 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "initialize.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
@ -27,34 +26,56 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
CORE_ADDR read_register ();
|
||||
|
||||
START_FILE
|
||||
|
||||
/* Return the address in which frame FRAME's value of register REGNUM
|
||||
has been saved in memory. Or return zero if it has not been saved.
|
||||
If REGNUM specifies the SP, the value we return is actually
|
||||
the SP value, not an address where it was saved. */
|
||||
|
||||
static CORE_ADDR
|
||||
CORE_ADDR
|
||||
find_saved_register (frame, regnum)
|
||||
FRAME frame;
|
||||
int regnum;
|
||||
{
|
||||
struct frame_info fi;
|
||||
struct frame_info *fi;
|
||||
struct frame_saved_regs saved_regs;
|
||||
|
||||
register FRAME frame1 = 0;
|
||||
register CORE_ADDR addr = 0;
|
||||
|
||||
#ifdef HAVE_REGISTER_WINDOWS
|
||||
/* We assume that a register in a register window will only be saved
|
||||
in one place (since the name changes and dissapears as you go
|
||||
towards inner frames), so we only call get_frame_saved_regs on
|
||||
the current frame. This is directly in contradiction to the
|
||||
usage below, which assumes that registers used in a frame must be
|
||||
saved in a lower (more interior) frame. This change is a result
|
||||
of working on a register window machine; get_frame_saved_regs
|
||||
always returns the registers saved within a frame, within the
|
||||
context (register namespace) of that frame. */
|
||||
|
||||
if (REGISTER_IN_WINDOW_P(regnum))
|
||||
{
|
||||
fi = get_frame_info (frame);
|
||||
get_frame_saved_regs (fi, &saved_regs);
|
||||
return (saved_regs.regs[regnum] ?
|
||||
saved_regs.regs[regnum] : 0);
|
||||
}
|
||||
#endif /* HAVE_REGISTER_WINDOWS */
|
||||
|
||||
/* Note that this next routine assumes that registers used in
|
||||
frame x will be saved only in the frame that x calls and
|
||||
frames interior to it. This is not true on the sparc, but the
|
||||
above macro takes care of it, so we should be all right. */
|
||||
while (1)
|
||||
{
|
||||
QUIT;
|
||||
fi = get_prev_frame_info (frame1);
|
||||
if (fi.frame == 0 || fi.frame == frame)
|
||||
frame1 = get_prev_frame (frame1);
|
||||
if (frame1 == 0 || frame1 == frame)
|
||||
break;
|
||||
get_frame_saved_regs (&fi, &saved_regs);
|
||||
fi = get_frame_info (frame1);
|
||||
get_frame_saved_regs (fi, &saved_regs);
|
||||
if (saved_regs.regs[regnum])
|
||||
addr = saved_regs.regs[regnum];
|
||||
frame1 = fi.frame;
|
||||
}
|
||||
|
||||
return addr;
|
||||
@ -73,7 +94,7 @@ read_relative_register_raw_bytes (regnum, myaddr)
|
||||
|
||||
if (regnum == FP_REGNUM)
|
||||
{
|
||||
bcopy (&selected_frame, myaddr, sizeof (CORE_ADDR));
|
||||
bcopy (&FRAME_FP(selected_frame), myaddr, sizeof (CORE_ADDR));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -102,15 +123,19 @@ value
|
||||
value_of_register (regnum)
|
||||
int regnum;
|
||||
{
|
||||
register CORE_ADDR addr = find_saved_register (selected_frame, regnum);
|
||||
register CORE_ADDR addr;
|
||||
register value val;
|
||||
char raw_buffer[MAX_REGISTER_RAW_SIZE];
|
||||
char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
|
||||
|
||||
if (! (have_inferior_p () || have_core_file_p ()))
|
||||
error ("Can't get value of register without inferior or core file");
|
||||
|
||||
addr = find_saved_register (selected_frame, regnum);
|
||||
if (addr)
|
||||
{
|
||||
if (regnum == SP_REGNUM)
|
||||
return value_from_long (builtin_type_int, addr);
|
||||
return value_from_long (builtin_type_int, (LONGEST) addr);
|
||||
read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
|
||||
}
|
||||
else
|
||||
@ -137,6 +162,7 @@ char registers[REGISTER_BYTES];
|
||||
starting with the REGBYTE'th byte of register data
|
||||
into memory at MYADDR. */
|
||||
|
||||
void
|
||||
read_register_bytes (regbyte, myaddr, len)
|
||||
int regbyte;
|
||||
char *myaddr;
|
||||
@ -148,6 +174,7 @@ read_register_bytes (regbyte, myaddr, len)
|
||||
/* Copy LEN bytes of consecutive data from memory at MYADDR
|
||||
into registers starting with the REGBYTE'th byte of register data. */
|
||||
|
||||
void
|
||||
write_register_bytes (regbyte, myaddr, len)
|
||||
int regbyte;
|
||||
char *myaddr;
|
||||
@ -211,7 +238,7 @@ read_var_value (var, frame)
|
||||
{
|
||||
register value v;
|
||||
|
||||
struct frame_info fi;
|
||||
struct frame_info *fi;
|
||||
|
||||
struct type *type = SYMBOL_TYPE (var);
|
||||
register CORE_ADDR addr = 0;
|
||||
@ -260,84 +287,178 @@ read_var_value (var, frame)
|
||||
|
||||
case LOC_REGISTER:
|
||||
case LOC_REGPARM:
|
||||
{
|
||||
char raw_buffer[MAX_REGISTER_RAW_SIZE];
|
||||
char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
|
||||
|
||||
VALUE_REGNO (v) = val;
|
||||
|
||||
/* Locate the register's contents in a real register or in core;
|
||||
read the data in raw format. */
|
||||
|
||||
addr = find_saved_register (frame, val);
|
||||
if (addr == 0)
|
||||
{
|
||||
/* Value is really in a register. */
|
||||
|
||||
VALUE_LVAL (v) = lval_register;
|
||||
VALUE_ADDRESS (v) = REGISTER_BYTE (val);
|
||||
|
||||
read_register_bytes (REGISTER_BYTE (val),
|
||||
raw_buffer, REGISTER_RAW_SIZE (val));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Value was in a register that has been saved in memory. */
|
||||
|
||||
read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (val));
|
||||
VALUE_ADDRESS (v) = addr;
|
||||
}
|
||||
|
||||
/* Convert the raw contents to virtual contents.
|
||||
(Just copy them if the formats are the same.) */
|
||||
|
||||
REGISTER_CONVERT_TO_VIRTUAL (val, raw_buffer, virtual_buffer);
|
||||
|
||||
if (REGISTER_CONVERTIBLE (val))
|
||||
{
|
||||
/* When the raw and virtual formats differ, the virtual format
|
||||
corresponds to a specific data type. If we want that type,
|
||||
copy the data into the value.
|
||||
Otherwise, do a type-conversion. */
|
||||
|
||||
if (type != REGISTER_VIRTUAL_TYPE (val))
|
||||
{
|
||||
/* eg a variable of type `float' in a 68881 register
|
||||
with raw type `extended' and virtual type `double'.
|
||||
Fetch it as a `double' and then convert to `float'. */
|
||||
v = allocate_value (REGISTER_VIRTUAL_TYPE (val));
|
||||
bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
|
||||
v = value_cast (type, v);
|
||||
}
|
||||
else
|
||||
bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raw and virtual formats are the same for this register. */
|
||||
|
||||
union { int i; char c; } test;
|
||||
/* If we want less than the full size, we need to
|
||||
test for a big-endian or little-endian machine. */
|
||||
test.i = 1;
|
||||
if (test.c != 1 && len < REGISTER_RAW_SIZE (val))
|
||||
{
|
||||
/* Big-endian, and we want less than full size. */
|
||||
VALUE_OFFSET (v) = REGISTER_RAW_SIZE (val) - len;
|
||||
}
|
||||
|
||||
bcopy (virtual_buffer + VALUE_OFFSET (v),
|
||||
VALUE_CONTENTS (v), len);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
v = value_from_register (type, val, frame);
|
||||
return v;
|
||||
}
|
||||
|
||||
read_memory (addr, VALUE_CONTENTS (v), len);
|
||||
VALUE_ADDRESS (v) = addr;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Return a value of type TYPE, stored in register REGNUM, in frame
|
||||
FRAME. */
|
||||
|
||||
value
|
||||
value_from_register (type, regnum, frame)
|
||||
struct type *type;
|
||||
int regnum;
|
||||
FRAME frame;
|
||||
{
|
||||
char raw_buffer [MAX_REGISTER_RAW_SIZE];
|
||||
char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
|
||||
CORE_ADDR addr;
|
||||
value v = allocate_value (type);
|
||||
int len = TYPE_LENGTH (type);
|
||||
char *value_bytes = 0;
|
||||
int value_bytes_copied = 0;
|
||||
int num_storage_locs;
|
||||
|
||||
VALUE_REGNO (v) = regnum;
|
||||
|
||||
num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ?
|
||||
((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 :
|
||||
1);
|
||||
|
||||
if (num_storage_locs > 1)
|
||||
{
|
||||
/* Value spread across multiple storage locations. */
|
||||
|
||||
int local_regnum;
|
||||
int mem_stor = 0, reg_stor = 0;
|
||||
int mem_tracking = 1;
|
||||
CORE_ADDR last_addr = 0;
|
||||
|
||||
value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE);
|
||||
|
||||
/* Copy all of the data out, whereever it may be. */
|
||||
|
||||
for (local_regnum = regnum;
|
||||
value_bytes_copied < len;
|
||||
(value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
|
||||
++local_regnum))
|
||||
{
|
||||
int register_index = local_regnum - regnum;
|
||||
addr = find_saved_register (frame, local_regnum);
|
||||
if (addr == 0)
|
||||
{
|
||||
read_register_bytes (REGISTER_BYTE (local_regnum),
|
||||
value_bytes + value_bytes_copied,
|
||||
REGISTER_RAW_SIZE (local_regnum));
|
||||
reg_stor++;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_memory (addr, value_bytes + value_bytes_copied,
|
||||
REGISTER_RAW_SIZE (local_regnum));
|
||||
mem_stor++;
|
||||
mem_tracking =
|
||||
(mem_tracking
|
||||
&& (regnum == local_regnum
|
||||
|| addr == last_addr));
|
||||
}
|
||||
last_addr = addr;
|
||||
}
|
||||
|
||||
if ((reg_stor && mem_stor)
|
||||
|| (mem_stor && !mem_tracking))
|
||||
/* Mixed storage; all of the hassle we just went through was
|
||||
for some good purpose. */
|
||||
{
|
||||
VALUE_LVAL (v) = lval_reg_frame_relative;
|
||||
VALUE_FRAME (v) = FRAME_FP (frame);
|
||||
VALUE_FRAME_REGNUM (v) = regnum;
|
||||
}
|
||||
else if (mem_stor)
|
||||
{
|
||||
VALUE_LVAL (v) = lval_memory;
|
||||
VALUE_ADDRESS (v) = find_saved_register (frame, regnum);
|
||||
}
|
||||
else if (reg_stor)
|
||||
{
|
||||
VALUE_LVAL (v) = lval_register;
|
||||
VALUE_ADDRESS (v) = REGISTER_BYTE (regnum);
|
||||
}
|
||||
else
|
||||
fatal ("value_from_register: Value not stored anywhere!");
|
||||
|
||||
/* Any structure stored in more than one register will always be
|
||||
an inegral number of registers. Otherwise, you'd need to do
|
||||
some fiddling with the last register copied here for little
|
||||
endian machines. */
|
||||
|
||||
/* Copy into the contents section of the value. */
|
||||
bcopy (value_bytes, VALUE_CONTENTS (v), len);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Data is completely contained within a single register. Locate the
|
||||
register's contents in a real register or in core;
|
||||
read the data in raw format. */
|
||||
|
||||
addr = find_saved_register (frame, regnum);
|
||||
if (addr == 0)
|
||||
{
|
||||
/* Value is really in a register. */
|
||||
|
||||
VALUE_LVAL (v) = lval_register;
|
||||
VALUE_ADDRESS (v) = REGISTER_BYTE (regnum);
|
||||
|
||||
read_register_bytes (REGISTER_BYTE (regnum),
|
||||
raw_buffer, REGISTER_RAW_SIZE (regnum));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Value was in a register that has been saved in memory. */
|
||||
|
||||
read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
|
||||
VALUE_LVAL (v) = lval_memory;
|
||||
VALUE_ADDRESS (v) = addr;
|
||||
}
|
||||
|
||||
/* Convert the raw contents to virtual contents.
|
||||
(Just copy them if the formats are the same.) */
|
||||
|
||||
REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
|
||||
|
||||
if (REGISTER_CONVERTIBLE (regnum))
|
||||
{
|
||||
/* When the raw and virtual formats differ, the virtual format
|
||||
corresponds to a specific data type. If we want that type,
|
||||
copy the data into the value.
|
||||
Otherwise, do a type-conversion. */
|
||||
|
||||
if (type != REGISTER_VIRTUAL_TYPE (regnum))
|
||||
{
|
||||
/* eg a variable of type `float' in a 68881 register
|
||||
with raw type `extended' and virtual type `double'.
|
||||
Fetch it as a `double' and then convert to `float'. */
|
||||
v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
|
||||
bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
|
||||
v = value_cast (type, v);
|
||||
}
|
||||
else
|
||||
bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raw and virtual formats are the same for this register. */
|
||||
|
||||
#ifdef BYTES_BIG_ENDIAN
|
||||
if (len < REGISTER_RAW_SIZE (regnum))
|
||||
{
|
||||
/* Big-endian, and we want less than full size. */
|
||||
VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len;
|
||||
}
|
||||
#endif
|
||||
|
||||
bcopy (virtual_buffer + VALUE_OFFSET (v),
|
||||
VALUE_CONTENTS (v), len);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Given a struct symbol for a variable,
|
||||
and a stack frame address,
|
||||
@ -350,7 +471,7 @@ locate_var_value (var, frame)
|
||||
{
|
||||
register CORE_ADDR addr = 0;
|
||||
int val = SYMBOL_VALUE (var);
|
||||
struct frame_info fi;
|
||||
struct frame_info *fi;
|
||||
struct type *type = SYMBOL_TYPE (var);
|
||||
|
||||
if (frame == 0) frame = selected_frame;
|
||||
@ -367,14 +488,12 @@ locate_var_value (var, frame)
|
||||
addr = find_saved_register (frame, val);
|
||||
if (addr != 0)
|
||||
{
|
||||
union { int i; char c; } test;
|
||||
int len = TYPE_LENGTH (type);
|
||||
/* If var is less than the full size of register, we need to
|
||||
test for a big-endian or little-endian machine. */
|
||||
test.i = 1;
|
||||
if (test.c != 1 && len < REGISTER_RAW_SIZE (val))
|
||||
#ifdef BYTES_BIG_ENDIAN
|
||||
if (len < REGISTER_RAW_SIZE (val))
|
||||
/* Big-endian, and we want less than full size. */
|
||||
addr += REGISTER_RAW_SIZE (val) - len;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
error ("Address requested for identifier \"%s\" which is in a register.",
|
||||
@ -405,11 +524,6 @@ locate_var_value (var, frame)
|
||||
}
|
||||
|
||||
return value_cast (lookup_pointer_type (type),
|
||||
value_from_long (builtin_type_long, addr));
|
||||
value_from_long (builtin_type_long, (LONGEST) addr));
|
||||
}
|
||||
|
||||
static
|
||||
initialize ()
|
||||
{}
|
||||
|
||||
END_FILE
|
||||
|
67
gdb/frame.h
67
gdb/frame.h
@ -20,22 +20,62 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
/* Note that frame.h requires param.h! */
|
||||
|
||||
#define FRAME CORE_ADDR
|
||||
/*
|
||||
* FRAME is the type of the identifier of a specific stack frame. It
|
||||
* is a pointer to the frame cache item corresponding to this frame.
|
||||
* Please note that frame id's are *not* constant over calls to the
|
||||
* inferior. Use frame addresses, which are.
|
||||
*
|
||||
* FRAME_ADDR is the type of the address of a specific frame. I
|
||||
* cannot imagine a case in which this would not be CORE_ADDR, so
|
||||
* maybe it's silly to give it it's own type. Life's rough.
|
||||
*
|
||||
* FRAME_FP is a macro which converts from a frame identifier into a
|
||||
* frame_address.
|
||||
*
|
||||
* FRAME_INFO_ID is a macro which "converts" from a frame info pointer
|
||||
* to a frame id. This is here in case I or someone else decides to
|
||||
* change the FRAME type again.
|
||||
*
|
||||
* This file and blockframe.c are the only places which are allowed to
|
||||
* use the equivalence between FRAME and struct frame_info *. EXCEPTION:
|
||||
* value.h uses CORE_ADDR instead of FRAME_ADDR because the compiler
|
||||
* will accept that in the absense of this file.
|
||||
*/
|
||||
typedef struct frame_info *FRAME;
|
||||
typedef CORE_ADDR FRAME_ADDR;
|
||||
#define FRAME_FP(fr) ((fr)->frame)
|
||||
#define FRAME_INFO_ID(f) (f)
|
||||
|
||||
/*
|
||||
* Caching structure for stack frames. This is also the structure
|
||||
* used for extended info about stack frames. May add more to this
|
||||
* structure as it becomes necessary.
|
||||
*
|
||||
* Note that the first entry in the cache will always refer to the
|
||||
* innermost executing frame. This value should be set (is it?
|
||||
* Check) in something like normal_stop.
|
||||
*/
|
||||
struct frame_info
|
||||
{
|
||||
/* Nominal address of the frame described. */
|
||||
FRAME frame;
|
||||
FRAME_ADDR frame;
|
||||
/* Address at which execution is occurring in this frame.
|
||||
For the innermost frame, it's the current pc.
|
||||
For other frames, it is a pc saved in the next frame. */
|
||||
CORE_ADDR pc;
|
||||
/* The frame called by the frame we are describing, or 0. */
|
||||
FRAME next_frame;
|
||||
|
||||
/* The frame called by `next_frame', or 0 if there is none
|
||||
(or `next_frame' is 0). */
|
||||
FRAME next_next_frame;
|
||||
/* The frame called by the frame we are describing, or 0.
|
||||
This may be set even if there isn't a frame called by the one
|
||||
we are describing (.->next == 0); in that case it is simply the
|
||||
bottom of this frame */
|
||||
FRAME_ADDR next_frame;
|
||||
/* Anything extra for this structure that may have been defined
|
||||
in the machine depedent files. */
|
||||
#ifdef EXTRA_FRAME_INFO
|
||||
EXTRA_FRAME_INFO
|
||||
#endif
|
||||
/* Pointers to the next and previous frame_info's in this stack. */
|
||||
FRAME next, prev;
|
||||
};
|
||||
|
||||
/* Describe the saved registers of a frame. */
|
||||
@ -52,13 +92,14 @@ struct frame_saved_regs
|
||||
|
||||
extern FRAME selected_frame;
|
||||
|
||||
extern struct frame_info get_frame_info ();
|
||||
extern struct frame_info get_prev_frame_info ();
|
||||
extern struct frame_info *get_frame_info ();
|
||||
extern struct frame_info *get_prev_frame_info ();
|
||||
|
||||
extern FRAME create_new_frame ();
|
||||
|
||||
extern void get_frame_saved_regs ();
|
||||
|
||||
extern FRAME get_prev_frame ();
|
||||
|
||||
extern FRAME get_current_frame ();
|
||||
|
||||
extern struct block *get_frame_block ();
|
||||
@ -66,3 +107,7 @@ extern struct block *get_current_block ();
|
||||
extern struct block *get_selected_block ();
|
||||
extern struct symbol *get_frame_function ();
|
||||
extern struct symbol *get_pc_function ();
|
||||
|
||||
/* In stack.c */
|
||||
extern FRAME find_relative_frame ();
|
||||
|
||||
|
91
gdb/gdb.1
91
gdb/gdb.1
@ -1,91 +0,0 @@
|
||||
.TH GDB 1 "13 April 1987"
|
||||
.UC 4
|
||||
.SH NAME
|
||||
gdb \- Project GNU's DeBugger
|
||||
.SH SYNOPSIS
|
||||
\fBgdb\fP [ \fBoptions\fP ] See documentation mentioned below.
|
||||
.SH DESCRIPTION
|
||||
\fIgdb\fP is a source level symbolic debugger for C programs, created by
|
||||
Richard M. Stallman (rms) for the GNU Project, and distributed by the
|
||||
Free Software Foundation. Eventually GNU (Gnu's Not Unix) will be a
|
||||
complete replacement for Berkeley Unix, all of which everyone will be
|
||||
able to use freely. See the \fIGNU Emacs\fP man page for pointers to more
|
||||
information.
|
||||
.PP
|
||||
\fIgdb\fP has something of the flavor of \fIdbx\fP,
|
||||
but has more features and power. It can also be used to debug o/s
|
||||
kernels, but needs to be configured differently for that task.
|
||||
.PP
|
||||
Project GNU isn't using Unix man pages. Its style of complete
|
||||
documentation can be found by:
|
||||
.PP
|
||||
The help and info commands inside \fIgdb\fP.
|
||||
.PP
|
||||
In the Info system in \fIGNU Emacs\fP. Type C-h i, and follow the
|
||||
directions. This is equivalent to the reference manual for
|
||||
\fIgdb\fP, and has about 55 pages of text.
|
||||
.PP
|
||||
\fIgdb\fP could be extended to work with other languages (e.g. Pascal) and
|
||||
machines (e.g. encores). If you like, copy the sources and give it a
|
||||
try. When you have it working send \fIdiff -c\fP's of the changed files to
|
||||
bug-gdb@prep.ai.mit.edu (fuller details below), so they can benefit everyone.
|
||||
.SH DISTRIBUTION
|
||||
\fIgdb\fP is free; anyone may redistribute copies of
|
||||
\fIgdb\fP to anyone under the terms stated in the
|
||||
\fIgdb\fP General Public License, a copy of which accompanies each copy of
|
||||
\fIgdb\fP, is readable with the info command inside \fIgdb\fP,
|
||||
and which also appears in the \fIgdb\fP reference manual.
|
||||
.PP
|
||||
Copies of \fIgdb\fP may sometimes be received packaged with
|
||||
distributions of Unix systems, but it is never included in the scope
|
||||
of any license covering those systems. Such inclusion would violate
|
||||
the terms on which distribution is permitted. In fact, the primary
|
||||
purpose of the General Public License is to prohibit anyone from
|
||||
attaching any other restrictions to redistribution of \fIgdb\fP.
|
||||
.PP
|
||||
You can order printed copies of the \fIgdb\fP reference manual for $10.00/copy
|
||||
postpaid from the Free Software Foundation, which develops GNU software
|
||||
(contact them for quantity prices on the manual). Their address is:
|
||||
.nf
|
||||
Free Software Foundation
|
||||
1000 Mass Ave.
|
||||
Cambridge, MA 02138
|
||||
.fi
|
||||
As with all software and publications from FSF, everyone is permitted to
|
||||
make and distribute copies of the \fIgdb\fP reference manual.
|
||||
The TeX source to the \fIgdb\fP reference
|
||||
manual is also included in the \fIGNU Emacs\fP source distribution.
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
See documentation.
|
||||
.SH EXAMPLES
|
||||
See documentation.
|
||||
.SH "SEE ALSO"
|
||||
adb(1), sdb(1), dbx(1)
|
||||
.SH BUGS
|
||||
There is a mailing list, bug-gdb@prep.ai.mit.edu on the internet
|
||||
(ucbvax!prep.ai.mit.edu!bug-gdb on UUCPnet), for reporting \fIgdb\fP
|
||||
bugs and fixes. But before reporting something as a bug, please try
|
||||
to be sure that it really is a bug, not a misunderstanding or a
|
||||
deliberate feature. We ask you to read the section ``Reporting Emacs
|
||||
Bugs'' near the end of the \fIGNU Emacs\fP reference manual
|
||||
(or Info system) for hints
|
||||
on how and when to report bugs. Also, include the version number of
|
||||
the \fIgdb\fP you are running in \fIevery\fR bug report that you send in.
|
||||
.PP
|
||||
Do not expect a personal answer to a bug report. The purpose of reporting
|
||||
bugs is to get them fixed for everyone in the next release, if possible.
|
||||
For personal assistance, look in the SERVICE file
|
||||
(see the \fIGNU Emacs\fP man page) for
|
||||
a list of people who offer it.
|
||||
.PP
|
||||
Please do not send anything but bug reports to this mailing list.
|
||||
Send other stuff to gnu@prep.ai.mit.edu (or the
|
||||
corresponding UUCP address). For more information about GNU mailing
|
||||
lists, see the file MAILINGLISTS (see the \fIGNU Emacs\fP man page). Bugs tend
|
||||
actually to be fixed if they can be isolated, so it is in your
|
||||
interest to report them in such a way that they can be easily
|
||||
reproduced.
|
||||
.PP
|
||||
No bugs are known at this time.
|
||||
|
1034
gdb/gdb.ideas
1034
gdb/gdb.ideas
File diff suppressed because it is too large
Load Diff
2924
gdb/gdb.texinfo
Normal file
2924
gdb/gdb.texinfo
Normal file
File diff suppressed because it is too large
Load Diff
68
gdb/gdbcore.h
Normal file
68
gdb/gdbcore.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* Machine independent variables that describe the core file under GDB.
|
||||
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
extern char *corefile;
|
||||
extern char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
extern int corechan;
|
||||
extern int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
|
||||
extern int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
extern CORE_ADDR data_start;
|
||||
extern CORE_ADDR data_end;
|
||||
extern CORE_ADDR stack_start;
|
||||
extern CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
|
||||
extern CORE_ADDR text_start;
|
||||
extern CORE_ADDR text_end;
|
||||
|
||||
extern CORE_ADDR exec_data_start;
|
||||
extern CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
extern int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
extern int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
extern int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
extern int stack_offset;
|
25
gdb/getpagesize.h
Normal file
25
gdb/getpagesize.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifdef BSD
|
||||
#ifndef BSD4_1
|
||||
#define HAVE_GETPAGESIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETPAGESIZE
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef EXEC_PAGESIZE
|
||||
#define getpagesize() EXEC_PAGESIZE
|
||||
#else
|
||||
#ifdef NBPG
|
||||
#define getpagesize() NBPG * CLSIZE
|
||||
#ifndef CLSIZE
|
||||
#define CLSIZE 1
|
||||
#endif /* no CLSIZE */
|
||||
#else /* no NBPG */
|
||||
#define getpagesize() NBPC
|
||||
#endif /* no NBPG */
|
||||
#endif /* no EXEC_PAGESIZE */
|
||||
|
||||
#endif /* not HAVE_GETPAGESIZE */
|
||||
|
@ -192,14 +192,14 @@ print_insn (memaddr, stream)
|
||||
* Find the number of arguments to a function.
|
||||
*/
|
||||
findarg(frame)
|
||||
struct frame_info frame;
|
||||
struct frame_info *frame;
|
||||
{
|
||||
register struct symbol *func;
|
||||
register unsigned pc;
|
||||
|
||||
#ifdef notdef
|
||||
/* find starting address of frame function */
|
||||
pc = get_pc_function_start (frame.pc);
|
||||
pc = get_pc_function_start (frame->pc);
|
||||
|
||||
/* find function symbol info */
|
||||
func = find_pc_function (pc);
|
||||
@ -220,29 +220,35 @@ findarg(frame)
|
||||
* 1.) stored in the code function header xA(Br1).
|
||||
* 2.) must be careful of recurssion.
|
||||
*/
|
||||
FRAME_ADDR
|
||||
findframe(thisframe)
|
||||
FRAME thisframe;
|
||||
{
|
||||
register FRAME pointer;
|
||||
struct frame_info frame;
|
||||
register FRAME_ADDR pointer;
|
||||
#if 0
|
||||
struct frame_info *frame;
|
||||
FRAME_ADDR framechain();
|
||||
|
||||
/* Setup toplevel frame structure */
|
||||
frame.pc = read_pc();
|
||||
frame.next_frame = 0;
|
||||
frame.frame = read_register (SP_REGNUM); /* Br2 */
|
||||
frame->pc = read_pc();
|
||||
frame->next_frame = 0;
|
||||
frame->frame = read_register (SP_REGNUM); /* Br2 */
|
||||
|
||||
/* Search for this frame (start at current Br2) */
|
||||
do
|
||||
{
|
||||
pointer = framechain(frame);
|
||||
frame.next_frame = frame.frame;
|
||||
frame.frame = pointer;
|
||||
frame.pc = FRAME_SAVED_PC(frame.next_frame);
|
||||
frame->next_frame = frame->frame;
|
||||
frame->frame = pointer;
|
||||
frame->pc = FRAME_SAVED_PC(frame);
|
||||
}
|
||||
while (frame.next_frame != thisframe);
|
||||
while (frame->next_frame != thisframe);
|
||||
#endif
|
||||
|
||||
pointer = framechain (thisframe);
|
||||
|
||||
/* stop gap for now, end at __base3 */
|
||||
if (frame.pc == 0)
|
||||
if (thisframe->pc == 0)
|
||||
return 0;
|
||||
|
||||
return pointer;
|
||||
@ -252,20 +258,21 @@ findframe(thisframe)
|
||||
* Gdb front-end and internal framechain routine.
|
||||
* Go back up stack one level. Tricky...
|
||||
*/
|
||||
FRAME_ADDR
|
||||
framechain(frame)
|
||||
register struct frame_info frame;
|
||||
register struct frame_info *frame;
|
||||
{
|
||||
register CORE_ADDR func, prevsp;
|
||||
register unsigned value;
|
||||
|
||||
/* Get real function start address from internal frame address */
|
||||
func = get_pc_function_start(frame.pc);
|
||||
func = get_pc_function_start(frame->pc);
|
||||
|
||||
/* If no stack given, read register Br1 "(sp)" */
|
||||
if (!frame.frame)
|
||||
if (!frame->frame)
|
||||
prevsp = read_register (SP_REGNUM);
|
||||
else
|
||||
prevsp = frame.frame;
|
||||
prevsp = frame->frame;
|
||||
|
||||
/* Check function header, case #2 */
|
||||
value = read_memory_integer (func, 4);
|
||||
|
550
gdb/gould-dep.c
Normal file
550
gdb/gould-dep.c
Normal file
@ -0,0 +1,550 @@
|
||||
/* Low level interface to ptrace, for GDB when running under Unix.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <a.out.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
/* This function simply calls ptrace with the given arguments.
|
||||
It exists so that all calls to ptrace are isolated in this
|
||||
machine-dependent file. */
|
||||
int
|
||||
call_ptrace (request, pid, arg3, arg4)
|
||||
int request, pid, arg3, arg4;
|
||||
{
|
||||
return ptrace (request, pid, arg3, arg4);
|
||||
}
|
||||
|
||||
kill_inferior ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
inferior_died ();
|
||||
}
|
||||
|
||||
/* This is used when GDB is exiting. It gives less chance of error.*/
|
||||
|
||||
kill_inferior_fast ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
}
|
||||
|
||||
/* Resume execution of the inferior process.
|
||||
If STEP is nonzero, single-step it.
|
||||
If SIGNAL is nonzero, give it that signal. */
|
||||
|
||||
void
|
||||
resume (step, signal)
|
||||
int step;
|
||||
int signal;
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_resume (step, signal);
|
||||
else
|
||||
{
|
||||
ptrace (step ? 9 : 7, inferior_pid, 1, signal);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers ()
|
||||
{
|
||||
register int regno;
|
||||
register unsigned int regaddr;
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
*(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
If REGNO is -1, do this for all registers.
|
||||
Otherwise, REGNO specifies which register (so we can save time). */
|
||||
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[80];
|
||||
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
|
||||
|
||||
if (regno >= 0)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
errno = 0;
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
else for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
errno = 0;
|
||||
ptrace (6, inferior_pid, regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
|
||||
in the NEW_SUN_PTRACE case.
|
||||
It ought to be straightforward. But it appears that writing did
|
||||
not write the data that I specified. I cannot understand where
|
||||
it got the data that it actually did write. */
|
||||
|
||||
/* Copy LEN bytes from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR.
|
||||
On failure (cannot read from inferior, usually because address is out
|
||||
of bounds) returns the value of errno. */
|
||||
|
||||
int
|
||||
read_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
buffer[i] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[i] = ptrace (1, inferior_pid, addr, 0);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy LEN bytes of data from debugger memory at MYADDR
|
||||
to inferior's memory at MEMADDR.
|
||||
On failure (cannot write the inferior)
|
||||
returns the value of errno. */
|
||||
|
||||
int
|
||||
write_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Fill start and end extra bytes of buffer with existing memory data. */
|
||||
|
||||
if (remote_debugging)
|
||||
buffer[0] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[0] = ptrace (1, inferior_pid, addr, 0);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
if (remote_debugging)
|
||||
buffer[count - 1]
|
||||
= remote_fetch_word (addr + (count - 1) * sizeof (int));
|
||||
else
|
||||
buffer[count - 1]
|
||||
= ptrace (1, inferior_pid,
|
||||
addr + (count - 1) * sizeof (int), 0);
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_store_word (addr, buffer[i]);
|
||||
else
|
||||
ptrace (4, inferior_pid, addr, buffer[i]);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
This code would be in core.c if it weren't machine-dependent. */
|
||||
|
||||
/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
|
||||
#ifdef AOUTHDR
|
||||
#define COFF_FORMAT
|
||||
#endif
|
||||
|
||||
#ifndef N_TXTADDR
|
||||
#define N_TXTADDR(hdr) 0
|
||||
#endif /* no N_TXTADDR */
|
||||
|
||||
#ifndef N_DATADDR
|
||||
#define N_DATADDR(hdr) hdr.a_text
|
||||
#endif /* no N_DATADDR */
|
||||
|
||||
/* Make COFF and non-COFF names for things a little more compatible
|
||||
to reduce conditionals later. */
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
#define a_magic magic
|
||||
#endif
|
||||
|
||||
#ifndef COFF_FORMAT
|
||||
#define AOUTHDR struct exec
|
||||
#endif
|
||||
|
||||
extern char *sys_siglist[];
|
||||
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
extern void (*exec_file_display_hook) ();
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
extern char *corefile;
|
||||
extern char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
extern int corechan;
|
||||
extern int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
|
||||
extern int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
extern CORE_ADDR data_start;
|
||||
extern CORE_ADDR data_end;
|
||||
extern CORE_ADDR stack_start;
|
||||
extern CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
|
||||
extern CORE_ADDR text_start;
|
||||
extern CORE_ADDR text_end;
|
||||
|
||||
extern CORE_ADDR exec_data_start;
|
||||
extern CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
extern int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
extern int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
extern int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
extern int stack_offset;
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
/* various coff data structures */
|
||||
|
||||
extern FILHDR file_hdr;
|
||||
extern SCNHDR text_hdr;
|
||||
extern SCNHDR data_hdr;
|
||||
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
/* a.out header saved in core file. */
|
||||
|
||||
extern AOUTHDR core_aouthdr;
|
||||
|
||||
/* a.out header of exec file. */
|
||||
|
||||
extern AOUTHDR exec_aouthdr;
|
||||
|
||||
extern void validate_files ();
|
||||
|
||||
core_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
if (corefile)
|
||||
free (corefile);
|
||||
corefile = 0;
|
||||
|
||||
if (corechan >= 0)
|
||||
close (corechan);
|
||||
corechan = -1;
|
||||
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
/* Now, if a new core file was specified, open it and digest it. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
error ("To look at a core file, you must kill the inferior with \"kill\".");
|
||||
corechan = open (filename, O_RDONLY, 0);
|
||||
if (corechan < 0)
|
||||
perror_with_name (filename);
|
||||
/* 4.2-style (and perhaps also sysV-style) core dump file. */
|
||||
{
|
||||
struct user u;
|
||||
int reg_offset;
|
||||
|
||||
val = myread (corechan, &u, sizeof u);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
data_start = exec_data_start;
|
||||
|
||||
data_end = data_start + NBPG * u.u_dsize;
|
||||
stack_start = stack_end - NBPG * u.u_ssize;
|
||||
data_offset = NBPG * UPAGES;
|
||||
stack_offset = NBPG * (UPAGES + u.u_dsize);
|
||||
reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
|
||||
|
||||
/* I don't know where to find this info.
|
||||
So, for now, mark it as not available. */
|
||||
core_aouthdr.a_magic = 0;
|
||||
|
||||
/* Read the register values out of the core file and store
|
||||
them where `read_register' will find them. */
|
||||
|
||||
{
|
||||
register int regno;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
val = lseek (corechan, register_addr (regno, reg_offset), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
val = myread (corechan, buf, sizeof buf);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filename[0] == '/')
|
||||
corefile = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
corefile = concat (current_directory, "/", filename);
|
||||
}
|
||||
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
|
||||
read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No core file now.\n");
|
||||
}
|
||||
|
||||
exec_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
|
||||
/* Eliminate all traces of old exec file.
|
||||
Mark text segment as empty. */
|
||||
|
||||
if (execfile)
|
||||
free (execfile);
|
||||
execfile = 0;
|
||||
data_start = 0;
|
||||
data_end -= exec_data_start;
|
||||
text_start = 0;
|
||||
text_end = 0;
|
||||
exec_data_start = 0;
|
||||
exec_data_end = 0;
|
||||
if (execchan >= 0)
|
||||
close (execchan);
|
||||
execchan = -1;
|
||||
|
||||
/* Now open and digest the file the user requested, if any. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
|
||||
&execfile);
|
||||
if (execchan < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
{
|
||||
int aout_hdrsize;
|
||||
int num_sections;
|
||||
|
||||
if (read_file_hdr (execchan, &file_hdr) < 0)
|
||||
error ("\"%s\": not in executable format.", execfile);
|
||||
|
||||
aout_hdrsize = file_hdr.f_opthdr;
|
||||
num_sections = file_hdr.f_nscns;
|
||||
|
||||
if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
|
||||
error ("\"%s\": can't read optional aouthdr", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read text section header", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read data section header", execfile);
|
||||
|
||||
text_start = exec_aouthdr.text_start;
|
||||
text_end = text_start + exec_aouthdr.tsize;
|
||||
text_offset = text_hdr.s_scnptr;
|
||||
exec_data_start = exec_aouthdr.data_start;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.dsize;
|
||||
exec_data_offset = data_hdr.s_scnptr;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
exec_mtime = file_hdr.f_timdat;
|
||||
}
|
||||
#else /* not COFF_FORMAT */
|
||||
{
|
||||
struct stat st_exec;
|
||||
|
||||
FILHDR exec_coffhdr;
|
||||
|
||||
val = myread (execchan, &exec_coffhdr, sizeof exec_coffhdr);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
|
||||
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
text_start = N_TXTADDR (exec_aouthdr);
|
||||
exec_data_start = N_DATADDR (exec_aouthdr);
|
||||
|
||||
text_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr);
|
||||
exec_data_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr)
|
||||
+ exec_aouthdr.a_text;
|
||||
|
||||
text_end = text_start + exec_aouthdr.a_text;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.a_data;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
|
||||
fstat (execchan, &st_exec);
|
||||
exec_mtime = st_exec.st_mtime;
|
||||
}
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No exec file now.\n");
|
||||
|
||||
/* Tell display code (if any) about the changed file name. */
|
||||
if (exec_file_display_hook)
|
||||
(*exec_file_display_hook) (filename);
|
||||
}
|
132
gdb/hp-include/a.out.h
Normal file
132
gdb/hp-include/a.out.h
Normal file
@ -0,0 +1,132 @@
|
||||
/* Special version of <a.out.h> for use under hp-ux.
|
||||
Copyright (C) 1988 Free Software Foundation, Inc. */
|
||||
|
||||
/* The `exec' structure and overall layout must be close to HP's when
|
||||
we are running on an HP system, otherwise we will not be able to
|
||||
execute the resulting file. */
|
||||
|
||||
/* Allow this file to be included twice. */
|
||||
#ifndef EXEC_PAGESIZE
|
||||
|
||||
struct exec
|
||||
{
|
||||
unsigned short a_machtype; /* machine type */
|
||||
unsigned short a_magic; /* magic number */
|
||||
unsigned long a_spare1;
|
||||
unsigned long a_spare2;
|
||||
unsigned long a_text; /* size of text segment */
|
||||
unsigned long a_data; /* size of data segment */
|
||||
unsigned long a_bss; /* size of bss segment */
|
||||
unsigned long a_trsize; /* text relocation size */
|
||||
unsigned long a_drsize; /* data relocation size */
|
||||
unsigned long a_spare3; /* HP = pascal interface size */
|
||||
unsigned long a_spare4; /* HP = symbol table size */
|
||||
unsigned long a_spare5; /* HP = debug name table size */
|
||||
unsigned long a_entry; /* entry point */
|
||||
unsigned long a_spare6; /* HP = source line table size */
|
||||
unsigned long a_spare7; /* HP = value table size */
|
||||
unsigned long a_syms; /* symbol table size */
|
||||
unsigned long a_spare8;
|
||||
};
|
||||
|
||||
#define OMAGIC 0x107
|
||||
#define NMAGIC 0x108
|
||||
#define ZMAGIC 0x10B
|
||||
|
||||
#define N_BADTYPE(x) \
|
||||
((((x) . a_magic) != OMAGIC) \
|
||||
&& (((x) . a_magic) != NMAGIC) \
|
||||
&& (((x) . a_magic) != ZMAGIC))
|
||||
|
||||
#define HP98x6_ID 0x20A
|
||||
#define HP9000S200_ID 0x20C
|
||||
|
||||
#define N_BADMACH(x) \
|
||||
((((x) . a_machtype) != HP9000S200_ID) \
|
||||
&& (((x) . a_machtype) != HP98x6_ID))
|
||||
|
||||
#define N_BADMAG(x) ((N_BADTYPE (x)) || (N_BADMACH (x)))
|
||||
|
||||
#define EXEC_PAGESIZE 0x1000
|
||||
|
||||
#define EXEC_ALIGN(offset) \
|
||||
(((offset) + (EXEC_PAGESIZE - 1)) & (~ (EXEC_PAGESIZE - 1)))
|
||||
|
||||
#define N_TXTOFF(x) \
|
||||
((((x) . a_magic) == ZMAGIC) \
|
||||
? (EXEC_ALIGN (sizeof (struct exec))) \
|
||||
: (sizeof (struct exec)))
|
||||
|
||||
#define N_DATOFF(x) \
|
||||
((((x) . a_magic) == ZMAGIC) \
|
||||
? ((EXEC_ALIGN (sizeof (struct exec))) \
|
||||
+ (EXEC_ALIGN ((x) . a_text))) \
|
||||
: ((sizeof (struct exec)) + ((x) . a_text)))
|
||||
|
||||
#define N_TROFF(x) \
|
||||
((((x) . a_magic) == ZMAGIC) \
|
||||
? ((EXEC_ALIGN (sizeof (struct exec))) \
|
||||
+ (EXEC_ALIGN ((x) . a_text)) \
|
||||
+ (EXEC_ALIGN ((x) . a_data))) \
|
||||
: ((sizeof (struct exec)) + ((x) . a_text) + ((x) . a_data)))
|
||||
|
||||
#define N_SYMOFF(x) ((N_TROFF (x)) + ((x) . a_trsize) + ((x) . a_drsize))
|
||||
|
||||
#define N_STROFF(x) ((N_SYMOFF (x)) + ((x) . a_syms))
|
||||
|
||||
/* Macros which take exec structures as arguments and tell where the
|
||||
various pieces will be loaded. */
|
||||
|
||||
#define N_TXTADDR(x) 0
|
||||
|
||||
#define N_DATADDR(x) \
|
||||
((((x) . a_magic) == OMAGIC) \
|
||||
? ((x) . a_text) \
|
||||
: (EXEC_ALIGN ((x) . a_text)))
|
||||
|
||||
#define N_BSSADDR(x) ((N_DATADDR (x)) + ((x) . a_data))
|
||||
|
||||
struct relocation_info
|
||||
{
|
||||
long r_address; /* address which is relocated */
|
||||
unsigned int
|
||||
r_symbolnum : 24, /* local symbol ordinal */
|
||||
r_pcrel : 1, /* was relocated pc relative already */
|
||||
r_length : 2, /* 0=byte, 1=word, 2=long */
|
||||
r_extern : 1, /* does not include value of sym referenced */
|
||||
: 4; /* nothing, yet */
|
||||
};
|
||||
|
||||
struct nlist
|
||||
{
|
||||
union
|
||||
{
|
||||
char *n_name; /* for use when in-core */
|
||||
long n_strx; /* index into file string table */
|
||||
} n_un;
|
||||
unsigned char n_type; /* type flag (N_TEXT,..) */
|
||||
char n_other; /* unused */
|
||||
short n_desc; /* see <stab.h> */
|
||||
unsigned long n_value; /* value of symbol (or sdb offset) */
|
||||
};
|
||||
|
||||
/* Simple values for n_type. */
|
||||
#define N_UNDF 0x00 /* undefined */
|
||||
#define N_ABS 0x02 /* absolute */
|
||||
#define N_TEXT 0x04 /* text */
|
||||
#define N_DATA 0x06 /* data */
|
||||
#define N_BSS 0x08 /* bss */
|
||||
#define N_COMM 0x12 /* common (internal to ld) */
|
||||
#define N_FN 0x1F /* file name symbol */
|
||||
|
||||
#define N_EXT 0x01 /* external bit, or'ed in */
|
||||
#define N_TYPE 0x1E /* mask for all the type bits */
|
||||
|
||||
/* dbx entries have some of the N_STAB bits set.
|
||||
These are given in <stab.h> */
|
||||
#define N_STAB 0xE0 /* if any of these bits set, a dbx symbol */
|
||||
|
||||
/* Format for namelist values. */
|
||||
#define N_FORMAT "%08x"
|
||||
|
||||
#endif /* EXEC_PAGESIZE */
|
47
gdb/hp-include/stab.h
Normal file
47
gdb/hp-include/stab.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* @(#)stab.h 1.1 86/07/07 SMI; from UCB X.X XX/XX/XX */
|
||||
|
||||
|
||||
/* IF YOU ADD DEFINITIONS, ADD THEM TO nm.c as well */
|
||||
/*
|
||||
* This file gives definitions supplementing <a.out.h>
|
||||
* for permanent symbol table entries.
|
||||
* These must have one of the N_STAB bits on,
|
||||
* and are subject to relocation according to the masks in <a.out.h>.
|
||||
*/
|
||||
/*
|
||||
* for symbolic debugger, sdb(1):
|
||||
*/
|
||||
#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */
|
||||
#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */
|
||||
#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */
|
||||
#define N_STSYM 0x26 /* static symbol: name,,0,type,address */
|
||||
#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */
|
||||
#define N_MAIN 0x2a /* name of main routine : name,,0,0,0 */
|
||||
#define N_RSYM 0x40 /* register sym: name,,0,type,register */
|
||||
#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */
|
||||
#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */
|
||||
#define N_SO 0x64 /* source file name: name,,0,0,address */
|
||||
#define N_LSYM 0x80 /* local sym: name,,0,type,offset */
|
||||
#define N_BINCL 0x82 /* header file: name,,0,0,0 */
|
||||
#define N_SOL 0x84 /* #included file name: name,,0,0,address */
|
||||
#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */
|
||||
#define N_EINCL 0xa2 /* end of include file */
|
||||
#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */
|
||||
#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */
|
||||
#define N_EXCL 0xc2 /* excluded include file */
|
||||
#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */
|
||||
#define N_BCOMM 0xe2 /* begin common: name,, */
|
||||
#define N_ECOMM 0xe4 /* end common: name,, */
|
||||
#define N_ECOML 0xe8 /* end common (local name): ,,address */
|
||||
#define N_LENG 0xfe /* second stab entry with length information */
|
||||
|
||||
/*
|
||||
* for the berkeley pascal compiler, pc(1):
|
||||
*/
|
||||
#define N_PC 0x30 /* global pascal symbol: name,,0,subtype,line */
|
||||
|
||||
/*
|
||||
* for modula-2 compiler only
|
||||
*/
|
||||
#define N_M2C 0x42 /* compilation unit stab */
|
||||
#define N_SCOPE 0xc4 /* scope information */
|
73
gdb/hp-include/sys/fcntl.h
Normal file
73
gdb/hp-include/sys/fcntl.h
Normal file
@ -0,0 +1,73 @@
|
||||
/* @(#)fcntl.h 1.3 86/07/16 SMI; from UCB 5.1 85/05/30 */
|
||||
/*
|
||||
* Copyright (c) 1983 Regents of the University of California.
|
||||
* All rights reserved. The Berkeley software License Agreement
|
||||
* specifies the terms and conditions for redistribution.
|
||||
*/
|
||||
|
||||
#ifndef __FCNTL_HEADER__
|
||||
#define __FCNTL_HEADER__
|
||||
|
||||
/*
|
||||
* Flag values accessible to open(2) and fcntl(2)
|
||||
* (The first three can only be set by open)
|
||||
*/
|
||||
#define O_RDONLY 0
|
||||
#define O_WRONLY 1
|
||||
#define O_RDWR 2
|
||||
#define O_NDELAY FNDELAY /* Non-blocking I/O */
|
||||
#define O_APPEND FAPPEND /* append (writes guaranteed at the end) */
|
||||
#define O_CREAT FCREAT /* open with file create */
|
||||
#define O_TRUNC FTRUNC /* open with truncation */
|
||||
#define O_EXCL FEXCL /* error on create if file exists */
|
||||
|
||||
/* flags for F_GETFL, F_SETFL-- needed by <sys/file.h> */
|
||||
#define FNDELAY 00004 /* non-blocking reads */
|
||||
#define FAPPEND 00010 /* append on each write */
|
||||
#define FASYNC 00100 /* signal pgrp when data ready */
|
||||
#define FCREAT 01000 /* create if nonexistant */
|
||||
#define FTRUNC 02000 /* truncate to zero length */
|
||||
#define FEXCL 04000 /* error if already created */
|
||||
|
||||
/* fcntl(2) requests */
|
||||
#define F_DUPFD 0 /* Duplicate fildes */
|
||||
#define F_GETFD 1 /* Get fildes flags */
|
||||
#define F_SETFD 2 /* Set fildes flags */
|
||||
#define F_GETFL 3 /* Get file flags */
|
||||
#define F_SETFL 4 /* Set file flags */
|
||||
#define F_GETOWN 5 /* Get owner */
|
||||
#define F_SETOWN 6 /* Set owner */
|
||||
#define F_GETLK 7 /* Get record-locking information */
|
||||
#define F_SETLK 8 /* Set or Clear a record-lock (Non-Blocking) */
|
||||
#define F_SETLKW 9 /* Set or Clear a record-lock (Blocking) */
|
||||
|
||||
/* access(2) requests */
|
||||
#define F_OK 0 /* does file exist */
|
||||
#define X_OK 1 /* is it executable by caller */
|
||||
#define W_OK 2 /* writable by caller */
|
||||
#define R_OK 4 /* readable by caller */
|
||||
|
||||
/* System-V record-locking options */
|
||||
/* lockf(2) requests */
|
||||
#define F_ULOCK 0 /* Unlock a previously locked region */
|
||||
#define F_LOCK 1 /* Lock a region for exclusive use */
|
||||
#define F_TLOCK 2 /* Test and lock a region for exclusive use */
|
||||
#define F_TEST 3 /* Test a region for other processes locks */
|
||||
|
||||
/* fcntl(2) flags (l_type field of flock structure) */
|
||||
#define F_RDLCK 1 /* read lock */
|
||||
#define F_WRLCK 2 /* write lock */
|
||||
#define F_UNLCK 3 /* remove lock(s) */
|
||||
|
||||
|
||||
/* file segment locking set data type - information passed to system by user */
|
||||
struct flock {
|
||||
short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */
|
||||
short l_whence; /* flag to choose starting offset */
|
||||
long l_start; /* relative offset, in bytes */
|
||||
long l_len; /* length, in bytes; 0 means lock to EOF */
|
||||
short l_pid; /* returned with F_GETLK */
|
||||
short l_xxx; /* reserved for future use */
|
||||
};
|
||||
|
||||
#endif !__FCNTL_HEADER__
|
643
gdb/hp9k320-dep.c
Normal file
643
gdb/hp9k320-dep.c
Normal file
@ -0,0 +1,643 @@
|
||||
/* Low level interface to ptrace, for GDB when running under Unix.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#define WOPR
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/reg.h>
|
||||
#include <sys/trap.h>
|
||||
|
||||
#include <a.out.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
/* This function simply calls ptrace with the given arguments.
|
||||
It exists so that all calls to ptrace are isolated in this
|
||||
machine-dependent file. */
|
||||
int
|
||||
call_ptrace (request, pid, arg3, arg4)
|
||||
int request, pid, arg3, arg4;
|
||||
{
|
||||
return ptrace (request, pid, arg3, arg4);
|
||||
}
|
||||
|
||||
kill_inferior ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
inferior_died ();
|
||||
}
|
||||
|
||||
/* This is used when GDB is exiting. It gives less chance of error.*/
|
||||
|
||||
kill_inferior_fast ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
}
|
||||
|
||||
/* Resume execution of the inferior process.
|
||||
If STEP is nonzero, single-step it.
|
||||
If SIGNAL is nonzero, give it that signal. */
|
||||
|
||||
void
|
||||
resume (step, signal)
|
||||
int step;
|
||||
int signal;
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_resume (step, signal);
|
||||
else
|
||||
{
|
||||
ptrace (step ? 9 : 7, inferior_pid, 1, signal);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
}
|
||||
|
||||
#define INFERIOR_AR0(u) \
|
||||
((ptrace \
|
||||
(PT_RUAREA, inferior_pid, ((char *) &u.u_ar0 - (char *) &u), 0)) \
|
||||
- KERNEL_U_ADDR)
|
||||
|
||||
static void
|
||||
fetch_inferior_register (regno, regaddr)
|
||||
register int regno;
|
||||
register unsigned int regaddr;
|
||||
{
|
||||
#ifndef HPUX_VERSION_5
|
||||
if (regno == PS_REGNUM)
|
||||
{
|
||||
union { int i; short s[2]; } ps_val;
|
||||
int regval;
|
||||
|
||||
ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0));
|
||||
regval = ps_val.s[0];
|
||||
supply_register (regno, ®val);
|
||||
}
|
||||
else
|
||||
#endif /* not HPUX_VERSION_5 */
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
*(int *) &buf[i] = ptrace (PT_RUAREA, inferior_pid, regaddr, 0);
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
store_inferior_register_1 (regno, regaddr, value)
|
||||
int regno;
|
||||
unsigned int regaddr;
|
||||
int value;
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WUAREA, inferior_pid, regaddr, value);
|
||||
#if 0
|
||||
/* HP-UX randomly sets errno to non-zero for regno == 25.
|
||||
However, the value is correctly written, so ignore errno. */
|
||||
if (errno != 0)
|
||||
{
|
||||
char string_buf[64];
|
||||
|
||||
sprintf (string_buf, "writing register number %d", regno);
|
||||
perror_with_name (string_buf);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
store_inferior_register (regno, regaddr)
|
||||
register int regno;
|
||||
register unsigned int regaddr;
|
||||
{
|
||||
#ifndef HPUX_VERSION_5
|
||||
if (regno == PS_REGNUM)
|
||||
{
|
||||
union { int i; short s[2]; } ps_val;
|
||||
|
||||
ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0));
|
||||
ps_val.s[0] = (read_register (regno));
|
||||
store_inferior_register_1 (regno, regaddr, ps_val.i);
|
||||
}
|
||||
else
|
||||
#endif /* not HPUX_VERSION_5 */
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
extern char registers[];
|
||||
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
store_inferior_register_1
|
||||
(regno, regaddr,
|
||||
(*(int *) ®isters[(REGISTER_BYTE (regno)) + i]));
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers ()
|
||||
{
|
||||
struct user u;
|
||||
register int regno;
|
||||
register unsigned int ar0_offset;
|
||||
|
||||
ar0_offset = (INFERIOR_AR0 (u));
|
||||
for (regno = 0; (regno < FP0_REGNUM); regno++)
|
||||
fetch_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno)));
|
||||
for (; (regno < NUM_REGS); regno++)
|
||||
fetch_inferior_register (regno, (FP_REGISTER_ADDR (u, regno)));
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
If REGNO is -1, do this for all registers.
|
||||
Otherwise, REGNO specifies which register (so we can save time). */
|
||||
|
||||
store_inferior_registers (regno)
|
||||
register int regno;
|
||||
{
|
||||
struct user u;
|
||||
register unsigned int ar0_offset;
|
||||
|
||||
if (regno >= FP0_REGNUM)
|
||||
{
|
||||
store_inferior_register (regno, (FP_REGISTER_ADDR (u, regno)));
|
||||
return;
|
||||
}
|
||||
|
||||
ar0_offset = (INFERIOR_AR0 (u));
|
||||
if (regno >= 0)
|
||||
{
|
||||
store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno)));
|
||||
return;
|
||||
}
|
||||
|
||||
for (regno = 0; (regno < FP0_REGNUM); regno++)
|
||||
store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno)));
|
||||
for (; (regno < NUM_REGS); regno++)
|
||||
store_inferior_register (regno, (FP_REGISTER_ADDR (u, regno)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
|
||||
in the NEW_SUN_PTRACE case.
|
||||
It ought to be straightforward. But it appears that writing did
|
||||
not write the data that I specified. I cannot understand where
|
||||
it got the data that it actually did write. */
|
||||
|
||||
/* Copy LEN bytes from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR.
|
||||
On failure (cannot read from inferior, usually because address is out
|
||||
of bounds) returns the value of errno. */
|
||||
|
||||
int
|
||||
read_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
buffer[i] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[i] = ptrace (1, inferior_pid, addr, 0);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy LEN bytes of data from debugger memory at MYADDR
|
||||
to inferior's memory at MEMADDR.
|
||||
On failure (cannot write the inferior)
|
||||
returns the value of errno. */
|
||||
|
||||
int
|
||||
write_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Fill start and end extra bytes of buffer with existing memory data. */
|
||||
|
||||
if (remote_debugging)
|
||||
buffer[0] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[0] = ptrace (1, inferior_pid, addr, 0);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
if (remote_debugging)
|
||||
buffer[count - 1]
|
||||
= remote_fetch_word (addr + (count - 1) * sizeof (int));
|
||||
else
|
||||
buffer[count - 1]
|
||||
= ptrace (1, inferior_pid,
|
||||
addr + (count - 1) * sizeof (int), 0);
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_store_word (addr, buffer[i]);
|
||||
else
|
||||
ptrace (4, inferior_pid, addr, buffer[i]);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
This code would be in core.c if it weren't machine-dependent. */
|
||||
|
||||
/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
|
||||
#ifdef AOUTHDR
|
||||
#define COFF_FORMAT
|
||||
#endif
|
||||
|
||||
#ifdef HPUX_VERSION_5
|
||||
#define e_PS e_regs[PS]
|
||||
#define e_PC e_regs[PC]
|
||||
#endif /* HPUX_VERSION_5 */
|
||||
|
||||
|
||||
#ifndef N_TXTADDR
|
||||
#define N_TXTADDR(hdr) 0
|
||||
#endif /* no N_TXTADDR */
|
||||
|
||||
#ifndef N_DATADDR
|
||||
#define N_DATADDR(hdr) hdr.a_text
|
||||
#endif /* no N_DATADDR */
|
||||
|
||||
/* Make COFF and non-COFF names for things a little more compatible
|
||||
to reduce conditionals later. */
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
#define a_magic magic
|
||||
#endif
|
||||
|
||||
#ifndef COFF_FORMAT
|
||||
#define AOUTHDR struct exec
|
||||
#endif
|
||||
|
||||
extern char *sys_siglist[];
|
||||
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
extern void (*exec_file_display_hook) ();
|
||||
|
||||
/* File names of core file and executable file. */
|
||||
|
||||
extern char *corefile;
|
||||
extern char *execfile;
|
||||
|
||||
/* Descriptors on which core file and executable file are open.
|
||||
Note that the execchan is closed when an inferior is created
|
||||
and reopened if the inferior dies or is killed. */
|
||||
|
||||
extern int corechan;
|
||||
extern int execchan;
|
||||
|
||||
/* Last modification time of executable file.
|
||||
Also used in source.c to compare against mtime of a source file. */
|
||||
|
||||
extern int exec_mtime;
|
||||
|
||||
/* Virtual addresses of bounds of the two areas of memory in the core file. */
|
||||
|
||||
extern CORE_ADDR data_start;
|
||||
extern CORE_ADDR data_end;
|
||||
extern CORE_ADDR stack_start;
|
||||
extern CORE_ADDR stack_end;
|
||||
|
||||
/* Virtual addresses of bounds of two areas of memory in the exec file.
|
||||
Note that the data area in the exec file is used only when there is no core file. */
|
||||
|
||||
extern CORE_ADDR text_start;
|
||||
extern CORE_ADDR text_end;
|
||||
|
||||
extern CORE_ADDR exec_data_start;
|
||||
extern CORE_ADDR exec_data_end;
|
||||
|
||||
/* Address in executable file of start of text area data. */
|
||||
|
||||
extern int text_offset;
|
||||
|
||||
/* Address in executable file of start of data area data. */
|
||||
|
||||
extern int exec_data_offset;
|
||||
|
||||
/* Address in core file of start of data area data. */
|
||||
|
||||
extern int data_offset;
|
||||
|
||||
/* Address in core file of start of stack area data. */
|
||||
|
||||
extern int stack_offset;
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
/* various coff data structures */
|
||||
|
||||
extern FILHDR file_hdr;
|
||||
extern SCNHDR text_hdr;
|
||||
extern SCNHDR data_hdr;
|
||||
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
/* a.out header saved in core file. */
|
||||
|
||||
extern AOUTHDR core_aouthdr;
|
||||
|
||||
/* a.out header of exec file. */
|
||||
|
||||
extern AOUTHDR exec_aouthdr;
|
||||
|
||||
extern void validate_files ();
|
||||
|
||||
core_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
if (corefile)
|
||||
free (corefile);
|
||||
corefile = 0;
|
||||
|
||||
if (corechan >= 0)
|
||||
close (corechan);
|
||||
corechan = -1;
|
||||
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
/* Now, if a new core file was specified, open it and digest it. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
if (have_inferior_p ())
|
||||
error ("To look at a core file, you must kill the inferior with \"kill\".");
|
||||
corechan = open (filename, O_RDONLY, 0);
|
||||
if (corechan < 0)
|
||||
perror_with_name (filename);
|
||||
/* 4.2-style (and perhaps also sysV-style) core dump file. */
|
||||
{
|
||||
struct user u;
|
||||
|
||||
int reg_offset;
|
||||
|
||||
val = myread (corechan, &u, sizeof u);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
data_start = exec_data_start;
|
||||
|
||||
data_end = data_start + NBPG * u.u_dsize;
|
||||
stack_start = stack_end - NBPG * u.u_ssize;
|
||||
data_offset = NBPG * UPAGES;
|
||||
stack_offset = NBPG * (UPAGES + u.u_dsize);
|
||||
reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
|
||||
|
||||
/* I don't know where to find this info.
|
||||
So, for now, mark it as not available. */
|
||||
core_aouthdr.a_magic = 0;
|
||||
|
||||
/* Read the register values out of the core file and store
|
||||
them where `read_register' will find them. */
|
||||
|
||||
{
|
||||
register int regno;
|
||||
struct exception_stack es;
|
||||
int val;
|
||||
|
||||
val = lseek (corechan, (REGISTER_ADDR (reg_offset, 0)), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
val = myread (corechan, es,
|
||||
((char *) &es.e_offset - (char *) &es.e_regs[R0]));
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
for (regno = 0; (regno < PS_REGNUM); regno++)
|
||||
supply_register (regno, &es.e_regs[regno + R0]);
|
||||
val = es.e_PS;
|
||||
supply_register (regno++, &val);
|
||||
supply_register (regno++, &es.e_PC);
|
||||
for (; (regno < NUM_REGS); regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
val = lseek (corechan, (FP_REGISTER_ADDR (u, regno)), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
val = myread (corechan, buf, sizeof buf);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filename[0] == '/')
|
||||
corefile = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
corefile = concat (current_directory, "/", filename);
|
||||
}
|
||||
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
|
||||
read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No core file now.\n");
|
||||
}
|
||||
|
||||
exec_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
|
||||
/* Eliminate all traces of old exec file.
|
||||
Mark text segment as empty. */
|
||||
|
||||
if (execfile)
|
||||
free (execfile);
|
||||
execfile = 0;
|
||||
data_start = 0;
|
||||
data_end -= exec_data_start;
|
||||
text_start = 0;
|
||||
text_end = 0;
|
||||
exec_data_start = 0;
|
||||
exec_data_end = 0;
|
||||
if (execchan >= 0)
|
||||
close (execchan);
|
||||
execchan = -1;
|
||||
|
||||
/* Now open and digest the file the user requested, if any. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
|
||||
&execfile);
|
||||
if (execchan < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
#ifdef COFF_FORMAT
|
||||
{
|
||||
int aout_hdrsize;
|
||||
int num_sections;
|
||||
|
||||
if (read_file_hdr (execchan, &file_hdr) < 0)
|
||||
error ("\"%s\": not in executable format.", execfile);
|
||||
|
||||
aout_hdrsize = file_hdr.f_opthdr;
|
||||
num_sections = file_hdr.f_nscns;
|
||||
|
||||
if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
|
||||
error ("\"%s\": can't read optional aouthdr", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read text section header", execfile);
|
||||
|
||||
if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
|
||||
error ("\"%s\": can't read data section header", execfile);
|
||||
|
||||
text_start = exec_aouthdr.text_start;
|
||||
text_end = text_start + exec_aouthdr.tsize;
|
||||
text_offset = text_hdr.s_scnptr;
|
||||
exec_data_start = exec_aouthdr.data_start;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.dsize;
|
||||
exec_data_offset = data_hdr.s_scnptr;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
exec_mtime = file_hdr.f_timdat;
|
||||
}
|
||||
#else /* not COFF_FORMAT */
|
||||
{
|
||||
struct stat st_exec;
|
||||
|
||||
val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
|
||||
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
text_start = N_TXTADDR (exec_aouthdr);
|
||||
exec_data_start = N_DATADDR (exec_aouthdr);
|
||||
|
||||
text_offset = N_TXTOFF (exec_aouthdr);
|
||||
exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
|
||||
|
||||
text_end = text_start + exec_aouthdr.a_text;
|
||||
exec_data_end = exec_data_start + exec_aouthdr.a_data;
|
||||
data_start = exec_data_start;
|
||||
data_end += exec_data_start;
|
||||
|
||||
fstat (execchan, &st_exec);
|
||||
exec_mtime = st_exec.st_mtime;
|
||||
}
|
||||
#endif /* not COFF_FORMAT */
|
||||
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No exec file now.\n");
|
||||
|
||||
/* Tell display code (if any) about the changed file name. */
|
||||
if (exec_file_display_hook)
|
||||
(*exec_file_display_hook) (filename);
|
||||
}
|
||||
|
1203
gdb/i386-dep.c
Normal file
1203
gdb/i386-dep.c
Normal file
File diff suppressed because it is too large
Load Diff
1813
gdb/i386-pinsn.c
Normal file
1813
gdb/i386-pinsn.c
Normal file
File diff suppressed because it is too large
Load Diff
268
gdb/infcmd.c
268
gdb/infcmd.c
@ -19,9 +19,8 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "initialize.h"
|
||||
#include "symtab.h"
|
||||
#include "param.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "environ.h"
|
||||
@ -59,7 +58,7 @@ CORE_ADDR stop_pc;
|
||||
|
||||
/* Stack frame when program stopped. */
|
||||
|
||||
FRAME stop_frame;
|
||||
FRAME_ADDR stop_frame_address;
|
||||
|
||||
/* Number of breakpoint it stopped at, or 0 if none. */
|
||||
|
||||
@ -73,6 +72,11 @@ int stop_step;
|
||||
|
||||
int stop_stack_dummy;
|
||||
|
||||
/* Nonzero if stopped due to a random (unexpected) signal in inferior
|
||||
process. */
|
||||
|
||||
int stopped_by_random_signal;
|
||||
|
||||
/* Range to single step within.
|
||||
If this is nonzero, respond to a single-step signal
|
||||
by continuing to step if the pc is in this range. */
|
||||
@ -84,7 +88,7 @@ CORE_ADDR step_range_end; /* Exclusive */
|
||||
This is how we know when we step into a subroutine call,
|
||||
and how to set the frame for the breakpoint used to step out. */
|
||||
|
||||
CORE_ADDR step_frame;
|
||||
FRAME_ADDR step_frame_address;
|
||||
|
||||
/* 1 means step over all subroutine calls.
|
||||
-1 means step over calls to undebuggable functions. */
|
||||
@ -105,7 +109,6 @@ struct environ *inferior_environ;
|
||||
CORE_ADDR read_pc ();
|
||||
struct command_line *get_breakpoint_commands ();
|
||||
|
||||
START_FILE
|
||||
|
||||
int
|
||||
have_inferior_p ()
|
||||
@ -150,11 +153,11 @@ run_command (args, from_tty)
|
||||
|
||||
if (inferior_pid)
|
||||
{
|
||||
if (query ("The program being debugged has been started already.\n\
|
||||
if (
|
||||
!query ("The program being debugged has been started already.\n\
|
||||
Start it from the beginning? "))
|
||||
kill_inferior ();
|
||||
else
|
||||
error ("Program already started.");
|
||||
error ("Program not restarted.");
|
||||
kill_inferior ();
|
||||
}
|
||||
|
||||
if (remote_debugging)
|
||||
@ -200,7 +203,7 @@ cont_command (proc_count_exp, from_tty)
|
||||
|
||||
/* If have argument, set proceed count of breakpoint we stopped at. */
|
||||
|
||||
if (stop_breakpoint && proc_count_exp)
|
||||
if (stop_breakpoint > 0 && proc_count_exp)
|
||||
{
|
||||
set_ignore_count (stop_breakpoint,
|
||||
parse_and_eval_address (proc_count_exp) - 1,
|
||||
@ -261,21 +264,36 @@ step_1 (skip_subroutines, single_inst, count_string)
|
||||
{
|
||||
clear_proceed_status ();
|
||||
|
||||
step_frame = get_current_frame ();
|
||||
step_frame_address = FRAME_FP (get_current_frame ());
|
||||
|
||||
if (! single_inst)
|
||||
{
|
||||
find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
|
||||
if (step_range_end == 0)
|
||||
{
|
||||
int misc;
|
||||
|
||||
misc = find_pc_misc_function (stop_pc);
|
||||
terminal_ours ();
|
||||
error ("Current function has no line number information.");
|
||||
printf ("Current function has no line number information.\n");
|
||||
fflush (stdout);
|
||||
|
||||
/* No info or after _etext ("Can't happen") */
|
||||
if (misc == -1 || misc == misc_function_count - 1)
|
||||
error ("No data available on pc function.");
|
||||
|
||||
printf ("Single stepping until function exit.\n");
|
||||
fflush (stdout);
|
||||
|
||||
step_range_start = misc_function_vector[misc].address;
|
||||
step_range_end = misc_function_vector[misc + 1].address;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Say we are stepping, but stop after one insn whatever it does.
|
||||
Don't step through subroutine calls even to undebuggable functions. */
|
||||
Don't step through subroutine calls even to undebuggable
|
||||
functions. */
|
||||
step_range_start = step_range_end = 1;
|
||||
if (!skip_subroutines)
|
||||
step_over_calls = 0;
|
||||
@ -307,7 +325,7 @@ jump_command (arg, from_tty)
|
||||
if (!arg)
|
||||
error_no_arg ("starting address");
|
||||
|
||||
sals = decode_line_spec (arg, 1);
|
||||
sals = decode_line_spec_1 (arg, 1);
|
||||
if (sals.nelts != 1)
|
||||
{
|
||||
error ("Unreasonable jump request");
|
||||
@ -393,20 +411,6 @@ run_stack_dummy (addr, buffer)
|
||||
CORE_ADDR addr;
|
||||
REGISTER_TYPE *buffer;
|
||||
{
|
||||
int saved_pc_changed = pc_changed;
|
||||
int saved_stop_signal = stop_signal;
|
||||
int saved_stop_pc = stop_pc;
|
||||
int saved_stop_frame = stop_frame;
|
||||
int saved_stop_breakpoint = stop_breakpoint;
|
||||
int saved_stop_step = stop_step;
|
||||
int saved_stop_stack_dummy = stop_stack_dummy;
|
||||
FRAME saved_selected_frame;
|
||||
int saved_selected_level;
|
||||
struct command_line *saved_breakpoint_commands
|
||||
= get_breakpoint_commands ();
|
||||
|
||||
record_selected_frame (&saved_selected_frame, &saved_selected_level);
|
||||
|
||||
/* Now proceed, having reached the desired place. */
|
||||
clear_proceed_status ();
|
||||
if (stack_dummy_testing & 4)
|
||||
@ -419,21 +423,86 @@ run_stack_dummy (addr, buffer)
|
||||
if (!stop_stack_dummy)
|
||||
error ("Cannot continue previously requested operation.");
|
||||
|
||||
set_breakpoint_commands (saved_breakpoint_commands);
|
||||
select_frame (saved_selected_frame, saved_selected_level);
|
||||
stop_signal = saved_stop_signal;
|
||||
stop_pc = saved_stop_pc;
|
||||
stop_frame = saved_stop_frame;
|
||||
stop_breakpoint = saved_stop_breakpoint;
|
||||
stop_step = saved_stop_step;
|
||||
stop_stack_dummy = saved_stop_stack_dummy;
|
||||
pc_changed = saved_pc_changed;
|
||||
|
||||
/* On return, the stack dummy has been popped already. */
|
||||
|
||||
bcopy (stop_registers, buffer, sizeof stop_registers);
|
||||
}
|
||||
|
||||
/* Proceed until we reach the given line as argument or exit the
|
||||
function. When called with no argument, proceed until we reach a
|
||||
different source line with pc greater than our current one or exit
|
||||
the function. We skip calls in both cases.
|
||||
|
||||
The effect of this command with an argument is identical to setting
|
||||
a momentary breakpoint at the line specified and executing
|
||||
"finish".
|
||||
|
||||
Note that eventually this command should probably be changed so
|
||||
that only source lines are printed out when we hit the breakpoint
|
||||
we set. I'm going to postpone this until after a hopeful rewrite
|
||||
of wait_for_inferior and the proceed status code. -- randy */
|
||||
|
||||
void
|
||||
until_next_command (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
FRAME frame;
|
||||
CORE_ADDR pc;
|
||||
struct symbol *func;
|
||||
struct symtab_and_line sal;
|
||||
|
||||
clear_proceed_status ();
|
||||
|
||||
frame = get_current_frame ();
|
||||
|
||||
/* Step until either exited from this function or greater
|
||||
than the current line (if in symbolic section) or pc (if
|
||||
not). */
|
||||
|
||||
pc = read_pc ();
|
||||
func = find_pc_function (pc);
|
||||
|
||||
if (!func)
|
||||
{
|
||||
int misc_func = find_pc_misc_function (pc);
|
||||
|
||||
if (misc_func != -1)
|
||||
error ("Execution is not within a known function.");
|
||||
|
||||
step_range_start = misc_function_vector[misc_func].address;
|
||||
step_range_end = pc;
|
||||
}
|
||||
else
|
||||
{
|
||||
sal = find_pc_line (pc, 0);
|
||||
|
||||
step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
|
||||
step_range_end = sal.end;
|
||||
}
|
||||
|
||||
step_over_calls = 1;
|
||||
step_frame_address = FRAME_FP (frame);
|
||||
|
||||
step_multi = 0; /* Only one call to proceed */
|
||||
|
||||
proceed (-1, -1, 1);
|
||||
}
|
||||
|
||||
void
|
||||
until_command (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
if (!have_inferior_p ())
|
||||
error ("The program is not being run.");
|
||||
|
||||
if (arg)
|
||||
until_break_command (arg, from_tty);
|
||||
else
|
||||
until_next_command (arg, from_tty);
|
||||
}
|
||||
|
||||
/* "finish": Set a temporary breakpoint at the place
|
||||
the selected frame will return to, then continue. */
|
||||
|
||||
@ -444,8 +513,7 @@ finish_command (arg, from_tty)
|
||||
{
|
||||
struct symtab_and_line sal;
|
||||
register FRAME frame;
|
||||
struct frame_info fi;
|
||||
|
||||
struct frame_info *fi;
|
||||
register struct symbol *function;
|
||||
|
||||
if (!have_inferior_p ())
|
||||
@ -460,14 +528,14 @@ finish_command (arg, from_tty)
|
||||
clear_proceed_status ();
|
||||
|
||||
fi = get_frame_info (frame);
|
||||
sal = find_pc_line (fi.pc, 0);
|
||||
sal.pc = fi.pc;
|
||||
sal = find_pc_line (fi->pc, 0);
|
||||
sal.pc = fi->pc;
|
||||
set_momentary_breakpoint (sal, frame);
|
||||
|
||||
/* Find the function we will return from. */
|
||||
|
||||
fi = get_frame_info (fi.next_frame, fi.next_next_frame);
|
||||
function = find_pc_function (fi.pc);
|
||||
fi = get_frame_info (selected_frame);
|
||||
function = find_pc_function (fi->pc);
|
||||
|
||||
if (from_tty)
|
||||
{
|
||||
@ -481,12 +549,22 @@ finish_command (arg, from_tty)
|
||||
{
|
||||
struct type *value_type;
|
||||
register value val;
|
||||
CORE_ADDR funcaddr;
|
||||
|
||||
value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
|
||||
if (!value_type)
|
||||
fatal ("internal: finish_command: function has no target type");
|
||||
|
||||
if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
|
||||
return;
|
||||
|
||||
val = value_being_returned (value_type, stop_registers);
|
||||
funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function));
|
||||
|
||||
val = value_being_returned (value_type, stop_registers,
|
||||
using_struct_return (function,
|
||||
funcaddr,
|
||||
value_type));
|
||||
|
||||
printf ("Value returned is $%d = ", record_latest_value (val));
|
||||
value_print (val, stdout, 0);
|
||||
putchar ('\n');
|
||||
@ -506,7 +584,7 @@ program_info ()
|
||||
inferior_pid, stop_pc);
|
||||
if (stop_step)
|
||||
printf ("It stopped after being stepped.\n");
|
||||
else if (stop_breakpoint)
|
||||
else if (stop_breakpoint > 0)
|
||||
printf ("It stopped at breakpoint %d.\n", stop_breakpoint);
|
||||
else if (stop_signal)
|
||||
printf ("It stopped with signal %d (%s).\n",
|
||||
@ -540,30 +618,58 @@ set_environment_command (arg)
|
||||
char *arg;
|
||||
{
|
||||
register char *p, *val, *var;
|
||||
int nullset = 0;
|
||||
|
||||
if (arg == 0)
|
||||
error_no_arg ("environment variable and value");
|
||||
|
||||
/* Find seperation between variable name and value */
|
||||
p = (char *) index (arg, '=');
|
||||
val = (char *) index (arg, ' ');
|
||||
|
||||
if (p != 0 && val != 0)
|
||||
p = arg + min (p - arg, val - arg);
|
||||
{
|
||||
/* We have both a space and an equals. If the space is before the
|
||||
equals and the only thing between the two is more space, use
|
||||
the equals */
|
||||
if (p > val)
|
||||
while (*val == ' ')
|
||||
val++;
|
||||
|
||||
/* Take the smaller of the two. If there was space before the
|
||||
"=", they will be the same right now. */
|
||||
p = arg + min (p - arg, val - arg);
|
||||
}
|
||||
else if (val != 0 && p == 0)
|
||||
p = val;
|
||||
|
||||
if (p == 0)
|
||||
error ("Space or \"=\" must separate variable name and its value");
|
||||
if (p[1] == 0)
|
||||
error_no_arg ("value for the variable");
|
||||
if (p == arg)
|
||||
error_no_arg ("environment variable to set");
|
||||
|
||||
val = p + 1;
|
||||
while (*val == ' ' || *val == '\t') val++;
|
||||
if (p == 0 || p[1] == 0)
|
||||
{
|
||||
nullset = 1;
|
||||
if (p == 0)
|
||||
p = arg + strlen (arg); /* So that savestring below will work */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not setting variable value to null */
|
||||
val = p + 1;
|
||||
while (*val == ' ' || *val == '\t')
|
||||
val++;
|
||||
}
|
||||
|
||||
while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--;
|
||||
|
||||
var = savestring (arg, p - arg);
|
||||
set_in_environ (inferior_environ, var, val);
|
||||
if (nullset)
|
||||
{
|
||||
printf ("Setting environment variable \"%s\" to null value.\n", var);
|
||||
set_in_environ (inferior_environ, var, "");
|
||||
}
|
||||
else
|
||||
set_in_environ (inferior_environ, var, val);
|
||||
free (var);
|
||||
}
|
||||
|
||||
@ -579,6 +685,7 @@ unset_environment_command (var)
|
||||
|
||||
/* Read an integer from debugged memory, given address and number of bytes. */
|
||||
|
||||
long
|
||||
read_memory_integer (memaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
int len;
|
||||
@ -617,6 +724,7 @@ read_pc ()
|
||||
return (CORE_ADDR) read_register (PC_REGNUM);
|
||||
}
|
||||
|
||||
void
|
||||
write_pc (val)
|
||||
CORE_ADDR val;
|
||||
{
|
||||
@ -635,6 +743,9 @@ registers_info (addr_exp)
|
||||
register int i;
|
||||
int regnum;
|
||||
|
||||
if (!have_inferior_p () && !have_core_file_p ())
|
||||
error ("No inferior or core file");
|
||||
|
||||
if (addr_exp)
|
||||
{
|
||||
if (*addr_exp >= '0' && *addr_exp <= '9')
|
||||
@ -669,7 +780,7 @@ registers_info (addr_exp)
|
||||
{
|
||||
printf ("--Type Return to print more--");
|
||||
fflush (stdout);
|
||||
read_line ();
|
||||
gdb_read_line (0, 0);
|
||||
}
|
||||
|
||||
/* Get the data in raw format, then convert also to virtual format. */
|
||||
@ -681,7 +792,8 @@ registers_info (addr_exp)
|
||||
/* If virtual format is floating, print it that way. */
|
||||
if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT
|
||||
&& ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i)))
|
||||
val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, stdout, 0, 1);
|
||||
val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0,
|
||||
stdout, 0, 1);
|
||||
/* Else if virtual format is too long for printf,
|
||||
print in hex a byte at a time. */
|
||||
else if (REGISTER_VIRTUAL_SIZE (i) > sizeof (long))
|
||||
@ -824,16 +936,31 @@ detach_command (args, from_tty)
|
||||
inferior_pid = 0;
|
||||
}
|
||||
#endif /* ATTACH_DETACH */
|
||||
|
||||
/* ARGUSUED */
|
||||
static void
|
||||
float_info (addr_exp)
|
||||
char *addr_exp;
|
||||
{
|
||||
#ifdef FLOAT_INFO
|
||||
FLOAT_INFO;
|
||||
#else
|
||||
printf ("No floating point info available for this processor.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
initialize ()
|
||||
extern struct cmd_list_element *setlist, *deletelist;
|
||||
|
||||
void
|
||||
_initialize_infcmd ()
|
||||
{
|
||||
add_com ("tty", class_run, tty_command,
|
||||
"Set terminal for future runs of program being debugged.");
|
||||
|
||||
add_com ("set-args", class_run, set_args_command,
|
||||
add_cmd ("args", class_run, set_args_command,
|
||||
"Specify arguments to give program being debugged when it is started.\n\
|
||||
Follow this command with any number of args, to be passed to the program.");
|
||||
Follow this command with any number of args, to be passed to the program.",
|
||||
&setlist);
|
||||
|
||||
add_info ("environment", environment_info,
|
||||
"The environment to give the program, or one variable's value.\n\
|
||||
@ -841,14 +968,17 @@ With an argument VAR, prints the value of environment variable VAR to\n\
|
||||
give the program being debugged. With no arguments, prints the entire\n\
|
||||
environment to be given to the program.");
|
||||
|
||||
add_com ("unset-environment", class_run, unset_environment_command,
|
||||
add_cmd ("environment", class_run, unset_environment_command,
|
||||
"Cancel environment variable VAR for the program.\n\
|
||||
This does not affect the program until the next \"run\" command.");
|
||||
add_com ("set-environment", class_run, set_environment_command,
|
||||
This does not affect the program until the next \"run\" command.",
|
||||
&deletelist);
|
||||
|
||||
add_cmd ("environment", class_run, set_environment_command,
|
||||
"Set environment variable value to give the program.\n\
|
||||
Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\
|
||||
VALUES of environment variables are uninterpreted strings.\n\
|
||||
This does not affect the program until the next \"run\" command.");
|
||||
This does not affect the program until the next \"run\" command.",
|
||||
&setlist);
|
||||
|
||||
#ifdef ATTACH_DETACH
|
||||
add_com ("attach", class_run, attach_command,
|
||||
@ -892,6 +1022,12 @@ Argument N means do this N times (or till program stops for another reason).");
|
||||
Argument N means do this N times (or till program stops for another reason).");
|
||||
add_com_alias ("s", "step", class_run, 1);
|
||||
|
||||
add_com ("until", class_run, until_command,
|
||||
"Execute until the program reaches a source line greater than the current\n\
|
||||
or a specified line or address or function (same args as break command).\n\
|
||||
Execution will also stop upon exit from the current stack frame.");
|
||||
add_com_alias ("u", "until", class_run, 1);
|
||||
|
||||
add_com ("jump", class_run, jump_command,
|
||||
"Continue program being debugged at specified line or address.\n\
|
||||
Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\
|
||||
@ -919,9 +1055,11 @@ Register name as argument means describe only that register.");
|
||||
add_info ("program", program_info,
|
||||
"Execution status of the program.");
|
||||
|
||||
add_info ("float", float_info,
|
||||
"Print the status of the floating point unit\n");
|
||||
|
||||
inferior_args = savestring (" ", 1); /* By default, no args. */
|
||||
inferior_environ = make_environ ();
|
||||
init_environ (inferior_environ);
|
||||
}
|
||||
|
||||
END_FILE
|
||||
|
@ -19,6 +19,40 @@ In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Structure in which to save the status of the inferior. Save
|
||||
* through "save_inferior_status", restore through
|
||||
* "restore_inferior_status".
|
||||
* This pair of routines should be called around any transfer of
|
||||
* control to the inferior which you don't want showing up in your
|
||||
* control variables.
|
||||
*/
|
||||
struct inferior_status {
|
||||
int pc_changed;
|
||||
int stop_signal;
|
||||
int stop_pc;
|
||||
int stop_frame_address;
|
||||
int stop_breakpoint;
|
||||
int stop_step;
|
||||
int stop_stack_dummy;
|
||||
int stopped_by_random_signal;
|
||||
int trap_expected;
|
||||
CORE_ADDR step_range_start;
|
||||
CORE_ADDR step_range_end;
|
||||
FRAME_ADDR step_frame_address;
|
||||
int step_over_calls;
|
||||
CORE_ADDR step_resume_break_address;
|
||||
int stop_after_trap;
|
||||
int stop_after_attach;
|
||||
FRAME_ADDR selected_frame_address;
|
||||
int selected_level;
|
||||
struct command_line *breakpoint_commands;
|
||||
char stop_registers[REGISTER_BYTES];
|
||||
int restore_stack_info;
|
||||
};
|
||||
|
||||
void save_inferior_status (), restore_inferior_status ();
|
||||
|
||||
/* File name for default use for standard in/out in the inferior. */
|
||||
|
||||
extern char *inferior_io_terminal;
|
||||
@ -41,7 +75,7 @@ extern CORE_ADDR stop_pc;
|
||||
|
||||
/* Stack frame when program stopped. */
|
||||
|
||||
extern FRAME stop_frame;
|
||||
extern FRAME_ADDR stop_frame_address;
|
||||
|
||||
/* Number of breakpoint it stopped at, or 0 if none. */
|
||||
|
||||
@ -55,6 +89,11 @@ extern int stop_step;
|
||||
|
||||
extern int stop_stack_dummy;
|
||||
|
||||
/* Nonzero if program stopped due to a random (unexpected) signal in
|
||||
inferior process. */
|
||||
|
||||
extern int stopped_by_random_signal;
|
||||
|
||||
/* Range to single step within.
|
||||
If this is nonzero, respond to a single-step signal
|
||||
by continuing to step if the pc is in this range. */
|
||||
@ -66,7 +105,7 @@ extern CORE_ADDR step_range_end; /* Exclusive */
|
||||
This is how we know when we step into a subroutine call,
|
||||
and how to set the frame for the breakpoint used to step out. */
|
||||
|
||||
extern CORE_ADDR step_frame;
|
||||
extern FRAME_ADDR step_frame_address;
|
||||
|
||||
/* 1 means step over all subroutine calls.
|
||||
-1 means step over calls to undebuggable functions. */
|
||||
@ -87,3 +126,6 @@ extern char stop_registers[REGISTER_BYTES];
|
||||
since the inferior stopped. */
|
||||
|
||||
extern int pc_changed;
|
||||
|
||||
|
||||
long read_memory_integer ();
|
||||
|
691
gdb/inflow.c
691
gdb/inflow.c
@ -17,40 +17,20 @@ notice and this notice must be preserved on all copies.
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
#include "initialize.h"
|
||||
#include "param.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#ifndef UMAX_PTRACE
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef UMAX_PTRACE
|
||||
#include <a.out.h>
|
||||
#include <sys/ptrace.h>
|
||||
#define PTRACE_ATTACH PT_ATTACH
|
||||
#define PTRACE_DETACH PT_FREEPROC
|
||||
#endif
|
||||
|
||||
#ifdef NEW_SUN_PTRACE
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
#endif
|
||||
|
||||
#ifdef HP9K320
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/reg.h>
|
||||
#include <sys/trap.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
#include <termio.h>
|
||||
@ -62,34 +42,48 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
#define TIOCSETP TCSETAF
|
||||
#define TERMINAL struct termio
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <sgtty.h>
|
||||
#define TERMINAL struct sgttyb
|
||||
#endif
|
||||
|
||||
#ifdef SET_STACK_LIMIT_HUGE
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
extern int original_stack_limit;
|
||||
#endif /* SET_STACK_LIMIT_HUGE */
|
||||
|
||||
extern int errno;
|
||||
|
||||
/* Nonzero if we are debugging an attached outside process
|
||||
rather than an inferior. */
|
||||
|
||||
static int attach_flag;
|
||||
int attach_flag;
|
||||
|
||||
START_FILE
|
||||
|
||||
/* Record terminal status separately for debugger and inferior. */
|
||||
|
||||
static TERMINAL sg_inferior;
|
||||
static TERMINAL sg_ours;
|
||||
|
||||
static int tflags_inferior;
|
||||
static int tflags_ours;
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
#ifdef TIOCGETC
|
||||
static struct tchars tc_inferior;
|
||||
static struct tchars tc_ours;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
static struct ltchars ltc_inferior;
|
||||
static struct ltchars ltc_ours;
|
||||
#endif /* TIOCGLTC */
|
||||
|
||||
#ifdef TIOCLGET
|
||||
static int lmode_inferior;
|
||||
static int lmode_ours;
|
||||
#endif /* TIOCGLTC */
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
static int pgrp_inferior;
|
||||
@ -120,11 +114,17 @@ terminal_init_inferior ()
|
||||
sg_inferior = sg_ours;
|
||||
tflags_inferior = tflags_ours;
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
#ifdef TIOCGETC
|
||||
tc_inferior = tc_ours;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
ltc_inferior = ltc_ours;
|
||||
#endif
|
||||
|
||||
#ifdef TIOCLGET
|
||||
lmode_inferior = lmode_ours;
|
||||
#endif /* TIOCGLTC */
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
pgrp_inferior = inferior_pid;
|
||||
@ -147,18 +147,21 @@ terminal_inferior ()
|
||||
fcntl (0, F_SETFL, tflags_inferior);
|
||||
fcntl (0, F_SETFL, tflags_inferior);
|
||||
ioctl (0, TIOCSETN, &sg_inferior);
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
#ifdef TIOCGETC
|
||||
ioctl (0, TIOCSETC, &tc_inferior);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCSLTC, <c_inferior);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLSET, &lmode_inferior);
|
||||
#endif /* TIOCGLTC */
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
ioctl (0, TIOCSPGRP, &pgrp_inferior);
|
||||
#else
|
||||
sigint_ours = (signal (SIGINT, SIG_IGN));
|
||||
sigquit_ours = (signal (SIGQUIT, SIG_IGN));
|
||||
sigint_ours = (int (*) ()) signal (SIGINT, SIG_IGN);
|
||||
sigquit_ours = (int (*) ()) signal (SIGQUIT, SIG_IGN);
|
||||
#endif /* TIOCGPGRP */
|
||||
}
|
||||
terminal_is_ours = 0;
|
||||
@ -222,11 +225,15 @@ terminal_ours_1 (output_only)
|
||||
tflags_inferior = fcntl (0, F_GETFL, 0);
|
||||
ioctl (0, TIOCGETP, &sg_inferior);
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
#ifdef TIOCGETC
|
||||
ioctl (0, TIOCGETC, &tc_inferior);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCGLTC, <c_inferior);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLGET, &lmode_inferior);
|
||||
#endif /* TIOCGLTC */
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
@ -243,11 +250,15 @@ terminal_ours_1 (output_only)
|
||||
fcntl (0, F_SETFL, tflags_ours);
|
||||
ioctl (0, TIOCSETN, &sg_ours);
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
#ifdef TIOCGETC
|
||||
ioctl (0, TIOCSETC, &tc_ours);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCSLTC, <c_ours);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLSET, &lmode_ours);
|
||||
#endif /* TIOCGLTC */
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
@ -283,18 +294,29 @@ term_status_command ()
|
||||
|
||||
#else /* not HAVE_TERMIO */
|
||||
|
||||
printf ("fcntl flags = 0x%x, lmode = 0x%x,\nsgttyb.sg_flags = 0x%x, owner pid = %d.\n",
|
||||
tflags_inferior, lmode_inferior,
|
||||
sg_inferior.sg_flags, pgrp_inferior);
|
||||
printf ("fcntl flags = 0x%x, sgttyb.sg_flags = 0x%x, owner pid = %d.\n",
|
||||
tflags_inferior, sg_inferior.sg_flags, pgrp_inferior);
|
||||
|
||||
#endif /* not HAVE_TERMIO */
|
||||
|
||||
#ifdef TIOCGETC
|
||||
printf ("tchars: ");
|
||||
for (i = 0; i < sizeof (struct tchars); i++)
|
||||
printf ("0x%x ", ((char *)&tc_inferior)[i]);
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
printf ("ltchars: ");
|
||||
for (i = 0; i < sizeof (struct ltchars); i++)
|
||||
printf ("0x%x ", ((char *)<c_inferior)[i]);
|
||||
printf ("\n");
|
||||
ioctl (0, TIOCSLTC, <c_ours);
|
||||
#endif
|
||||
|
||||
#endif /* not HAVE_TERMIO */
|
||||
#ifdef TIOCLGET
|
||||
printf ("lmode: %x\n", lmode_inferior);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -304,11 +326,7 @@ new_tty (ttyname)
|
||||
register int tty;
|
||||
register int fd;
|
||||
|
||||
#if 0
|
||||
/* I think it is better not to do this. Then C-z on the GDB terminal
|
||||
will still stop the program, while C-z on the data terminal
|
||||
will be input. */
|
||||
|
||||
#ifdef TIOCNOTTY
|
||||
/* Disconnect the child process from our controlling terminal. */
|
||||
tty = open("/dev/tty", O_RDWR);
|
||||
if (tty > 0)
|
||||
@ -317,6 +335,7 @@ new_tty (ttyname)
|
||||
close(tty);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now open the specified new terminal. */
|
||||
|
||||
tty = open(ttyname, O_RDWR);
|
||||
@ -361,19 +380,29 @@ create_inferior (allargs, env)
|
||||
/* exec is said to fail if the executable is open. */
|
||||
close_exec_file ();
|
||||
|
||||
pid = vfork ();
|
||||
pid = fork ();
|
||||
if (pid < 0)
|
||||
perror_with_name ("vfork");
|
||||
perror_with_name ("fork");
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
char *args[4];
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
/* Run inferior in a separate process group. */
|
||||
setpgrp (getpid (), getpid ());
|
||||
#endif /* TIOCGPGRP */
|
||||
|
||||
#ifdef SET_STACK_LIMIT_HUGE
|
||||
/* Reset the stack limit back to what it was. */
|
||||
{
|
||||
struct rlimit rlim;
|
||||
|
||||
getrlimit (RLIMIT_STACK, &rlim);
|
||||
rlim.rlim_cur = original_stack_limit;
|
||||
setrlimit (RLIMIT_STACK, &rlim);
|
||||
}
|
||||
#endif /* SET_STACK_LIMIT_HUGE */
|
||||
|
||||
|
||||
inferior_thisrun_terminal = inferior_io_terminal;
|
||||
if (inferior_io_terminal != 0)
|
||||
new_tty (inferior_io_terminal);
|
||||
@ -383,14 +412,8 @@ create_inferior (allargs, env)
|
||||
/*??? signal (SIGQUIT, SIG_DFL);
|
||||
signal (SIGINT, SIG_DFL); */
|
||||
|
||||
ptrace (0);
|
||||
|
||||
args[0] = "sh";
|
||||
args[1] = "-c";
|
||||
args[2] = shell_command;
|
||||
args[3] = 0;
|
||||
|
||||
execve (SHELL_FILE, args, env);
|
||||
call_ptrace (0);
|
||||
execle (SHELL_FILE, "sh", "-c", shell_command, 0, env);
|
||||
|
||||
fprintf (stderr, "Cannot exec %s: %s.\n", SHELL_FILE,
|
||||
errno < sys_nerr ? sys_errlist[errno] : "unknown error");
|
||||
@ -414,538 +437,17 @@ kill_command ()
|
||||
kill_inferior ();
|
||||
}
|
||||
|
||||
kill_inferior ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
inferior_died ();
|
||||
}
|
||||
|
||||
/* This is used when GDB is exiting. It gives less chance of error.*/
|
||||
|
||||
kill_inferior_fast ()
|
||||
{
|
||||
if (remote_debugging)
|
||||
return;
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (8, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
}
|
||||
|
||||
void
|
||||
inferior_died ()
|
||||
{
|
||||
inferior_pid = 0;
|
||||
attach_flag = 0;
|
||||
mark_breakpoints_out ();
|
||||
select_frame ( (FRAME) 0, -1);
|
||||
reopen_exec_file ();
|
||||
if (have_core_file_p ())
|
||||
set_current_frame (read_register (FP_REGNUM));
|
||||
}
|
||||
|
||||
/* Resume execution of the inferior process.
|
||||
If STEP is nonzero, single-step it.
|
||||
If SIGNAL is nonzero, give it that signal. */
|
||||
|
||||
void
|
||||
resume (step, signal)
|
||||
int step;
|
||||
int signal;
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_resume (step, signal);
|
||||
else
|
||||
{
|
||||
#ifdef NO_SINGLE_STEP
|
||||
if (step)
|
||||
{
|
||||
single_step (signal);
|
||||
}
|
||||
else ptrace (7, inferior_pid, 1, signal);
|
||||
#else
|
||||
ptrace (step ? 9 : 7, inferior_pid, 1, signal);
|
||||
#endif
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ATTACH_DETACH
|
||||
|
||||
/* Start debugging the process whose number is PID. */
|
||||
|
||||
attach (pid)
|
||||
int pid;
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PTRACE_ATTACH, pid, 0, 0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
attach_flag = 1;
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* Stop debugging the process whose number is PID
|
||||
and continue it with signal number SIGNAL.
|
||||
SIGNAL = 0 means just continue it. */
|
||||
|
||||
void
|
||||
detach (signal)
|
||||
int signal;
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PTRACE_DETACH, inferior_pid, 1, signal);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
attach_flag = 0;
|
||||
}
|
||||
#endif /* ATTACH_DETACH */
|
||||
|
||||
#ifdef NEW_SUN_PTRACE
|
||||
|
||||
void
|
||||
fetch_inferior_registers ()
|
||||
{
|
||||
struct regs inferior_registers;
|
||||
struct fp_status inferior_fp_registers;
|
||||
extern char registers[];
|
||||
|
||||
if (remote_debugging)
|
||||
remote_fetch_registers (registers);
|
||||
else
|
||||
{
|
||||
ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers);
|
||||
ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers);
|
||||
|
||||
#if defined(sun2) || defined(sun3)
|
||||
bcopy (&inferior_registers, registers, 16 * 4);
|
||||
bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
sizeof inferior_fp_registers.fps_regs);
|
||||
*(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
|
||||
*(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
|
||||
bcopy (&inferior_fp_registers.fps_control,
|
||||
®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
|
||||
#endif
|
||||
#if defined(sun4)
|
||||
registers[REGISTER_BYTE (0)] = 0;
|
||||
bcopy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (1)], 15 * 4);
|
||||
bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
sizeof inferior_fp_registers.fpu_fr);
|
||||
*(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
|
||||
*(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
|
||||
*(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc;
|
||||
*(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y;
|
||||
/* *(int *)®isters[REGISTER_BYTE (RP_REGNUM)] =
|
||||
inferior_registers.r_o7 + 8;
|
||||
bcopy (&inferior_fp_registers.Fpu_fsr,
|
||||
®isters[REGISTER_BYTE (FPS_REGNUM)],
|
||||
sizeof (FPU_FSR_TYPE)); */
|
||||
read_inferior_memory (inferior_registers.r_sp,
|
||||
®isters[REGISTER_BYTE (16)],
|
||||
16*4);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
If REGNO is -1, do this for all registers.
|
||||
Otherwise, REGNO specifies which register (so we can save time). */
|
||||
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct regs inferior_registers;
|
||||
struct fp_status inferior_fp_registers;
|
||||
extern char registers[];
|
||||
|
||||
if (remote_debugging)
|
||||
remote_store_registers (registers);
|
||||
else
|
||||
{
|
||||
int in_regs = 1, in_fpregs = 1, in_fparegs, in_cpregs = 1;
|
||||
|
||||
#if defined(sun2) || defined(sun3)
|
||||
if (in_regs)
|
||||
{
|
||||
bcopy (registers, &inferior_registers, 16 * 4);
|
||||
inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)];
|
||||
inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)];
|
||||
}
|
||||
if (in_fpregs)
|
||||
{
|
||||
bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
|
||||
sizeof inferior_fp_registers.fps_regs);
|
||||
bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
&inferior_fp_registers.fps_control,
|
||||
sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
|
||||
}
|
||||
if (in_regs)
|
||||
ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers);
|
||||
if (in_fpregs)
|
||||
ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers);
|
||||
#endif
|
||||
#if defined(sun4)
|
||||
if (regno >= 0)
|
||||
if (FP0_REGNUM <= regno && regno <= FP0_REGNUM + 32)
|
||||
in_regs = 0;
|
||||
else
|
||||
in_fpregs = 0;
|
||||
|
||||
if (in_regs)
|
||||
{
|
||||
bcopy (®isters[REGISTER_BYTE (1)], &inferior_registers.r_g1, 15 * 4);
|
||||
inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)];
|
||||
inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)];
|
||||
inferior_registers.r_npc = *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)];
|
||||
inferior_registers.r_y = *(int *)®isters[REGISTER_BYTE (Y_REGNUM)];
|
||||
write_inferior_memory (*(int *)®isters[REGISTER_BYTE (SP_REGNUM)],
|
||||
®isters[REGISTER_BYTE (16)],
|
||||
16*4);
|
||||
}
|
||||
if (in_fpregs)
|
||||
{
|
||||
bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
|
||||
sizeof inferior_fp_registers.fpu_fr);
|
||||
/* bcopy (®isters[REGISTER_BYTE (FPS_REGNUM)],
|
||||
&inferior_fp_registers.Fpu_fsr,
|
||||
sizeof (FPU_FSR_TYPE));
|
||||
****/
|
||||
}
|
||||
|
||||
if (in_regs)
|
||||
ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers);
|
||||
if (in_fpregs)
|
||||
ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef HP9K320
|
||||
|
||||
#define FP_REGISTER_ADDR_DIFF(u, regno) \
|
||||
(((char *) (FP_REGISTER_ADDR (u, regno))) - ((char *) &(u)))
|
||||
|
||||
#define INFERIOR_AR0(u) \
|
||||
((ptrace \
|
||||
(PT_RUAREA, inferior_pid, ((char *) &u.u_ar0 - (char *) &u), 0)) \
|
||||
- KERNEL_U_ADDR)
|
||||
|
||||
static void
|
||||
fetch_inferior_register (regno, regaddr)
|
||||
register int regno;
|
||||
register unsigned int regaddr;
|
||||
{
|
||||
#ifndef HPUX_VERSION_5
|
||||
if (regno == PS_REGNUM)
|
||||
{
|
||||
union { int i; short s[2]; } ps_val;
|
||||
int regval;
|
||||
|
||||
ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0));
|
||||
regval = ps_val.s[0];
|
||||
supply_register (regno, ®val);
|
||||
}
|
||||
else
|
||||
#endif /* not HPUX_VERSION_5 */
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
*(int *) &buf[i] = ptrace (PT_RUAREA, inferior_pid, regaddr, 0);
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
store_inferior_register_1 (regno, regaddr, value)
|
||||
int regno;
|
||||
unsigned int regaddr;
|
||||
int value;
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WUAREA, inferior_pid, regaddr, value);
|
||||
#if 0
|
||||
/* HP-UX randomly sets errno to non-zero for regno == 25.
|
||||
However, the value is correctly written, so ignore errno. */
|
||||
if (errno != 0)
|
||||
{
|
||||
char string_buf[64];
|
||||
|
||||
sprintf (string_buf, "writing register number %d", regno);
|
||||
perror_with_name (string_buf);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
store_inferior_register (regno, regaddr)
|
||||
register int regno;
|
||||
register unsigned int regaddr;
|
||||
{
|
||||
#ifndef HPUX_VERSION_5
|
||||
if (regno == PS_REGNUM)
|
||||
{
|
||||
union { int i; short s[2]; } ps_val;
|
||||
|
||||
ps_val.i = (ptrace (PT_RUAREA, inferior_pid, regaddr, 0));
|
||||
ps_val.s[0] = (read_register (regno));
|
||||
store_inferior_register_1 (regno, regaddr, ps_val.i);
|
||||
}
|
||||
else
|
||||
#endif /* not HPUX_VERSION_5 */
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
extern char registers[];
|
||||
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
store_inferior_register_1
|
||||
(regno, regaddr,
|
||||
(*(int *) ®isters[(REGISTER_BYTE (regno)) + i]));
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers ()
|
||||
{
|
||||
struct user u;
|
||||
register int regno;
|
||||
register unsigned int ar0_offset;
|
||||
|
||||
ar0_offset = (INFERIOR_AR0 (u));
|
||||
for (regno = 0; (regno < FP0_REGNUM); regno++)
|
||||
fetch_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno)));
|
||||
for (; (regno < NUM_REGS); regno++)
|
||||
fetch_inferior_register (regno, (FP_REGISTER_ADDR_DIFF (u, regno)));
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
If REGNO is -1, do this for all registers.
|
||||
Otherwise, REGNO specifies which register (so we can save time). */
|
||||
|
||||
store_inferior_registers (regno)
|
||||
register int regno;
|
||||
{
|
||||
struct user u;
|
||||
register unsigned int ar0_offset;
|
||||
|
||||
if (regno >= FP0_REGNUM)
|
||||
{
|
||||
store_inferior_register (regno, (FP_REGISTER_ADDR_DIFF (u, regno)));
|
||||
return;
|
||||
}
|
||||
|
||||
ar0_offset = (INFERIOR_AR0 (u));
|
||||
if (regno >= 0)
|
||||
{
|
||||
store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno)));
|
||||
return;
|
||||
}
|
||||
|
||||
for (regno = 0; (regno < FP0_REGNUM); regno++)
|
||||
store_inferior_register (regno, (REGISTER_ADDR (ar0_offset, regno)));
|
||||
for (; (regno < NUM_REGS); regno++)
|
||||
store_inferior_register (regno, (FP_REGISTER_ADDR_DIFF (u, regno)));
|
||||
return;
|
||||
}
|
||||
|
||||
#else /* not HP9K320 */
|
||||
|
||||
void
|
||||
fetch_inferior_registers ()
|
||||
{
|
||||
register int regno;
|
||||
register unsigned int regaddr;
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
#ifdef UMAX_PTRACE
|
||||
unsigned int offset = 0;
|
||||
#else
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
|
||||
#endif
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
*(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
If REGNO is -1, do this for all registers.
|
||||
Otherwise, REGNO specifies which register (so we can save time). */
|
||||
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[80];
|
||||
extern char registers[];
|
||||
int i;
|
||||
|
||||
#ifdef UMAX_PTRACE
|
||||
unsigned int offset = 0;
|
||||
#else
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
|
||||
#endif
|
||||
|
||||
if (regno >= 0)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (6, inferior_pid, regaddr,
|
||||
*(int *) ®isters[REGISTER_BYTE (regno) + i]);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d(%d)", regno, i);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
regaddr += sizeof(int);
|
||||
}
|
||||
}
|
||||
else for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (6, inferior_pid, regaddr,
|
||||
*(int *) ®isters[REGISTER_BYTE (regno) + i]);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d(%d)", regno, i);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
regaddr += sizeof(int);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* not HP9K320 */
|
||||
#endif /* not NEW_SUN_PTRACE */
|
||||
|
||||
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
|
||||
in the NEW_SUN_PTRACE case.
|
||||
It ought to be straightforward. But it appears that writing did
|
||||
not write the data that I specified. I cannot understand where
|
||||
it got the data that it actually did write. */
|
||||
|
||||
/* Copy LEN bytes from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR. */
|
||||
|
||||
read_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
if (remote_debugging)
|
||||
buffer[i] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[i] = ptrace (1, inferior_pid, addr, 0);
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
}
|
||||
|
||||
/* Copy LEN bytes of data from debugger memory at MYADDR
|
||||
to inferior's memory at MEMADDR.
|
||||
On failure (cannot write the inferior)
|
||||
returns the value of errno. */
|
||||
|
||||
int
|
||||
write_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
extern int errno;
|
||||
|
||||
/* Fill start and end extra bytes of buffer with existing memory data. */
|
||||
|
||||
if (remote_debugging)
|
||||
buffer[0] = remote_fetch_word (addr);
|
||||
else
|
||||
buffer[0] = ptrace (1, inferior_pid, addr, 0);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
if (remote_debugging)
|
||||
buffer[count - 1]
|
||||
= remote_fetch_word (addr + (count - 1) * sizeof (int));
|
||||
else
|
||||
buffer[count - 1]
|
||||
= ptrace (1, inferior_pid,
|
||||
addr + (count - 1) * sizeof (int), 0);
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
if (remote_debugging)
|
||||
remote_store_word (addr, buffer[i]);
|
||||
else
|
||||
ptrace (4, inferior_pid, addr, buffer[i]);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
|
||||
read_pc ()));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -962,8 +464,8 @@ try_writing_regs_command ()
|
||||
{
|
||||
QUIT;
|
||||
errno = 0;
|
||||
value = ptrace (3, inferior_pid, i, 0);
|
||||
ptrace (6, inferior_pid, i, value);
|
||||
value = call_ptrace (3, inferior_pid, i, 0);
|
||||
call_ptrace (6, inferior_pid, i, value);
|
||||
if (errno == 0)
|
||||
{
|
||||
printf (" Succeeded with address 0x%x; value 0x%x (%d).\n",
|
||||
@ -974,8 +476,8 @@ try_writing_regs_command ()
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
initialize ()
|
||||
void
|
||||
_initialize_inflow ()
|
||||
{
|
||||
add_com ("term-status", class_obscure, term_status_command,
|
||||
"Print info on inferior's saved terminal status.");
|
||||
@ -992,11 +494,15 @@ Report which ones can be written.");
|
||||
ioctl (0, TIOCGETP, &sg_ours);
|
||||
fcntl (0, F_GETFL, tflags_ours);
|
||||
|
||||
#ifdef TIOCGLTC
|
||||
#ifdef TIOCGETC
|
||||
ioctl (0, TIOCGETC, &tc_ours);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCGLTC, <c_ours);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLGET, &lmode_ours);
|
||||
#endif /* TIOCGLTC */
|
||||
#endif
|
||||
|
||||
#ifdef TIOCGPGRP
|
||||
ioctl (0, TIOCGPGRP, &pgrp_ours);
|
||||
@ -1005,4 +511,3 @@ Report which ones can be written.");
|
||||
terminal_is_ours = 1;
|
||||
}
|
||||
|
||||
END_FILE
|
||||
|
1016
gdb/infrun.c
1016
gdb/infrun.c
File diff suppressed because it is too large
Load Diff
134
gdb/initialize.h
134
gdb/initialize.h
@ -1,134 +0,0 @@
|
||||
/* Macros to enable automatic execution of an initialization function
|
||||
in each object file without having to include a list of all object files
|
||||
anywhere in the source code. This goes with firstfile.c and lastfile.c.
|
||||
|
||||
Copyright (C) 1986 Free Software Foundation, Inc.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
|
||||
NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
|
||||
WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
|
||||
RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
|
||||
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
||||
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
|
||||
AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
|
||||
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
|
||||
CORRECTION.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
|
||||
STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
|
||||
WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
|
||||
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
|
||||
OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
|
||||
DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
|
||||
A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
|
||||
PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
|
||||
|
||||
GENERAL PUBLIC LICENSE TO COPY
|
||||
|
||||
1. You may copy and distribute verbatim copies of this source file
|
||||
as you receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy a valid copyright notice "Copyright
|
||||
(C) 1986 Free Software Foundation, Inc."; and include following the
|
||||
copyright notice a verbatim copy of the above disclaimer of warranty
|
||||
and of this License. You may charge a distribution fee for the
|
||||
physical act of transferring a copy.
|
||||
|
||||
2. You may modify your copy or copies of this source file or
|
||||
any portion of it, and copy and distribute such modifications under
|
||||
the terms of Paragraph 1 above, provided that you also do the following:
|
||||
|
||||
a) cause the modified files to carry prominent notices stating
|
||||
that you changed the files and the date of any change; and
|
||||
|
||||
b) cause the whole of any work that you distribute or publish,
|
||||
that in whole or in part contains or is a derivative of this
|
||||
program or any part thereof, to be licensed at no charge to all
|
||||
third parties on terms identical to those contained in this
|
||||
License Agreement (except that you may choose to grant more extensive
|
||||
warranty protection to some or all third parties, at your option).
|
||||
|
||||
c) You may charge a distribution fee for the physical act of
|
||||
transferring a copy, and you may at your option offer warranty
|
||||
protection in exchange for a fee.
|
||||
|
||||
Mere aggregation of another unrelated program with this program (or its
|
||||
derivative) on a volume of a storage or distribution medium does not bring
|
||||
the other program under the scope of these terms.
|
||||
|
||||
3. You may copy and distribute this program (or a portion or derivative
|
||||
of it, under Paragraph 2) in object code or executable form under the terms
|
||||
of Paragraphs 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of
|
||||
Paragraphs 1 and 2 above; or,
|
||||
|
||||
b) accompany it with a written offer, valid for at least three
|
||||
years, to give any third party free (except for a nominal
|
||||
shipping charge) a complete machine-readable copy of the
|
||||
corresponding source code, to be distributed under the terms of
|
||||
Paragraphs 1 and 2 above; or,
|
||||
|
||||
c) accompany it with the information you received as to where the
|
||||
corresponding source code may be obtained. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form alone.)
|
||||
|
||||
For an executable file, complete source code means all the source code for
|
||||
all modules it contains; but, as a special exception, it need not include
|
||||
source code for modules which are standard libraries that accompany the
|
||||
operating system on which the executable file runs.
|
||||
|
||||
4. You may not copy, sublicense, distribute or transfer this program
|
||||
except as expressly provided under this License Agreement. Any attempt
|
||||
otherwise to copy, sublicense, distribute or transfer this program is void and
|
||||
your rights to use the program under this License agreement shall be
|
||||
automatically terminated. However, parties who have received computer
|
||||
software programs from you with this License Agreement will not have
|
||||
their licenses terminated so long as such parties remain in full compliance.
|
||||
|
||||
5. If you wish to incorporate parts of this program into other free
|
||||
programs whose distribution conditions are different, write to the Free
|
||||
Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
|
||||
worked out a simple rule that can be stated here, but we will often permit
|
||||
this. We will be guided by the two goals of preserving the free status of
|
||||
all derivatives of our free software and of promoting the sharing and reuse of
|
||||
software.
|
||||
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
|
||||
/* Here a machine-specific header file must be included to define
|
||||
the macro FILEADDR_ROUND which we use to round up from the address
|
||||
of the end of one object file's text to the start of the next
|
||||
object file's text. */
|
||||
|
||||
#include "m-init.h"
|
||||
|
||||
/* This is used to make a file's initialization function.
|
||||
It calls another function named `initialize', which must
|
||||
appear later in the file. */
|
||||
|
||||
#define START_FILE \
|
||||
static initialize (), initialize_next_file (); \
|
||||
static initialize_1 (offset) \
|
||||
{ initialize (); initialize_next_file (offset); }
|
||||
|
||||
/* The argument OFFSET is the size of this function.
|
||||
By adding it to the address of this function,
|
||||
we find the next function, which is the next file's
|
||||
initialization function. */
|
||||
|
||||
#define END_FILE \
|
||||
static initialize_next_file (offset) \
|
||||
int offset; \
|
||||
{ long addr = FILEADDR_ROUND ((int) initialize_next_file + offset); \
|
||||
(*(void (*) ()) addr) (offset); }
|
@ -1,6 +0,0 @@
|
||||
/* This ends the chain of files for the purpose of initialization,
|
||||
because it does not attempt to find the start of the following file. */
|
||||
|
||||
initialize_last_file ()
|
||||
{
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* Parameters for execution on a Sun, for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
/* Parameters for execution on A/UX, for GDB, the GNU debugger.
|
||||
Copyright (C) 1989 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
@ -18,32 +18,36 @@ In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Configuration file for HP9000/300 series machine running
|
||||
* University of Utah's 4.3bsd port. This is NOT for HP-UX.
|
||||
* Problems to hpbsd-bugs@cs.utah.edu
|
||||
*/
|
||||
|
||||
#ifndef hp300
|
||||
#define hp300
|
||||
#ifndef aux
|
||||
#define aux
|
||||
#endif
|
||||
|
||||
/* Watch out for NaNs */
|
||||
/* It's a USG system */
|
||||
#define USG
|
||||
|
||||
#define IEEE_FLOAT
|
||||
/* Assembler instructions in USG "SGS" (sw generation system) format */
|
||||
#define USG_SGS_ASM
|
||||
|
||||
/* Get rid of any system-imposed stack limit if possible. */
|
||||
/* Debugger information will be in COFF format. */
|
||||
#define COFF_FORMAT
|
||||
#define COFF_NO_LONG_FILE_NAMES
|
||||
|
||||
#define SET_STACK_LIMIT_HUGE
|
||||
/* Terminal interface via termio */
|
||||
#define HAVE_TERMIO
|
||||
|
||||
/* Define this if the C compiler puts an underscore at the front
|
||||
of external names before giving them to the linker. */
|
||||
/* Unisoft fucked up the include files */
|
||||
#define UNISOFT_ASSHOLES
|
||||
|
||||
#define NAMES_HAVE_UNDERSCORE
|
||||
/* Big or Little-Endian target machine
|
||||
BITS: defined if bit #0 is the high-order bit of a byte.
|
||||
BYTES:defined if byte#0 is the high-order byte of an int.
|
||||
WORDS:defined if word#0 is the high-order word of a double. */
|
||||
#define BITS_BIG_ENDIAN
|
||||
#define BYTES_BIG_ENDIAN
|
||||
#define WORDS_BIG_ENDIAN
|
||||
|
||||
/* Debugger information will be in DBX format. */
|
||||
|
||||
#define READ_DBX_FORMAT
|
||||
/* Floating point is IEEE compatible */
|
||||
#define IEEE_FLOAT
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
Zero on most machines. */
|
||||
@ -69,36 +73,40 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
#define SAVED_PC_AFTER_CALL(frame) \
|
||||
read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
/* This is the amount to subtract from u.u_ar0
|
||||
to get the offset in the core file of the register values. */
|
||||
|
||||
#define KERNEL_U_ADDR 0x00917000
|
||||
|
||||
/* Address of end of stack space. */
|
||||
|
||||
#define STACK_END_ADDR 0xFFF00000
|
||||
#define STACK_END_ADDR 0x20000000
|
||||
|
||||
/* Stack grows downward. */
|
||||
|
||||
#define INNER_THAN <
|
||||
|
||||
/* Sequence of bytes for breakpoint instruction. */
|
||||
/* A/UX uses "trap &1" */
|
||||
|
||||
#define BREAKPOINT {0x4e, 0x42}
|
||||
#define BREAKPOINT {0x4e, 0x41}
|
||||
|
||||
/* Amount PC must be decremented by after a breakpoint.
|
||||
This is often the number of bytes in BREAKPOINT
|
||||
but not always. */
|
||||
|
||||
#define DECR_PC_AFTER_BREAK 2
|
||||
#define DECR_PC_AFTER_BREAK 0
|
||||
|
||||
/* Nonzero if instruction at PC is a return instruction. */
|
||||
|
||||
#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75)
|
||||
|
||||
/* Return 1 if P points to an invalid floating point value. */
|
||||
/* FIXME, it's not clear what "invalid" means here. I take it to mean
|
||||
"something that coredumps gdb if gdb tries to manipulate it" */
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
#define INVALID_FLOAT(p, len) is_nan(p, len)
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
@ -113,7 +121,7 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#define REGISTER_NAMES \
|
||||
{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \
|
||||
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \
|
||||
"a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \
|
||||
"ps", "pc", \
|
||||
"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \
|
||||
"fpcontrol", "fpstatus", "fpiaddr" }
|
||||
@ -131,11 +139,31 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
#define PC_REGNUM 17 /* Contains program counter */
|
||||
#define FP0_REGNUM 18 /* Floating point register 0 */
|
||||
#define FPC_REGNUM 26 /* 68881 control register */
|
||||
#define FPS_REGNUM 27 /* 68881 status register */
|
||||
|
||||
/* This is a piece of magic that is given a register number REGNO
|
||||
and as BLOCKEND the address in the system of the end of the user structure
|
||||
and stores in ADDR the address in the kernel or core dump
|
||||
of that register. */
|
||||
|
||||
#define REGISTER_U_ADDR(addr, blockend, regno) { \
|
||||
struct user u; \
|
||||
if (regno <= SP_REGNUM) \
|
||||
addr = blockend + regno * 4; \
|
||||
else if (regno == PS_REGNUM) \
|
||||
addr = blockend + RPS * 4; /* From reg.h */ \
|
||||
else if (regno == PC_REGNUM) \
|
||||
addr = blockend + PC * 4; /* From reg.h */ \
|
||||
else if (regno < FPC_REGNUM) \
|
||||
addr = (char *) u.u_fpdreg [regno-FP0_REGNUM] - (char *)&u; \
|
||||
else \
|
||||
addr = (char *)&u.u_fpsysreg[regno-FPC_REGNUM] - (char *)&u; \
|
||||
}
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
/* Total amount of space needed to store our copies of the machine's
|
||||
register state, the array `registers'. */
|
||||
#define REGISTER_BYTES (16*4+8*12+8+12)
|
||||
#define REGISTER_BYTES (16*4+8*12+8+20)
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
@ -148,6 +176,8 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. On the 68000, all regs are 4 bytes
|
||||
except the floating point regs which are 12 bytes. */
|
||||
/* Note that the unsigned cast here forces the result of the
|
||||
subtractiion to very high positive values if N < FP0_REGNUM */
|
||||
|
||||
#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4)
|
||||
|
||||
@ -194,6 +224,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
(((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (9, (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
@ -213,37 +249,6 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
|
||||
|
||||
/* Compensate for lack of `vprintf' function. */
|
||||
#define vprintf(format, ap) _doprnt (format, ap, stdout)
|
||||
|
||||
/* This is a piece of magic that is given a register number REGNO
|
||||
and as BLOCKEND the address in the system of the end of the user structure
|
||||
and stores in ADDR the address in the kernel or core dump
|
||||
of that register. */
|
||||
|
||||
#define REGISTER_U_ADDR(addr, blockend, regno) \
|
||||
{ \
|
||||
if (regno < PS_REGNUM) \
|
||||
addr = (int) &((struct frame *)(blockend))->f_regs[regno]; \
|
||||
else if (regno == PS_REGNUM) \
|
||||
addr = (int) &((struct frame *)(blockend))->f_stackadj; \
|
||||
else if (regno == PC_REGNUM) \
|
||||
addr = (int) &((struct frame *)(blockend))->f_pc; \
|
||||
else if (regno < FPC_REGNUM) \
|
||||
addr = (int) \
|
||||
&((struct user *)0)->u_pcb.pcb_fpregs.fpf_regs[((regno)-FP0_REGNUM)*3];\
|
||||
else if (regno == FPC_REGNUM) \
|
||||
addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpcr; \
|
||||
else if (regno == FPS_REGNUM) \
|
||||
addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpsr; \
|
||||
else \
|
||||
addr = (int) &((struct user *)0)->u_pcb.pcb_fpregs.fpf_fpiar; \
|
||||
}
|
||||
|
||||
/* It is safe to look for symsegs on a Sun, because Sun's ld
|
||||
does not screw up with random garbage at end of file. */
|
||||
|
||||
#define READ_GDB_SYMSEGS
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
@ -258,23 +263,23 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
it means the given frame is the outermost one and has no caller.
|
||||
In that case, FRAME_CHAIN_COMBINE is not used. */
|
||||
|
||||
/* In the case of the Sun, the frame's nominal address
|
||||
/* In the case of the 68k, the frame's nominal address
|
||||
is the address of a 4-byte word containing the calling frame's address. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4))
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end))
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4))
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
@ -285,7 +290,7 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#if 0
|
||||
#define FRAME_NUM_ARGS(val, fi) \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
|
||||
register int insn = 0177777 & read_memory_integer (pc, 2); \
|
||||
val = 0; \
|
||||
if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
|
||||
@ -315,19 +320,19 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
register CORE_ADDR pc; \
|
||||
int nextinsn; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info).pc <= (frame_info).frame) \
|
||||
{ next_addr = (frame_info).frame; \
|
||||
pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info)->pc <= (frame_info)->frame) \
|
||||
{ next_addr = (frame_info)->frame; \
|
||||
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
else \
|
||||
{ pc = get_pc_function_start ((frame_info).pc); \
|
||||
{ pc = get_pc_function_start ((frame_info)->pc); \
|
||||
/* Verify we have a link a6 instruction next; \
|
||||
if not we lose. If we win, find the address above the saved \
|
||||
regs using the amount of storage from the link instruction. */\
|
||||
if (044016 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
else if (047126 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
else goto lose; \
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */ \
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
|
||||
@ -354,7 +359,7 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \
|
||||
else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) \
|
||||
{ regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
/* fmovemx to index of sp may follow. */ \
|
||||
@ -371,9 +376,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
if (0x426742e7 == read_memory_integer (pc, 4)) \
|
||||
(frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
|
||||
lose: ; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
@ -399,13 +404,15 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
restoring all saved registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[12]; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
{ read_memory (fsr.regs[regnum], raw_buffer, 12); \
|
||||
@ -418,7 +425,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
set_current_frame (read_register (FP_REGNUM)); }
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
fmovem 0xff,-(sp)
|
||||
@ -431,7 +440,7 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
the following jsr instruction. *../
|
||||
jsr @#32323232
|
||||
addl #69696969,sp
|
||||
trap #2
|
||||
trap #15
|
||||
nop
|
||||
Note this is 28 bytes.
|
||||
We actually start executing at the jsr, since the pushing of the
|
||||
@ -442,7 +451,7 @@ But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done,
|
||||
and we cannot allow the moveml to push the registers again lest they be
|
||||
taken for the arguments. */
|
||||
|
||||
#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e424e71}
|
||||
#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71}
|
||||
|
||||
#define CALL_DUMMY_LENGTH 28
|
||||
|
||||
@ -451,7 +460,7 @@ taken for the arguments. */
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
@ -25,15 +25,18 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
/* Set flag to indicate whether HP's assembler is in use. */
|
||||
#ifdef __GNU__
|
||||
#ifdef __HPUX_ASM__
|
||||
#define HPUX_ASM
|
||||
#define USG_SGS_ASM
|
||||
#endif
|
||||
#else
|
||||
#define HPUX_ASM
|
||||
#define USG_SGS_ASM
|
||||
#endif
|
||||
|
||||
/* Define this for versions of hp-ux older than 6.0 */
|
||||
/* #define HPUX_VERSION_5 */
|
||||
|
||||
/* define USG if you are using sys5 /usr/include's */
|
||||
#define USG
|
||||
|
||||
#define HAVE_TERMIO
|
||||
|
||||
/* Get rid of any system-imposed stack limit if possible. */
|
||||
@ -108,6 +111,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
@ -201,6 +210,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
(((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (9, (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
@ -228,9 +243,11 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
: (&((struct exception_stack *) (u_ar0))->e_PC)))
|
||||
|
||||
#define FP_REGISTER_ADDR(u, regno) \
|
||||
(((regno) < FPC_REGNUM) \
|
||||
? (&u.u_pcb.pcb_mc68881[FMC68881_R0 + (((regno) - FP0_REGNUM) * 3)]) \
|
||||
: (&u.u_pcb.pcb_mc68881[FMC68881_C + ((regno) - FPC_REGNUM)]))
|
||||
(((char *) \
|
||||
(((regno) < FPC_REGNUM) \
|
||||
? (&u.u_pcb.pcb_mc68881[FMC68881_R0 + (((regno) - FP0_REGNUM) * 3)]) \
|
||||
: (&u.u_pcb.pcb_mc68881[FMC68881_C + ((regno) - FPC_REGNUM)]))) \
|
||||
- ((char *) (& u)))
|
||||
|
||||
/* It is safe to look for symsegs on a Sun, because Sun's ld
|
||||
does not screw up with random garbage at end of file. */
|
||||
@ -253,20 +270,20 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
/* In the case of the Sun, the frame's nominal address
|
||||
is the address of a 4-byte word containing the calling frame's address. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4))
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end))
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4))
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
@ -277,7 +294,7 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#if 0
|
||||
#define FRAME_NUM_ARGS(val, fi) \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
|
||||
register int insn = 0177777 & read_memory_integer (pc, 2); \
|
||||
val = 0; \
|
||||
if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
|
||||
@ -307,19 +324,19 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
register CORE_ADDR pc; \
|
||||
int nextinsn; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info).pc <= (frame_info).frame) \
|
||||
{ next_addr = (frame_info).frame; \
|
||||
pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info)->pc <= (frame_info)->frame) \
|
||||
{ next_addr = (frame_info)->frame; \
|
||||
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
else \
|
||||
{ pc = get_pc_function_start ((frame_info).pc); \
|
||||
{ pc = get_pc_function_start ((frame_info)->pc); \
|
||||
/* Verify we have a link a6 instruction next; \
|
||||
if not we lose. If we win, find the address above the saved \
|
||||
regs using the amount of storage from the link instruction. */\
|
||||
if (044016 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
else if (047126 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
else goto lose; \
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */ \
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
|
||||
@ -363,9 +380,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
if (0x426742e7 == read_memory_integer (pc, 4)) \
|
||||
(frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
|
||||
lose: ; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
@ -391,13 +408,15 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
restoring all saved registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[12]; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
{ read_memory (fsr.regs[regnum], raw_buffer, 12); \
|
||||
@ -410,7 +429,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
set_current_frame (read_register (FP_REGNUM)); }
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ()));}
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
fmovem 0xff,-(sp)
|
||||
@ -443,7 +464,7 @@ taken for the arguments. */
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
||||
|
394
gdb/m-i386.h
Normal file
394
gdb/m-i386.h
Normal file
@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu)
|
||||
* July 1988
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#ifndef i386
|
||||
#define i386
|
||||
#endif
|
||||
|
||||
/* define USG if you are using sys5 /usr/include's */
|
||||
#define USG
|
||||
|
||||
/* USG systems need these */
|
||||
#define vfork() fork()
|
||||
#define MAXPATHLEN 500
|
||||
|
||||
/* define this if you don't have the extension to coff that allows
|
||||
* file names to appear in the string table
|
||||
* (aux.x_file.x_foff)
|
||||
*/
|
||||
#define COFF_NO_LONG_FILE_NAMES
|
||||
|
||||
/* turn this on when rest of gdb is ready */
|
||||
/* #define IEEE_FLOAT */
|
||||
|
||||
#define NBPG NBPC
|
||||
#define UPAGES USIZE
|
||||
|
||||
#define HAVE_TERMIO
|
||||
|
||||
/* Get rid of any system-imposed stack limit if possible. */
|
||||
|
||||
/* #define SET_STACK_LIMIT_HUGE not in sys5 */
|
||||
|
||||
/* Define this if the C compiler puts an underscore at the front
|
||||
of external names before giving them to the linker. */
|
||||
|
||||
/* #define NAMES_HAVE_UNDERSCORE */
|
||||
|
||||
/* Specify debugger information format. */
|
||||
|
||||
/* #define READ_DBX_FORMAT */
|
||||
#define COFF_FORMAT
|
||||
|
||||
/* number of traps that happen between exec'ing the shell
|
||||
* to run an inferior, and when we finally get to
|
||||
* the inferior code. This is 2 on most implementations.
|
||||
*/
|
||||
#define START_INFERIOR_TRAPS_EXPECTED 4
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
Zero on most machines. */
|
||||
|
||||
#define FUNCTION_START_OFFSET 0
|
||||
|
||||
/* Advance PC across any function entry prologue instructions
|
||||
to reach some "real" code. */
|
||||
|
||||
#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));}
|
||||
|
||||
/* Immediately after a function call, return the saved pc.
|
||||
Can't always go through the frames for this because on some machines
|
||||
the new frame is not set up until the new function executes
|
||||
some instructions. */
|
||||
|
||||
#define SAVED_PC_AFTER_CALL(frame) \
|
||||
(read_memory_integer (read_register (SP_REGNUM), 4))
|
||||
|
||||
/* This is the amount to subtract from u.u_ar0
|
||||
to get the offset in the core file of the register values. */
|
||||
|
||||
#define KERNEL_U_ADDR 0xe0000000
|
||||
|
||||
/* Address of end of stack space. */
|
||||
|
||||
#define STACK_END_ADDR 0x80000000
|
||||
|
||||
/* Stack grows downward. */
|
||||
|
||||
#define INNER_THAN <
|
||||
|
||||
/* Sequence of bytes for breakpoint instruction. */
|
||||
|
||||
#define BREAKPOINT {0xcc}
|
||||
|
||||
/* Amount PC must be decremented by after a breakpoint.
|
||||
This is often the number of bytes in BREAKPOINT
|
||||
but not always. */
|
||||
|
||||
#define DECR_PC_AFTER_BREAK 1
|
||||
|
||||
/* Nonzero if instruction at PC is a return instruction. */
|
||||
|
||||
#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc3)
|
||||
|
||||
/* Return 1 if P points to an invalid floating point value.
|
||||
LEN is the length in bytes -- not relevant on the 386. */
|
||||
|
||||
#define INVALID_FLOAT(p, len) (0)
|
||||
|
||||
/* code to execute to print interesting information about the
|
||||
* floating point processor (if any)
|
||||
* No need to define if there is nothing to do.
|
||||
*/
|
||||
#define FLOAT_INFO { i386_float_info (); }
|
||||
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
|
||||
/* Number of machine registers */
|
||||
|
||||
#define NUM_REGS 16
|
||||
|
||||
/* Initializer for an array of names of registers.
|
||||
There should be NUM_REGS strings in this initializer. */
|
||||
|
||||
/* the order of the first 8 registers must match the compiler's
|
||||
* numbering scheme (which is the same as the 386 scheme)
|
||||
* also, this table must match regmap in i386-pinsn.c.
|
||||
*/
|
||||
#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \
|
||||
"esp", "ebp", "esi", "edi", \
|
||||
"eip", "ps", "cs", "ss", \
|
||||
"ds", "es", "fs", "gs", \
|
||||
}
|
||||
|
||||
/* Register numbers of various important registers.
|
||||
Note that some of these values are "real" register numbers,
|
||||
and correspond to the general registers of the machine,
|
||||
and some are "phony" register numbers which are too large
|
||||
to be actual register numbers as far as the user is concerned
|
||||
but do serve to get the desired values when passed to read_register. */
|
||||
|
||||
#define FP_REGNUM 5 /* Contains address of executing stack frame */
|
||||
#define SP_REGNUM 4 /* Contains address of top of stack */
|
||||
|
||||
#define PC_REGNUM 8
|
||||
#define PS_REGNUM 9
|
||||
|
||||
#define REGISTER_U_ADDR(addr, blockend, regno) \
|
||||
(addr) = i386_register_u_addr ((blockend),(regno));
|
||||
|
||||
/* Total amount of space needed to store our copies of the machine's
|
||||
register state, the array `registers'. */
|
||||
#define REGISTER_BYTES (NUM_REGS * 4)
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
|
||||
#define REGISTER_BYTE(N) ((N)*4)
|
||||
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. */
|
||||
|
||||
#define REGISTER_RAW_SIZE(N) (4)
|
||||
|
||||
/* Number of bytes of storage in the program's representation
|
||||
for register N. */
|
||||
|
||||
#define REGISTER_VIRTUAL_SIZE(N) (4)
|
||||
|
||||
/* Largest value REGISTER_RAW_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_RAW_SIZE 4
|
||||
|
||||
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_VIRTUAL_SIZE 4
|
||||
|
||||
/* Nonzero if register N requires conversion
|
||||
from raw format to virtual format. */
|
||||
|
||||
#define REGISTER_CONVERTIBLE(N) (0)
|
||||
|
||||
/* Convert data from raw format for register REGNUM
|
||||
to virtual format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);}
|
||||
|
||||
/* Convert data from virtual format for register REGNUM
|
||||
to raw format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);}
|
||||
|
||||
/* Return the GDB type object for the "standard" data type
|
||||
of data in register N. */
|
||||
|
||||
#define REGISTER_VIRTUAL_TYPE(N) (builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ (SP) -= sizeof (ADDR); \
|
||||
write_memory ((SP), &(ADDR), sizeof (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Write into appropriate registers a function return value
|
||||
of type TYPE, given in virtual format. */
|
||||
|
||||
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
|
||||
write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
the address in which a function should return its structure value,
|
||||
as a CORE_ADDR (or an expression that can be used as one). */
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
|
||||
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
|
||||
/* FRAME_CHAIN takes a frame's nominal address
|
||||
and produces the frame's chain-pointer.
|
||||
|
||||
FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
|
||||
and produces the nominal address of the caller frame.
|
||||
|
||||
However, if FRAME_CHAIN_VALID returns zero,
|
||||
it means the given frame is the outermost one and has no caller.
|
||||
In that case, FRAME_CHAIN_COMBINE is not used. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Return number of args passed to a frame.
|
||||
Can return -1, meaning no way to tell. */
|
||||
|
||||
/* on the 386, the instruction following the call could be:
|
||||
* popl %ecx - one arg
|
||||
* addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits
|
||||
* anything else - zero args
|
||||
*/
|
||||
#define FRAME_NUM_ARGS(numargs, fi) { \
|
||||
int retpc; \
|
||||
unsigned char op; \
|
||||
struct frame_info *pfi; \
|
||||
pfi = get_prev_frame_info ((fi)); \
|
||||
retpc = pfi->pc; \
|
||||
numargs = 0; \
|
||||
op = read_memory_integer (retpc, 1); \
|
||||
if (op == 0x59) \
|
||||
/* pop %ecx */ \
|
||||
(numargs) = 1; \
|
||||
else if (op == 0x83) { \
|
||||
op = read_memory_integer (retpc+1, 1); \
|
||||
if (op == 0xc4) \
|
||||
/* addl $<signed imm 8 bits>, %esp */ \
|
||||
(numargs) = (read_memory_integer (retpc+2,1)&0xff)/4;\
|
||||
} else if (op == 0x81) { /* add with 32 bit immediate */\
|
||||
op = read_memory_integer (retpc+1, 1); \
|
||||
if (op == 0xc4) \
|
||||
/* addl $<imm 32>, %esp */ \
|
||||
(numargs) = read_memory_integer (retpc+2, 4) / 4;\
|
||||
} \
|
||||
}
|
||||
|
||||
/* Return number of bytes at start of arglist that are not really args. */
|
||||
|
||||
#define FRAME_ARGS_SKIP 8
|
||||
|
||||
/* Put here the code to store, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame. */
|
||||
|
||||
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
|
||||
{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); }
|
||||
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
#define PUSH_DUMMY_FRAME { i386_push_dummy_frame (); }
|
||||
|
||||
/* Discard from the stack the innermost frame, restoring all registers. */
|
||||
|
||||
#define POP_FRAME { i386_pop_frame (); }
|
||||
|
||||
/* this is
|
||||
* call 11223344 (32 bit relative)
|
||||
* int3
|
||||
*/
|
||||
|
||||
#define CALL_DUMMY { 0x223344e8, 0xcc11 }
|
||||
|
||||
#define CALL_DUMMY_LENGTH 8
|
||||
|
||||
#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */
|
||||
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ \
|
||||
int from, to, delta, loc; \
|
||||
loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \
|
||||
from = loc + 5; \
|
||||
to = (int)(fun); \
|
||||
delta = to - from; \
|
||||
*(int *)((char *)(dummyname) + 1) = delta; \
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* Interface definitions for kernel debugger KDB. */
|
||||
|
||||
/* Map machine fault codes into signal numbers.
|
||||
First subtract 0, divide by 4, then index in a table.
|
||||
Faults for which the entry in this table is 0
|
||||
are not handled by KDB; the program's own trap handler
|
||||
gets to handle then. */
|
||||
|
||||
#define FAULT_CODE_ORIGIN 0
|
||||
#define FAULT_CODE_UNITS 4
|
||||
#define FAULT_TABLE \
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
/* Start running with a stack stretching from BEG to END.
|
||||
BEG and END should be symbols meaningful to the assembler.
|
||||
This is used only for kdb. */
|
||||
|
||||
#define INIT_STACK(beg, end) {}
|
||||
|
||||
/* Push the frame pointer register on the stack. */
|
||||
#define PUSH_FRAME_PTR {}
|
||||
|
||||
/* Copy the top-of-stack to the frame pointer register. */
|
||||
#define POP_FRAME_PTR {}
|
||||
|
||||
/* After KDB is entered by a fault, push all registers
|
||||
that GDB thinks about (all NUM_REGS of them),
|
||||
so that they appear in order of ascending GDB register number.
|
||||
The fault code will be on the stack beyond the last register. */
|
||||
|
||||
#define PUSH_REGISTERS {}
|
||||
|
||||
/* Assuming the registers (including processor status) have been
|
||||
pushed on the stack in order of ascending GDB register number,
|
||||
restore them and return to the address in the saved PC register. */
|
||||
|
||||
#define POP_REGISTERS {}
|
||||
#endif
|
37
gdb/m-i386gas.h
Normal file
37
gdb/m-i386gas.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu)
|
||||
* July 1988
|
||||
*
|
||||
* i386gnu: COFF_ENCAPSULATE
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
#define COFF_ENCAPSULATE
|
||||
|
||||
#include "m-i386.h"
|
||||
|
||||
|
||||
#define NAMES_HAVE_UNDERSCORE
|
||||
|
||||
#undef COFF_FORMAT
|
||||
#define READ_DBX_FORMAT
|
||||
|
@ -1,5 +0,0 @@
|
||||
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on a sun. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) ((addr + 7) & -8)
|
549
gdb/m-isi.h
Normal file
549
gdb/m-isi.h
Normal file
@ -0,0 +1,549 @@
|
||||
/*
|
||||
Date: Thu, 2 Apr 87 00:02:42 EST
|
||||
From: crl@maxwell.physics.purdue.edu (Charles R. LaBrec)
|
||||
Message-Id: <8704020502.AA01744@maxwell.physics.purdue.edu>
|
||||
To: bug-gdb@prep.ai.mit.edu
|
||||
Subject: gdb for ISI Optimum V
|
||||
|
||||
Here is an m-isi-ov.h file for gdb version 2.1. It supports the 68881
|
||||
registers, and tracks down the function prologue (since the ISI cc
|
||||
puts it at the end of the function and branches to it if not
|
||||
optimizing). Also included are diffs to core.c, findvar.c, and
|
||||
inflow.c, since the original code assumed that registers are an int in
|
||||
the user struct, which isn't the case for 68020's with 68881's (and
|
||||
not using the NEW_SUN_PTRACE). I have not fixed the bugs associated
|
||||
with the other direction (writing registers back to the user struct).
|
||||
I have also included a diff that turns m68k-pinsn.c into isi-pinsn.c,
|
||||
which is needed since the 3.05 release of as does not understand
|
||||
floating point ops, and it compiles incorrectly under "cc -20"
|
||||
|
||||
I have used gdb for a while now, and it seems to work relatively well,
|
||||
but I do not guarantee that it is perfect. The more that use it, the
|
||||
faster the bugs will get shaken out. One bug I know of is not in gdb,
|
||||
but in the assembler. It seems to screw up the .stabs of variables.
|
||||
For externs, this is not important since gdb uses the global symbol
|
||||
value, but for statics, this makes gdb unable to find them. I am
|
||||
currently trying to track it down.
|
||||
|
||||
As an aside, I notice that only global functions are used as symbols
|
||||
to print as relative addresses, i.e. "<function + offset>", and not
|
||||
static functions, which end up printing as large offsets from the last
|
||||
global one. Would there be a problem if static functions were also
|
||||
recorded as misc functions in read_dbx_symtab?
|
||||
|
||||
Charles LaBrec
|
||||
crl @ maxwell.physics.purdue.edu
|
||||
|
||||
Definitions to make GDB run on a ISI Optimum V (3.05) under 4.2bsd.
|
||||
|
||||
Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
|
||||
/* Identify this machine */
|
||||
#ifndef ISI68K
|
||||
#define ISI68K
|
||||
#endif
|
||||
|
||||
/* Define this if the C compiler puts an underscore at the front
|
||||
of external names before giving them to the linker. */
|
||||
|
||||
#define NAMES_HAVE_UNDERSCORE
|
||||
|
||||
/* Debugger information will be in DBX format. */
|
||||
|
||||
#define READ_DBX_FORMAT
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
Zero on most machines. */
|
||||
|
||||
#define FUNCTION_START_OFFSET 0
|
||||
|
||||
/* Advance PC across any function entry prologue instructions
|
||||
to reach some "real" code. */
|
||||
|
||||
#define SKIP_PROLOGUE(pc) \
|
||||
{ register int op = read_memory_integer (pc, 2); \
|
||||
if (op == 0047126) \
|
||||
pc += 4; /* Skip link #word */ \
|
||||
else if (op == 0044016) \
|
||||
pc += 6; /* Skip link #long */ \
|
||||
else if (op == 0060000) \
|
||||
pc += 4; /* Skip bra #word */ \
|
||||
else if (op == 00600377) \
|
||||
pc += 6; /* skip bra #long */ \
|
||||
else if ((op & 0177400) == 0060000) \
|
||||
pc += 2; /* skip bra #char */ \
|
||||
}
|
||||
|
||||
|
||||
/* Immediately after a function call, return the saved pc.
|
||||
Can't always go through the frames for this because on some machines
|
||||
the new frame is not set up until the new function executes
|
||||
some instructions. */
|
||||
|
||||
#define SAVED_PC_AFTER_CALL(frame) \
|
||||
read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
/* This is the amount to subtract from u.u_ar0
|
||||
to get the offset in the core file of the register values. */
|
||||
|
||||
#define KERNEL_U_ADDR 0x10800000
|
||||
|
||||
/* Address of end of stack space. */
|
||||
|
||||
#define STACK_END_ADDR 0x10000000
|
||||
|
||||
/* Stack grows downward. */
|
||||
|
||||
#define INNER_THAN <
|
||||
|
||||
/* Sequence of bytes for breakpoint instruction. */
|
||||
|
||||
#define BREAKPOINT {0x4e, 0x4f}
|
||||
|
||||
/* Data segment starts at etext rounded up to DATAROUND in {N,Z}MAGIC files */
|
||||
|
||||
#define DATAROUND 0x20000
|
||||
#define N_DATADDR(hdr) (hdr.a_magic != OMAGIC ? \
|
||||
(hdr.a_text + DATAROUND) & ~(DATAROUND-1) : hdr.a_text)
|
||||
|
||||
/* Text segment starts at sizeof (struct exec) in {N,Z}MAGIC files */
|
||||
|
||||
#define N_TXTADDR(hdr) (hdr.a_magic != OMAGIC ? sizeof (struct exec) : 0)
|
||||
|
||||
/* Amount PC must be decremented by after a breakpoint.
|
||||
This is often the number of bytes in BREAKPOINT
|
||||
but not always.
|
||||
On the ISI, the kernel resets the pc to the trap instr */
|
||||
|
||||
#define DECR_PC_AFTER_BREAK 0
|
||||
|
||||
/* Nonzero if instruction at PC is a return instruction. */
|
||||
|
||||
#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e75)
|
||||
|
||||
/* Return 1 if P points to an invalid floating point value. */
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
|
||||
/* Number of machine registers */
|
||||
|
||||
#define NUM_REGS 29
|
||||
|
||||
/* Initializer for an array of names of registers.
|
||||
There should be NUM_REGS strings in this initializer. */
|
||||
|
||||
#define REGISTER_NAMES \
|
||||
{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \
|
||||
"a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \
|
||||
"ps", "pc", \
|
||||
"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \
|
||||
"fpcontrol", "fpstatus", "fpiaddr" }
|
||||
|
||||
/* Register numbers of various important registers.
|
||||
Note that some of these values are "real" register numbers,
|
||||
and correspond to the general registers of the machine,
|
||||
and some are "phony" register numbers which are too large
|
||||
to be actual register numbers as far as the user is concerned
|
||||
but do serve to get the desired values when passed to read_register. */
|
||||
|
||||
#define FP_REGNUM 14 /* Contains address of executing stack frame */
|
||||
#define SP_REGNUM 15 /* Contains address of top of stack */
|
||||
#define PS_REGNUM 16 /* Contains processor status */
|
||||
#define PC_REGNUM 17 /* Contains program counter */
|
||||
#define FP0_REGNUM 18 /* Floating point register 0 */
|
||||
#define FPC_REGNUM 26 /* 68881 control register */
|
||||
|
||||
#ifdef BSD43_ISI40D
|
||||
#define BLOCKFUDGE 0x400000
|
||||
#else
|
||||
#define BLOCKFUDGE 0
|
||||
#endif
|
||||
#define REGISTER_U_ADDR(addr, blockend, regno) \
|
||||
{ blockend -= BLOCKFUDGE; \
|
||||
if (regno < 2) addr = blockend - 0x18 + regno * 4; \
|
||||
else if (regno < 8) addr = blockend - 0x54 + regno * 4; \
|
||||
else if (regno < 10) addr = blockend - 0x30 + regno * 4;\
|
||||
else if (regno < 15) addr = blockend - 0x5c + regno * 4;\
|
||||
else if (regno < 16) addr = blockend - 0x1c; \
|
||||
else if (regno < 18) addr = blockend - 0x44 + regno * 4;\
|
||||
else if (regno < 26) addr = (int) ((struct user *)0)->u_68881_regs \
|
||||
+ (regno - 18) * 12; \
|
||||
else if (regno < 29) addr = (int) ((struct user *)0)->u_68881_regs \
|
||||
+ 8 * 12 + (regno - 26) * 4; \
|
||||
}
|
||||
|
||||
/* Total amount of space needed to store our copies of the machine's
|
||||
register state, the array `registers'. */
|
||||
#define REGISTER_BYTES (16*4+8*12+8+20)
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
|
||||
#define REGISTER_BYTE(N) \
|
||||
((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \
|
||||
: (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \
|
||||
: (N) * 4)
|
||||
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. On the 68000, all regs are 4 bytes
|
||||
except the floating point regs which are 12 bytes. */
|
||||
|
||||
#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4)
|
||||
|
||||
/* Number of bytes of storage in the program's representation
|
||||
for register N. On the 68000, all regs are 4 bytes
|
||||
except the floating point regs which are 8-byte doubles. */
|
||||
|
||||
#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4)
|
||||
|
||||
/* Largest value REGISTER_RAW_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_RAW_SIZE 12
|
||||
|
||||
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_VIRTUAL_SIZE 8
|
||||
|
||||
/* Nonzero if register N requires conversion
|
||||
from raw format to virtual format. */
|
||||
|
||||
#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8)
|
||||
|
||||
/* Convert data from raw format for register REGNUM
|
||||
to virtual format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
|
||||
{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
|
||||
convert_from_68881 ((FROM), (TO)); \
|
||||
else \
|
||||
bcopy ((FROM), (TO), 4); }
|
||||
|
||||
/* Convert data from virtual format for register REGNUM
|
||||
to raw format for register REGNUM. */
|
||||
|
||||
#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
|
||||
{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \
|
||||
convert_to_68881 ((FROM), (TO)); \
|
||||
else \
|
||||
bcopy ((FROM), (TO), 4); }
|
||||
|
||||
/* Return the GDB type object for the "standard" data type
|
||||
of data in register N. */
|
||||
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
(((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (9, (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Write into appropriate registers a function return value
|
||||
of type TYPE, given in virtual format. */
|
||||
|
||||
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
|
||||
write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
the address in which a function should return its structure value,
|
||||
as a CORE_ADDR (or an expression that can be used as one). */
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
|
||||
/* FRAME_CHAIN takes a frame's nominal address
|
||||
and produces the frame's chain-pointer.
|
||||
|
||||
FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
|
||||
and produces the nominal address of the caller frame.
|
||||
|
||||
However, if FRAME_CHAIN_VALID returns zero,
|
||||
it means the given frame is the outermost one and has no caller.
|
||||
In that case, FRAME_CHAIN_COMBINE is not used. */
|
||||
|
||||
/* In the case of the ISI, the frame's nominal address
|
||||
is the address of a 4-byte word containing the calling frame's address. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Return number of args passed to a frame.
|
||||
Can return -1, meaning no way to tell. */
|
||||
|
||||
#define FRAME_NUM_ARGS(val, fi) \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
|
||||
register int insn = 0177777 & read_memory_integer (pc, 2); \
|
||||
val = 0; \
|
||||
if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
|
||||
val = read_memory_integer (pc + 2, 2); \
|
||||
else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \
|
||||
|| (insn & 0170777) == 0050117) /* addqw */ \
|
||||
{ val = (insn >> 9) & 7; if (val == 0) val = 8; } \
|
||||
else if (insn == 0157774) /* addal #WW, sp */ \
|
||||
val = read_memory_integer (pc + 2, 4); \
|
||||
val >>= 2; }
|
||||
|
||||
/* Return number of bytes at start of arglist that are not really args. */
|
||||
|
||||
#define FRAME_ARGS_SKIP 8
|
||||
|
||||
/* Put here the code to store, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame. */
|
||||
|
||||
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
|
||||
{ register int regnum; \
|
||||
register int regmask; \
|
||||
register CORE_ADDR next_addr; \
|
||||
register CORE_ADDR pc; \
|
||||
register int insn; \
|
||||
register int offset; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info)->pc <= (frame_info)->frame) \
|
||||
{ next_addr = (frame_info)->frame; \
|
||||
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
else \
|
||||
{ pc = get_pc_function_start ((frame_info)->pc); \
|
||||
/* Verify we have a link a6 instruction next, \
|
||||
or a branch followed by a link a6 instruction; \
|
||||
if not we lose. If we win, find the address above the saved \
|
||||
regs using the amount of storage from the link instruction. */\
|
||||
retry: \
|
||||
insn = read_memory_integer (pc, 2); \
|
||||
if (insn == 044016) \
|
||||
next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
else if (insn == 047126) \
|
||||
next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
else if ((insn & 0177400) == 060000) /* bra insn */ \
|
||||
{ offset = insn & 0377; \
|
||||
pc += 2; /* advance past bra */ \
|
||||
if (offset == 0) /* bra #word */ \
|
||||
offset = read_memory_integer (pc, 2), pc += 2; \
|
||||
else if (offset == 0377) /* bra #long */ \
|
||||
offset = read_memory_integer (pc, 4), pc += 4; \
|
||||
pc += offset; \
|
||||
goto retry; \
|
||||
} else goto lose; \
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */ \
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
|
||||
next_addr += read_memory_integer (pc += 2, 4), pc += 4; \
|
||||
} \
|
||||
/* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \
|
||||
insn = read_memory_integer (pc, 2), pc += 2; \
|
||||
regmask = read_memory_integer (pc, 2); \
|
||||
if ((insn & 0177760) == 022700) /* movl rn, (sp) */ \
|
||||
(frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr; \
|
||||
else if ((insn & 0177760) == 024700) /* movl rn, -(sp) */ \
|
||||
(frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr-=4; \
|
||||
else if (insn == 0044327) /* moveml mask, (sp) */ \
|
||||
{ pc += 2; \
|
||||
/* Regmask's low bit is for register 0, the first written */ \
|
||||
next_addr -= 4; \
|
||||
for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr += 4); \
|
||||
} else if (insn == 0044347) /* moveml mask, -(sp) */ \
|
||||
{ pc += 2; \
|
||||
/* Regmask's low bit is for register 15, the first pushed */ \
|
||||
for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
/* clrw -(sp); movw ccr,-(sp) may follow. */ \
|
||||
if (read_memory_integer (pc, 2) == 041147 \
|
||||
&& read_memory_integer (pc+2, 2) == 042347) \
|
||||
(frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
|
||||
lose: ; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
}
|
||||
|
||||
/* Compensate for lack of `vprintf' function. */
|
||||
#define vprintf(format, ap) _doprnt (format, ap, stdout)
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
#define PUSH_DUMMY_FRAME \
|
||||
{ register CORE_ADDR sp = read_register (SP_REGNUM); \
|
||||
register int regnum; \
|
||||
char raw_buffer[12]; \
|
||||
sp = push_word (sp, read_register (PC_REGNUM)); \
|
||||
sp = push_word (sp, read_register (FP_REGNUM)); \
|
||||
write_register (FP_REGNUM, sp); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
{ read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \
|
||||
sp = push_bytes (sp, raw_buffer, 12); } \
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
sp = push_word (sp, read_register (regnum)); \
|
||||
sp = push_word (sp, read_register (PS_REGNUM)); \
|
||||
write_register (SP_REGNUM, sp); }
|
||||
|
||||
/* Discard from the stack the innermost frame, restoring all registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[12]; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
{ read_memory (fsr.regs[regnum], raw_buffer, 12); \
|
||||
write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
if (fsr.regs[PS_REGNUM]) \
|
||||
write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
flush_cached_frames (); \
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM), \
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
fmovem #<f0-f7>,-(sp)
|
||||
moveml 0xfffc,-(sp)
|
||||
clrw -(sp)
|
||||
movew ccr,-(sp)
|
||||
/..* The arguments are pushed at this point by GDB;
|
||||
no code is needed in the dummy for this.
|
||||
The CALL_DUMMY_START_OFFSET gives the position of
|
||||
the following jsr instruction. *../
|
||||
jsr @#32323232
|
||||
addl #69696969,sp
|
||||
bpt
|
||||
nop
|
||||
Note this is 24 bytes.
|
||||
We actually start executing at the jsr, since the pushing of the
|
||||
registers is done by PUSH_DUMMY_FRAME. If this were real code,
|
||||
the arguments for the function called by the jsr would be pushed
|
||||
between the moveml and the jsr, and we could allow it to execute through.
|
||||
But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done,
|
||||
and we cannot allow the moveml to push the registers again lest they be
|
||||
taken for the arguments. */
|
||||
|
||||
#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71}
|
||||
|
||||
#define CALL_DUMMY_LENGTH 28
|
||||
|
||||
#define CALL_DUMMY_START_OFFSET 12
|
||||
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
||||
/* Interface definitions for kernel debugger KDB. */
|
||||
|
||||
/* Map machine fault codes into signal numbers.
|
||||
First subtract 0, divide by 4, then index in a table.
|
||||
Faults for which the entry in this table is 0
|
||||
are not handled by KDB; the program's own trap handler
|
||||
gets to handle then. */
|
||||
|
||||
#define FAULT_CODE_ORIGIN 0
|
||||
#define FAULT_CODE_UNITS 4
|
||||
#define FAULT_TABLE \
|
||||
{ 0, 0, 0, 0, SIGTRAP, 0, 0, 0, \
|
||||
0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
SIGILL }
|
||||
|
||||
/* Start running with a stack stretching from BEG to END.
|
||||
BEG and END should be symbols meaningful to the assembler.
|
||||
This is used only for kdb. */
|
||||
|
||||
#define INIT_STACK(beg, end) \
|
||||
{ asm (".globl end"); \
|
||||
asm ("movl $ end, sp"); \
|
||||
asm ("clrl fp"); }
|
||||
|
||||
/* Push the frame pointer register on the stack. */
|
||||
#define PUSH_FRAME_PTR \
|
||||
asm ("movel fp, -(sp)");
|
||||
|
||||
/* Copy the top-of-stack to the frame pointer register. */
|
||||
#define POP_FRAME_PTR \
|
||||
asm ("movl (sp), fp");
|
||||
|
||||
/* After KDB is entered by a fault, push all registers
|
||||
that GDB thinks about (all NUM_REGS of them),
|
||||
so that they appear in order of ascending GDB register number.
|
||||
The fault code will be on the stack beyond the last register. */
|
||||
|
||||
#define PUSH_REGISTERS \
|
||||
{ asm ("clrw -(sp)"); \
|
||||
asm ("pea 10(sp)"); \
|
||||
asm ("movem $ 0xfffe,-(sp)"); }
|
||||
|
||||
/* Assuming the registers (including processor status) have been
|
||||
pushed on the stack in order of ascending GDB register number,
|
||||
restore them and return to the address in the saved PC register. */
|
||||
|
||||
#define POP_REGISTERS \
|
||||
{ asm ("subil $8,28(sp)"); \
|
||||
asm ("movem (sp),$ 0xffff"); \
|
||||
asm ("rte"); }
|
@ -1,11 +0,0 @@
|
||||
/* Customize initialize.h for Integrated Solutions machines. */
|
||||
|
||||
/* Define this if you are using system version 4; undefine it for
|
||||
version 3. This alters the action of m-isi-ov.h as well as this file. */
|
||||
#define BSD43_ISI40D
|
||||
|
||||
#ifdef BSD43_ISI40D
|
||||
#define FILEADDR_ROUND(addr) (addr)
|
||||
#else
|
||||
#define FILEADDR_ROUND(addr) ((addr + 3) & -4)
|
||||
#endif
|
@ -94,6 +94,12 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
#define NS32K_SVC_IMMED_OPERANDS
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
@ -216,6 +222,14 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
: builtin_type_float) \
|
||||
: builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function.
|
||||
|
||||
On this machine this is a no-op, as gcc doesn't run on it yet.
|
||||
This calling convention is not used. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP)
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
@ -251,21 +265,21 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
/* In the case of the Merlin, the frame's nominal address is the FP value,
|
||||
and at that address is saved previous FP value as a 4-byte word. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4))
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end))
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4))
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
/* compute base of arguments */
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi).frame)
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Return number of args passed to a frame.
|
||||
Can return -1, meaning no way to tell. */
|
||||
@ -276,7 +290,7 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
int addr_mode; \
|
||||
int width; \
|
||||
\
|
||||
pc = FRAME_SAVED_PC (fi.frame,0); \
|
||||
pc = FRAME_SAVED_PC (fi); \
|
||||
insn = read_memory_integer (pc,2); \
|
||||
addr_mode = (insn >> 11) & 0x1f; \
|
||||
insn = insn & 0x7ff; \
|
||||
@ -311,17 +325,17 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
CORE_ADDR enter_addr; \
|
||||
CORE_ADDR next_addr; \
|
||||
\
|
||||
enter_addr = get_pc_function_start ((frame_info).pc); \
|
||||
enter_addr = get_pc_function_start ((frame_info)->pc); \
|
||||
regmask = read_memory_integer (enter_addr+1, 1); \
|
||||
localcount = ns32k_localcount (enter_addr); \
|
||||
next_addr = (frame_info).frame + localcount; \
|
||||
next_addr = (frame_info)->frame + localcount; \
|
||||
for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \
|
||||
(frame_saved_regs).regs[regnum] \
|
||||
= (regmask & 1) ? (next_addr -= 4) : 0; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 4; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 4; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] \
|
||||
= read_memory_integer ((frame_info).frame, 4); }
|
||||
= read_memory_integer ((frame_info)->frame, 4); }
|
||||
|
||||
/* Compensate for lack of `vprintf' function. */
|
||||
#define vprintf(format, ap) _doprnt (format, ap, stdout)
|
||||
@ -344,18 +358,23 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
/* Discard from the stack the innermost frame, restoring all registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
struct frame_info *fi; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = 0; regnum < 8; regnum++) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ()));
|
||||
}
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
@ -375,7 +394,7 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ int flipped = fun | 0xc0000000; \
|
||||
flip_bytes (&flipped, 4); \
|
||||
*((int *) (((char *) dummyname)+CALL_DUMMY_ADDR)) = flipped; \
|
||||
|
133
gdb/m-news.h
133
gdb/m-news.h
@ -1,14 +1,17 @@
|
||||
/* Parameters for execution on a Sony/NEWS, for GDB, the GNU debugger.
|
||||
Probably ths parameters is match as news800, news700 and news900.
|
||||
|
||||
Here is an m-news800.h file for gdb version 2.1. It supports the reading
|
||||
the 68881 registers, but the kernel doesn't know how to write them
|
||||
and probably cannot write the frame pointer register either.
|
||||
Here is an m-news800.h file for gdb version 2.6. It supports the 68881
|
||||
registers.
|
||||
|
||||
Now(9/2 '87) NEWS's printf has a bug.
|
||||
And support Sun assembly format instead of Motorola one.
|
||||
Probably not well support floating registers from core file rarely that
|
||||
(hikichi@srava.sra.junet or hikichi%srava.sra.junet%kddlabs@uunet.uu.net
|
||||
and now hikichi@wheaties.ai.mit.edu)
|
||||
* Now(9/2 '87) NEWS's printf has a bug.
|
||||
* And support Sun assembly format instead of Motorola one.
|
||||
* Probably not well support floating registers from core file rarely that
|
||||
I do not know detail.
|
||||
(hikichi@srava.sra.junet or hikichi%srava.sra.junet%kddlabs%seismo.CSS.GOV)
|
||||
* Ptrace for handling floating register has a bug(7/3 '87), but not fixed
|
||||
yet. We cannot write floating register.
|
||||
|
||||
Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
@ -34,6 +37,7 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
#define news800
|
||||
#endif
|
||||
|
||||
/* Use GNU assembler instead of standard assembler */
|
||||
#define USE_GAS
|
||||
|
||||
/* Motorola assembly format */
|
||||
@ -41,16 +45,12 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
#define MOTOROLA
|
||||
#endif
|
||||
|
||||
/* bug when printf special number; NAN */
|
||||
#define PRINTF_BUG
|
||||
|
||||
/* Define this if the C compiler puts an underscore at the front
|
||||
of external names before giving them to the linker. */
|
||||
|
||||
#define NAMES_HAVE_UNDERSCORE
|
||||
|
||||
/* Debugger info will be in DBX format. */
|
||||
|
||||
/* Symbols on this machine are in DBX format. */
|
||||
#define READ_DBX_FORMAT
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
@ -109,6 +109,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
@ -215,27 +221,24 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
(((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (9, (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
{ if (TYPE_CODE (TYPE) != TYPE_CODE_FLT) \
|
||||
bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)); \
|
||||
else \
|
||||
convert_from_68881 (REGBUF + REGISTER_BYTE (FP0_REGNUM), VALBUF); }
|
||||
bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Write into appropriate registers a function return value
|
||||
of type TYPE, given in virtual format. */
|
||||
|
||||
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
|
||||
{ if (TYPE_CODE (TYPE) != TYPE_CODE_FLT) \
|
||||
write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)); \
|
||||
else \
|
||||
{ \
|
||||
char raw_buffer[12]; \
|
||||
convert_to_68881 (VALBUF, raw_buffer); \
|
||||
write_register_bytes (REGISTER_BYTE(FP0_REGNUM), raw_buffer, 12); }}
|
||||
write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
the address in which a function should return its structure value,
|
||||
@ -262,26 +265,26 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
/* In the case of the NEWS, the frame's nominal address
|
||||
is the address of a 4-byte word containing the calling frame's address. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4))
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end))
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4))
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Return number of args passed to a frame.
|
||||
Can return -1, meaning no way to tell. */
|
||||
|
||||
#define FRAME_NUM_ARGS(val, fi) \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
|
||||
register int insn = 0177777 & read_memory_integer (pc, 2); \
|
||||
val = 0; \
|
||||
if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
|
||||
@ -311,12 +314,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
register int insn; \
|
||||
register int offset; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info).pc <= (frame_info).frame) \
|
||||
{ next_addr = (frame_info).frame; \
|
||||
pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info)->pc <= (frame_info)->frame) \
|
||||
{ next_addr = (frame_info)->frame; \
|
||||
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
else \
|
||||
{ pc = get_pc_function_start ((frame_info).pc); \
|
||||
{ pc = get_pc_function_start ((frame_info)->pc); \
|
||||
/* Verify we have a link a6 instruction next, \
|
||||
or a branch followed by a link a6 instruction; \
|
||||
if not we lose. If we win, find the address above the saved \
|
||||
@ -324,9 +327,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
retry: \
|
||||
insn = read_memory_integer (pc, 2); \
|
||||
if (insn == 044016) \
|
||||
next_addr = (frame_info).frame - read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
else if (insn == 047126) \
|
||||
next_addr = (frame_info).frame - read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
else if ((insn & 0177400) == 060000) /* bra insn */ \
|
||||
{ offset = insn & 0377; \
|
||||
pc += 2; /* advance past bra */ \
|
||||
@ -366,15 +369,15 @@ retry: \
|
||||
&& read_memory_integer (pc+2, 2) == 042347) \
|
||||
(frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
|
||||
lose: ; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
#if 0 /* now these define is not used */
|
||||
#define PUSH_DUMMY_FRAME \
|
||||
{ register CORE_ADDR sp = read_register (SP_REGNUM); \
|
||||
register int regnum; \
|
||||
@ -393,13 +396,15 @@ retry: \
|
||||
/* Discard from the stack the innermost frame, restoring all registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[12]; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
{ read_memory (fsr.regs[regnum], raw_buffer, 12); \
|
||||
@ -412,8 +417,44 @@ retry: \
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
}
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM), \
|
||||
read_pc ())); }
|
||||
#else /* now ptrace has a bug to write floating register */
|
||||
#define PUSH_DUMMY_FRAME \
|
||||
{ register CORE_ADDR sp = read_register (SP_REGNUM); \
|
||||
register int regnum; \
|
||||
sp = push_word (sp, read_register (PC_REGNUM)); \
|
||||
sp = push_word (sp, read_register (FP_REGNUM)); \
|
||||
write_register (FP_REGNUM, sp); \
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
sp = push_word (sp, read_register (regnum)); \
|
||||
sp = push_word (sp, read_register (PS_REGNUM)); \
|
||||
write_register (SP_REGNUM, sp); }
|
||||
|
||||
/* Discard from the stack the innermost frame, restoring all registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info *fi; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
if (fsr.regs[PS_REGNUM]) \
|
||||
write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM), \
|
||||
read_pc ())); }
|
||||
#endif
|
||||
/* This sequence of words is the instructions
|
||||
fmove.m #<f0-f7>,-(sp)
|
||||
movem.l 0xfffc,-(sp)
|
||||
@ -445,7 +486,7 @@ taken for the arguments. */
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on a SONY NEWS. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) ((addr + 3) & -4)
|
58
gdb/m-npl.h
58
gdb/m-npl.h
@ -17,8 +17,8 @@ notice and this notice must be preserved on all copies.
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
|
||||
/* Read file headers properly in core.c */
|
||||
#define gould
|
||||
/* This code appears in libraries on Gould machines. Ignore it. */
|
||||
#define IGNORE_SYMBOL(type) (type == N_ENTRY)
|
||||
|
||||
/* Macro for text-offset and data info (in NPL a.out format). */
|
||||
#define TEXTINFO \
|
||||
@ -169,7 +169,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
the new frame is not set up until the new function executes
|
||||
some instructions. True on NPL! Return address is in R1.
|
||||
The true return address is REALLY 4 past that location! */
|
||||
#define SAVED_PC_AFTER_CALL(frame) \
|
||||
`#define SAVED_PC_AFTER_CALL(frame) \
|
||||
(read_register(R1_REGNUM) + 4)
|
||||
|
||||
/* Address of U in kernel space */
|
||||
@ -195,6 +195,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
/* Return 1 if P points to an invalid floating point value. */
|
||||
#define INVALID_FLOAT(p, len) ((*(short *)p & 0xff80) == 0x8000)
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
#define REGISTER_TYPE long
|
||||
|
||||
@ -296,6 +302,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
of data in register N. */
|
||||
#define REGISTER_VIRTUAL_TYPE(N) (builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function.
|
||||
|
||||
On this machine this is a no-op, because gcc isn't used on it
|
||||
yet. So this calling convention is not used. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP)
|
||||
|
||||
/* Extract from an arrary REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
@ -335,21 +349,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
#define FRAME_CHAIN(thisframe) (findframe(thisframe))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && chain != thisframe)
|
||||
(chain != 0 && chain != (thisframe)->frame)
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) \
|
||||
(chain)
|
||||
|
||||
/* Define other aspects of the stack frame on NPL. */
|
||||
#define FRAME_SAVED_PC(frame,ignore) \
|
||||
(read_memory_integer (frame + 8, 4))
|
||||
#define FRAME_SAVED_PC(FRAME) \
|
||||
(read_memory_integer ((FRAME)->frame + 8, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) \
|
||||
((fi).next_frame ? \
|
||||
read_memory_integer ((fi).frame + 12, 4) : \
|
||||
((fi)->next_frame ? \
|
||||
read_memory_integer ((fi)->frame + 12, 4) : \
|
||||
read_register (AP_REGNUM))
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame + 80)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame + 80)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
@ -370,11 +384,11 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
|
||||
{ \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 8; \
|
||||
(frame_saved_regs).regs[R4_REGNUM] = (frame_info).frame + 0x30; \
|
||||
(frame_saved_regs).regs[R5_REGNUM] = (frame_info).frame + 0x34; \
|
||||
(frame_saved_regs).regs[R6_REGNUM] = (frame_info).frame + 0x38; \
|
||||
(frame_saved_regs).regs[R7_REGNUM] = (frame_info).frame + 0x3C; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[R4_REGNUM] = (frame_info)->frame + 0x30; \
|
||||
(frame_saved_regs).regs[R5_REGNUM] = (frame_info)->frame + 0x34; \
|
||||
(frame_saved_regs).regs[R6_REGNUM] = (frame_info)->frame + 0x38; \
|
||||
(frame_saved_regs).regs[R7_REGNUM] = (frame_info)->frame + 0x3C; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
@ -396,12 +410,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
restoring all saved registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
struct frame_info *fi; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
@ -410,7 +426,9 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
set_current_frame (read_register (FP_REGNUM)); }
|
||||
flush_cached_frames (); \
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions:
|
||||
halt
|
||||
@ -443,7 +461,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on a NP1. See np1-pinsn.c for rounding function. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) (((int)(addr) + 31) & ~0xf)
|
56
gdb/m-pn.h
56
gdb/m-pn.h
@ -17,8 +17,8 @@ notice and this notice must be preserved on all copies.
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
|
||||
/* Read file headers properly in core.c */
|
||||
#define gould
|
||||
/* This code appears in libraries on Gould machines. Ignore it. */
|
||||
#define IGNORE_SYMBOL(type) (type == N_ENTRY)
|
||||
|
||||
/* Macro for text-offset and data info (in PN a.out format). */
|
||||
#define TEXTINFO \
|
||||
@ -195,6 +195,12 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
/* Return 1 if P points to an invalid floating point value. */
|
||||
#define INVALID_FLOAT(p, len) ((*(short *)p & 0xff80) == 0x8000)
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
#define REGISTER_TYPE long
|
||||
|
||||
@ -280,6 +286,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
of data in register N. */
|
||||
#define REGISTER_VIRTUAL_TYPE(N) (builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function.
|
||||
|
||||
On this machine this is a no-op, because gcc isn't used on it
|
||||
yet. So this calling convention is not used. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP)
|
||||
|
||||
/* Extract from an arrary REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
@ -319,21 +333,21 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
#define FRAME_CHAIN(thisframe) (findframe(thisframe))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && chain != thisframe)
|
||||
(chain != 0 && chain != (thisframe)->frame)
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) \
|
||||
(chain)
|
||||
|
||||
/* Define other aspects of the stack frame on NPL. */
|
||||
#define FRAME_SAVED_PC(frame,ignore) \
|
||||
(read_memory_integer (frame + 8, 4))
|
||||
#define FRAME_SAVED_PC(frame) \
|
||||
(read_memory_integer ((frame)->frame + 8, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) \
|
||||
((fi).next_frame ? \
|
||||
read_memory_integer ((fi).frame + 12, 4) : \
|
||||
((fi)->next_frame ? \
|
||||
read_memory_integer ((fi)->frame + 12, 4) : \
|
||||
read_register (AP_REGNUM))
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame + 80)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame + 80)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
@ -354,11 +368,11 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
|
||||
{ \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 8; \
|
||||
(frame_saved_regs).regs[R4_REGNUM] = (frame_info).frame + 0x30; \
|
||||
(frame_saved_regs).regs[R5_REGNUM] = (frame_info).frame + 0x34; \
|
||||
(frame_saved_regs).regs[R6_REGNUM] = (frame_info).frame + 0x38; \
|
||||
(frame_saved_regs).regs[R7_REGNUM] = (frame_info).frame + 0x3C; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[R4_REGNUM] = (frame_info)->frame + 0x30; \
|
||||
(frame_saved_regs).regs[R5_REGNUM] = (frame_info)->frame + 0x34; \
|
||||
(frame_saved_regs).regs[R6_REGNUM] = (frame_info)->frame + 0x38; \
|
||||
(frame_saved_regs).regs[R7_REGNUM] = (frame_info)->frame + 0x3C; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
@ -380,12 +394,14 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
restoring all saved registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
struct frame_info *fi; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
@ -394,7 +410,9 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
set_current_frame (read_register (FP_REGNUM)); }
|
||||
flush_cached_frames (); \
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions:
|
||||
halt
|
||||
@ -427,7 +445,7 @@ anyone else from sharing it farther. Help stamp out software hoarding! */
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on a Concept. See pn-pinsn.c for rounding function. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) (((int)(addr) + 7) & ~0x7)
|
@ -36,6 +36,17 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
#define READ_DBX_FORMAT
|
||||
|
||||
/* Big or Little-Endian target machine
|
||||
BITS: defined if bit #0 is the high-order bit of a byte.
|
||||
BYTES:defined if byte#0 is the high-order byte of an int.
|
||||
WORDS:defined if word#0 is the high-order word of a double. */
|
||||
#define BITS_BIG_ENDIAN
|
||||
#define BYTES_BIG_ENDIAN
|
||||
#define WORDS_BIG_ENDIAN
|
||||
|
||||
/* Floating point is IEEE compatible. */
|
||||
#define IEEE_FLOAT
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
Zero on most machines. */
|
||||
|
||||
@ -56,13 +67,14 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
encodes the structure size being returned. If we detect such
|
||||
a fake insn, step past it. */
|
||||
|
||||
#define PC_ADJUST(pc) ((read_memory_integer (pc + 8, 4) & 0xfffffe00) == 0 ? pc+12 : pc+8)
|
||||
#define PC_ADJUST(pc) ((read_memory_integer (pc + 8, 4) & 0xfffffe00) == 0 ? \
|
||||
pc+12 : pc+8)
|
||||
|
||||
#define SAVED_PC_AFTER_CALL(frame) PC_ADJUST (read_register (RP_REGNUM))
|
||||
|
||||
/* Address of end of stack space. */
|
||||
|
||||
#define STACK_END_ADDR 0xf000000
|
||||
#define STACK_END_ADDR 0xf8000000
|
||||
|
||||
/* Stack grows downward. */
|
||||
|
||||
@ -93,6 +105,12 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
@ -146,6 +164,19 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
/* ?? */
|
||||
#define REGISTER_BYTE(N) ((N)*4)
|
||||
|
||||
/* The SPARC processor has register windows. */
|
||||
|
||||
#define HAVE_REGISTER_WINDOWS
|
||||
|
||||
/* Is this register part of the register window system? A yes answer
|
||||
implies that 1) The name of this register will not be the same in
|
||||
other frames, and 2) This register is automatically "saved" (out
|
||||
registers shifting into ins counts) upon subroutine calls and thus
|
||||
there is no need to search more than one stack frame for it. */
|
||||
|
||||
#define REGISTER_IN_WINDOW_P(regnum) \
|
||||
((regnum) >= 8 && (regnum) < 32)
|
||||
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. */
|
||||
|
||||
@ -189,14 +220,21 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
of data in register N. */
|
||||
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
((N) < 32 ? builtin_type_int : (N) < 64 ? builtin_type_float : builtin_type_int)
|
||||
((N) < 32 ? builtin_type_int : (N) < 64 ? builtin_type_float : \
|
||||
builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_memory ((SP)+(16*4), &(ADDR), 4); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
bcopy ((int *)REGBUF+8, VALBUF, TYPE_LENGTH (TYPE))
|
||||
bcopy (((int *)(REGBUF))+8, (VALBUF), TYPE_LENGTH (TYPE))
|
||||
|
||||
/* Write into appropriate registers a function return value
|
||||
of type TYPE, given in virtual format. */
|
||||
@ -208,7 +246,8 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
the address in which a function should return its structure value,
|
||||
as a CORE_ADDR (or an expression that can be used as one). */
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (read_memory_integer (((int *)(REGBUF))[SP_REGNUM]+(16*4), 4))
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \
|
||||
(read_memory_integer (((int *)(REGBUF))[SP_REGNUM]+(16*4), 4))
|
||||
|
||||
/* Enable use of alternate code to read and write registers. */
|
||||
|
||||
@ -227,9 +266,6 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
#define READ_GDB_SYMSEGS
|
||||
|
||||
/* The SPARC processor has register windows. */
|
||||
|
||||
#define HAVE_REGISTER_WINDOWS
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
@ -253,26 +289,56 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
On the Sun4, the frame (in %fp) is %sp for the previous frame.
|
||||
From the previous frame's %sp, we can find the previous frame's
|
||||
%fp: it is in the save area just above the previous frame's %sp. */
|
||||
%fp: it is in the save area just above the previous frame's %sp.
|
||||
|
||||
If we are setting up an arbitrary frame, we'll need to know where
|
||||
it ends. Hence the following. This part of the frame cache
|
||||
structure should be checked before it is assumed that this frame's
|
||||
bottom is in the stack pointer.
|
||||
|
||||
If there isn't a frame below this one, the bottom of this frame is
|
||||
in the stack pointer.
|
||||
|
||||
If there is a frame below this one, and the frame pointers are
|
||||
identical, it's a leaf frame and the bottoms are the same also.
|
||||
|
||||
Otherwise the bottom of this frame is the top of the next frame. */
|
||||
|
||||
#define EXTRA_FRAME_INFO FRAME_ADDR bottom;
|
||||
#define INIT_EXTRA_FRAME_INFO(fci) \
|
||||
(fci)->bottom = \
|
||||
((fci)->next ? \
|
||||
((fci)->frame == (fci)->next_frame ? \
|
||||
(fci)->next->bottom : (fci)->next->frame) : \
|
||||
read_register (SP_REGNUM));
|
||||
|
||||
#define FRAME_CHAIN(thisframe) \
|
||||
GET_RWINDOW_REG (thisframe, rw_in[6])
|
||||
GET_RWINDOW_REG ((thisframe)->frame, rw_in[6])
|
||||
|
||||
/* Avoid checking FRAME_SAVED_PC since that screws us due to
|
||||
improperly set up saved PC on a signal trampoline call */
|
||||
#if 0
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe, 0) >= first_object_file_end))
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
#else
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0)
|
||||
#endif
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(frame, next_frame) frame_saved_pc (frame, next_frame)
|
||||
/* Where is the PC for a specific frame */
|
||||
|
||||
#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME)
|
||||
|
||||
/* If the argument is on the stack, it will be here. */
|
||||
#define FRAME_ARGS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_STRUCT_ARGS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_STRUCT_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
@ -291,101 +357,216 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame.
|
||||
|
||||
Note that on register window machines, we are currently making the
|
||||
assumption that window registers are being saved somewhere in the
|
||||
frame in which they are being used. If they are stored in an
|
||||
inferior frame, find_saved_register will break.
|
||||
|
||||
On the Sun 4, the only time all registers are saved is when
|
||||
a dummy frame is involved. Otherwise, the only saved registers
|
||||
are the LOCAL and IN registers which are saved as a result
|
||||
of the "save/restore" opcodes. This condition is determined
|
||||
by address rather than by value. */
|
||||
|
||||
#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \
|
||||
#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs) \
|
||||
{ register int regnum; \
|
||||
register CORE_ADDR pc; \
|
||||
FRAME frame = (fi).frame; \
|
||||
FRAME next_frame = (fi).next_frame; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((fi).pc >= frame - CALL_DUMMY_LENGTH - 0x140 \
|
||||
&& (fi).pc <= frame) \
|
||||
FRAME_ADDR frame = read_register (FP_REGNUM); \
|
||||
FRAME fid = FRAME_INFO_ID (fi); \
|
||||
if (!fid) fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS"); \
|
||||
bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \
|
||||
if ((fi)->pc >= frame - CALL_DUMMY_LENGTH - 0x140 \
|
||||
&& (fi)->pc <= frame) \
|
||||
{ \
|
||||
for (regnum = 0; regnum < 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum+FP0_REGNUM] = frame + regnum * 4 - 0x80;\
|
||||
for (regnum = 1; regnum < 8; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = frame + regnum * 4 - 0xa0; \
|
||||
for (regnum = 0; regnum < 8; regnum++) \
|
||||
(frame_saved_regs).regs[regnum+24] = frame + regnum * 4 - 0xc0; \
|
||||
for (regnum = 0; regnum < 8; regnum++) \
|
||||
(frame_saved_regs).regs[regnum+64] = frame + regnum * 4 - 0xe0; \
|
||||
frame = (fi).next_frame ? \
|
||||
(fi).next_frame : read_register (SP_REGNUM); \
|
||||
(frame_saved_regs).regs[regnum] = \
|
||||
frame + regnum * 4 - 0xa0; \
|
||||
for (regnum = 24; regnum < 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = \
|
||||
frame + (regnum - 24) * 4 - 0xc0; \
|
||||
for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = \
|
||||
frame + (regnum - FP0_REGNUM) * 4 - 0x80; \
|
||||
for (regnum = 64; regnum < NUM_REGS; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = \
|
||||
frame + (regnum - 64) * 4 - 0xe0; \
|
||||
frame = (fi)->bottom ? \
|
||||
(fi)->bottom : read_register (SP_REGNUM); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
for (regnum = 0; regnum < 16; regnum++) \
|
||||
(frame_saved_regs).regs[regnum+16] = frame + regnum * 4; \
|
||||
frame = (fi)->bottom ? \
|
||||
(fi)->bottom : read_register (SP_REGNUM); \
|
||||
for (regnum = 16; regnum < 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \
|
||||
} \
|
||||
if (next_frame == 0) next_frame = read_register (SP_REGNUM); \
|
||||
for (regnum = 0; regnum < 8; regnum++) \
|
||||
(frame_saved_regs).regs[regnum+8] = next_frame + regnum * 4; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = frame + 14*4; \
|
||||
if ((fi)->next) \
|
||||
{ \
|
||||
/* Pull off either the next frame pointer or \
|
||||
the stack pointer */ \
|
||||
FRAME_ADDR next_next_frame = \
|
||||
((fi)->next->bottom ? \
|
||||
(fi)->next->bottom : \
|
||||
read_register (SP_REGNUM)); \
|
||||
for (regnum = 8; regnum < 16; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = next_next_frame + regnum * 4; \
|
||||
} \
|
||||
/* Otherwise, whatever we would get from ptrace(GETREGS) */ \
|
||||
/* is accurate */ \
|
||||
for (regnum = 30; regnum < 32; regnum++) \
|
||||
(frame_saved_regs).regs[regnum] = frame + (regnum-16) * 4; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = frame + 15*4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
/*
|
||||
* First of all, let me give my opinion of what the DUMMY_FRAME
|
||||
* actually looks like.
|
||||
*
|
||||
* | |
|
||||
* | |
|
||||
* + - - - - - - - - - - - - - - - - +<-- fp (level 0)
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | Frame of innermost program |
|
||||
* | function |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* |---------------------------------|<-- sp (level 0), fp (c)
|
||||
* | |
|
||||
* DUMMY | fp0-31 |
|
||||
* | |
|
||||
* | ------ |<-- fp - 0x80
|
||||
* FRAME | g0-7 |<-- fp - 0xa0
|
||||
* | i0-7 |<-- fp - 0xc0
|
||||
* | other |<-- fp - 0xe0
|
||||
* | ? |
|
||||
* | ? |
|
||||
* |---------------------------------|<-- sp' = fp - 0x140
|
||||
* | |
|
||||
* xcution start | |
|
||||
* sp' + 0x94 -->| CALL_DUMMY (x code) |
|
||||
* | |
|
||||
* | |
|
||||
* |---------------------------------|<-- sp'' = fp - 0x200
|
||||
* | align sp to 8 byte boundary |
|
||||
* | ==> args to fn <== |
|
||||
* Room for | |
|
||||
* i & l's + agg | CALL_DUMMY_STACK_ADJUST = 0x0x44|
|
||||
* |---------------------------------|<-- final sp (variable)
|
||||
* | |
|
||||
* | Where function called will |
|
||||
* | build frame. |
|
||||
* | |
|
||||
* | |
|
||||
*
|
||||
* I understand everything in this picture except what the space
|
||||
* between fp - 0xe0 and fp - 0x140 is used for. Oh, and I don't
|
||||
* understand why there's a large chunk of CALL_DUMMY that never gets
|
||||
* executed (its function is superceeded by PUSH_DUMMY_FRAME; they
|
||||
* are designed to do the same thing).
|
||||
*
|
||||
* PUSH_DUMMY_FRAME saves the registers above sp' and pushes the
|
||||
* register file stack down one.
|
||||
*
|
||||
* call_function then writes CALL_DUMMY, pushes the args onto the
|
||||
* stack, and adjusts the stack pointer.
|
||||
*
|
||||
* run_stack_dummy then starts execution (in the middle of
|
||||
* CALL_DUMMY, as directed by call_function).
|
||||
*/
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
/* NOTE: to be perfectly correct, we will probably have to restore the
|
||||
/* Note: to be perfectly correct, we have to restore the
|
||||
IN registers (which were the OUT registers of the calling frame). */
|
||||
/* Note that the write's are of registers in the context of the newly
|
||||
pushed frame. Thus the the fp*'s, the g*'s, the i*'s, and
|
||||
the others, of the new frame, are being saved.
|
||||
The locals are new; they don't need to be saved. The i's and l's of
|
||||
the last frame were saved by the do_save_insn in the register
|
||||
file (ie. on the stack, since a context switch happended imm after) */
|
||||
/* We note that the return pointer register does not *need* to have
|
||||
the pc saved into it (return from this frame will be accomplished
|
||||
by a POP_FRAME), however, just in case it might be needed, we will
|
||||
leave it. However, we will write the original value of RP into the
|
||||
location on the stack for saving i7 (what rp turns into upon call);
|
||||
this way we don't loose the value with our function call. */
|
||||
/* Note that the pc saved must be 8 less than the actual pc, since
|
||||
both POP_FRAME and the normal return sequence on the sparc return
|
||||
to 8 more than the value of RP_REGNUM */
|
||||
|
||||
#define PUSH_DUMMY_FRAME \
|
||||
{ extern char registers[]; \
|
||||
register int regnum; \
|
||||
CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
CORE_ADDR pc = read_register (PC_REGNUM); \
|
||||
CORE_ADDR pc = read_register (PC_REGNUM) - 8; \
|
||||
CORE_ADDR rp = read_register (RP_REGNUM); \
|
||||
void do_save_insn (); \
|
||||
supply_register (RP_REGNUM, &pc); \
|
||||
do_save_insn (0x140); \
|
||||
fp = read_register (FP_REGNUM); \
|
||||
write_memory (fp - 0x80, ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * 4); \
|
||||
write_memory (fp - 0x80, ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * 4);\
|
||||
write_memory (fp - 0xa0, ®isters[REGISTER_BYTE (0)], 8 * 4); \
|
||||
write_memory (fp - 0xc0, ®isters[REGISTER_BYTE (24)], 8 * 4); \
|
||||
write_memory (fp - 0xc0, ®isters[REGISTER_BYTE (24)], 7 * 4); \
|
||||
write_memory (fp - 0xa4, &rp, 4); \
|
||||
write_memory (fp - 0xe0, ®isters[REGISTER_BYTE (64)], 8 * 4); \
|
||||
}
|
||||
|
||||
/* Discard from the stack the innermost frame,
|
||||
restoring all saved registers. */
|
||||
/* Discard from the stack the innermost frame,
|
||||
restoring all saved registers.
|
||||
Note that the values stored in fsr by get_frame_saved_regs are *in
|
||||
the context of the inferior frame*. What this means is that the i
|
||||
regs of fsr must be restored into the o regs of the frame popped
|
||||
into. We don't care about the output regs of the inferior frame.
|
||||
|
||||
This is true for dummy frames. Is it true for normal frames? It
|
||||
really does appear so. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
char raw_buffer_fp[REGISTER_BYTES]; \
|
||||
char raw_buffer_globals[REGISTER_BYTES]; \
|
||||
char raw_buffer_outs[REGISTER_BYTES]; \
|
||||
char raw_buffer_xx[REGISTER_BYTES]; \
|
||||
void do_restore_insn (); \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
if (fsr.regs[FP0_REGNUM]) \
|
||||
read_memory (fsr.regs[FP0_REGNUM], raw_buffer_fp, 32 * 4); \
|
||||
if (fsr.regs[1]) \
|
||||
read_memory (fsr.regs[1], raw_buffer_globals, 7 * 4); \
|
||||
if (fsr.regs[24]) \
|
||||
read_memory (fsr.regs[24], raw_buffer_outs, 8 * 4); \
|
||||
if (fsr.regs[64]) \
|
||||
read_memory (fsr.regs[64], raw_buffer_xx, 8 * 4); \
|
||||
do_restore_insn (fsr.regs); \
|
||||
if (fsr.regs[FP0_REGNUM]) \
|
||||
write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer_fp, 32 * 4); \
|
||||
if (fsr.regs[1]) \
|
||||
write_register_bytes (REGISTER_BYTE (1), raw_buffer_globals, 7 * 4);\
|
||||
if (fsr.regs[24]) \
|
||||
write_register_bytes (REGISTER_BYTE (8), raw_buffer_outs, 8 * 4); \
|
||||
if (fsr.regs[64]) \
|
||||
write_register_bytes (REGISTER_BYTE (64), raw_buffer_xx, 8 * 4); \
|
||||
set_current_frame (read_register (FP_REGNUM)); \
|
||||
}
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register CORE_ADDR pc; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[REGISTER_BYTES]; \
|
||||
void do_restore_insn (); \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
pc = read_memory_integer (fsr.regs[PC_REGNUM], 4); \
|
||||
do_restore_insn (PC_ADJUST (pc)); \
|
||||
if (fsr.regs[FP0_REGNUM]) \
|
||||
{ \
|
||||
read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4); \
|
||||
write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer, 32 * 4); \
|
||||
} \
|
||||
if (fsr.regs[1]) \
|
||||
{ \
|
||||
read_memory (fsr.regs[1], raw_buffer, 7 * 4); \
|
||||
write_register_bytes (REGISTER_BYTE (1), raw_buffer, 7 * 4); \
|
||||
} \
|
||||
if (fsr.regs[24]) \
|
||||
{ \
|
||||
read_memory (fsr.regs[24], raw_buffer, 8 * 4); \
|
||||
write_register_bytes (REGISTER_BYTE (8), raw_buffer, 8 * 4); \
|
||||
} \
|
||||
if (fsr.regs[PS_REGNUM]) \
|
||||
write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \
|
||||
if (fsr.regs[Y_REGNUM]) \
|
||||
write_register (Y_REGNUM, read_memory_integer (fsr.regs[Y_REGNUM], 4)); \
|
||||
if (fsr.regs[NPC_REGNUM]) \
|
||||
write_register (NPC_REGNUM, read_memory_integer (fsr.regs[NPC_REGNUM], 4)); \
|
||||
flush_cached_frames (); \
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM), \
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
|
||||
@ -429,15 +610,15 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
|
||||
/..* The arguments are pushed at this point by GDB;
|
||||
no code is needed in the dummy for this.
|
||||
The CALL_DUMMY_START_OFFSET gives the position of
|
||||
the following call instruction. *../
|
||||
The CALL_DUMMY_START_OFFSET gives the position of
|
||||
the following ld instruction. *../
|
||||
|
||||
ld [%sp+0x58],%o5
|
||||
ld [%sp+0x44],%o4
|
||||
ld [%sp+0x54],%o4
|
||||
ld [%sp+0x50],%o3
|
||||
ld [%sp+0x4c],%o2
|
||||
ld [%sp+0x48],%o1
|
||||
call 0x34343434
|
||||
call 0x00000000
|
||||
ld [%sp+0x44],%o0
|
||||
nop
|
||||
ta 1
|
||||
@ -466,7 +647,7 @@ arguments. */
|
||||
0xf03fbf40, 0x01000000, 0x01000000, 0x01000000, \
|
||||
0x01000000, 0x91580000, 0xd027bf50, 0x93500000, \
|
||||
0xd027bf4c, 0x91480000, 0xd027bf48, 0x91400000, \
|
||||
0xd027bf44, 0xda03a058, 0xd803a044, 0xd603a050, \
|
||||
0xd027bf44, 0xda03a058, 0xd803a054, 0xd603a050, \
|
||||
0xd403a04c, 0xd203a048, 0x40000000, 0xd003a044, \
|
||||
0x01000000, 0x91d02001, 0x01000000, 0x01000000}
|
||||
|
||||
@ -482,12 +663,29 @@ arguments. */
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ \
|
||||
*(int *)((char *) dummyname+168) = (0x40000000|((fun-(pc+168))>>2)); \
|
||||
if (TYPE_CODE (type) == TYPE_CODE_STRUCT || TYPE_CODE (type) == TYPE_CODE_UNION) \
|
||||
if (TYPE_CODE (type) == TYPE_CODE_STRUCT \
|
||||
|| TYPE_CODE (type) == TYPE_CODE_UNION) \
|
||||
*(int *)((char *) dummyname+176) = (TYPE_LENGTH (type) & 0x1fff); \
|
||||
}
|
||||
|
||||
|
||||
/* Sparc has no reliable single step ptrace call */
|
||||
|
||||
#define NO_SINGLE_STEP 1
|
||||
|
||||
/* It does have a wait structure, and it might help things out . . . */
|
||||
|
||||
#define HAVE_WAIT_STRUCT
|
||||
|
||||
/* Handle a feature in the sun4 compiler ("call .stret4" at the end of
|
||||
functions returning structures). */
|
||||
|
||||
#define SUN4_COMPILER_FEATURE
|
||||
|
||||
/* We need two arguments (in general) to the "info frame" command.
|
||||
Note that the definition of this macro implies that there exists a
|
||||
function "setup_arbitrary_frame" in mach-dep.c */
|
||||
|
||||
#define FRAME_SPECIFICATION_DYADIC
|
||||
|
||||
/* KDB stuff flushed for now. */
|
72
gdb/m-sun2.h
72
gdb/m-sun2.h
@ -86,6 +86,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
@ -162,6 +168,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#define REGISTER_VIRTUAL_TYPE(N) builtin_type_int
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (9, (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
@ -181,6 +193,18 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))
|
||||
|
||||
/* Enable use of alternate code to read and write registers. */
|
||||
|
||||
#define NEW_SUN_PTRACE
|
||||
|
||||
/* Enable use of alternate code for Sun's format of core dump file. */
|
||||
|
||||
#define NEW_SUN_CORE
|
||||
|
||||
/* Do implement the attach and detach commands. */
|
||||
|
||||
#define ATTACH_DETACH
|
||||
|
||||
/* This is a piece of magic that is given a register number REGNO
|
||||
and as BLOCKEND the address in the system of the end of the user structure
|
||||
and stores in ADDR the address in the kernel or core dump
|
||||
@ -205,20 +229,20 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
/* In the case of the Sun, the frame's nominal address
|
||||
is the address of a 4-byte word containing the calling frame's address. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4))
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end))
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4))
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
@ -229,7 +253,7 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#if 0
|
||||
#define FRAME_NUM_ARGS(val, fi) \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
|
||||
register int insn = 0177777 & read_memory_integer (pc, 2); \
|
||||
val = 0; \
|
||||
if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
|
||||
@ -258,19 +282,19 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
register CORE_ADDR next_addr; \
|
||||
register CORE_ADDR pc; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 4 \
|
||||
&& (frame_info).pc <= (frame_info).frame) \
|
||||
{ next_addr = (frame_info).frame; \
|
||||
pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4; }\
|
||||
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 4 \
|
||||
&& (frame_info)->pc <= (frame_info)->frame) \
|
||||
{ next_addr = (frame_info)->frame; \
|
||||
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4; }\
|
||||
else \
|
||||
{ pc = get_pc_function_start ((frame_info).pc); \
|
||||
{ pc = get_pc_function_start ((frame_info)->pc); \
|
||||
/* Verify we have a link a6 instruction next; \
|
||||
if not we lose. If we win, find the address above the saved \
|
||||
regs using the amount of storage from the link instruction. */\
|
||||
if (044016 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
else if (047126 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
else goto lose; \
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */ \
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
|
||||
@ -295,9 +319,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
if (0x426742e7 == read_memory_integer (pc, 4)) \
|
||||
(frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
|
||||
lose: ; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
@ -318,12 +342,14 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
/* Discard from the stack the innermost frame, restoring all registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
struct frame_info *fi; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
@ -332,7 +358,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
}
|
||||
flush_cached_frames (); \
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
moveml 0xfffc,-(sp)
|
||||
@ -364,7 +392,7 @@ taken for the arguments. */
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 16) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 10) = fun; }
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on a sun. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) (addr)
|
2
gdb/m-sun2os4.h
Normal file
2
gdb/m-sun2os4.h
Normal file
@ -0,0 +1,2 @@
|
||||
#include "m-sun2.h"
|
||||
#define SUNOS4
|
64
gdb/m-sun3.h
64
gdb/m-sun3.h
@ -85,6 +85,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
@ -132,6 +138,8 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. On the 68000, all regs are 4 bytes
|
||||
except the floating point regs which are 12 bytes. */
|
||||
/* Note that the unsigned cast here forces the result of the
|
||||
subtractiion to very high positive values if N < FP0_REGNUM */
|
||||
|
||||
#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4)
|
||||
|
||||
@ -178,6 +186,12 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
(((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (9, (ADDR)); }
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
@ -230,20 +244,20 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
/* In the case of the Sun, the frame's nominal address
|
||||
is the address of a 4-byte word containing the calling frame's address. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4))
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end))
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4))
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) (fi.frame)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Set VAL to the number of args passed to frame described by FI.
|
||||
Can set VAL to -1, meaning no way to tell. */
|
||||
@ -254,7 +268,7 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
|
||||
#if 0
|
||||
#define FRAME_NUM_ARGS(val, fi) \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame,0); \
|
||||
{ register CORE_ADDR pc = FRAME_SAVED_PC (fi); \
|
||||
register int insn = 0177777 & read_memory_integer (pc, 2); \
|
||||
val = 0; \
|
||||
if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \
|
||||
@ -284,19 +298,19 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
register CORE_ADDR pc; \
|
||||
int nextinsn; \
|
||||
bzero (&frame_saved_regs, sizeof frame_saved_regs); \
|
||||
if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info).pc <= (frame_info).frame) \
|
||||
{ next_addr = (frame_info).frame; \
|
||||
pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \
|
||||
&& (frame_info)->pc <= (frame_info)->frame) \
|
||||
{ next_addr = (frame_info)->frame; \
|
||||
pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\
|
||||
else \
|
||||
{ pc = get_pc_function_start ((frame_info).pc); \
|
||||
{ pc = get_pc_function_start ((frame_info)->pc); \
|
||||
/* Verify we have a link a6 instruction next; \
|
||||
if not we lose. If we win, find the address above the saved \
|
||||
regs using the amount of storage from the link instruction. */\
|
||||
if (044016 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; \
|
||||
else if (047126 == read_memory_integer (pc, 2)) \
|
||||
next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; \
|
||||
else goto lose; \
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */ \
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \
|
||||
@ -323,7 +337,7 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \
|
||||
if (regmask & 1) \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \
|
||||
else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) \
|
||||
{ regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \
|
||||
(frame_saved_regs).regs[regnum] = (next_addr -= 4); } \
|
||||
/* fmovemx to index of sp may follow. */ \
|
||||
@ -340,9 +354,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
if (0x426742e7 == read_memory_integer (pc, 4)) \
|
||||
(frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \
|
||||
lose: ; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \
|
||||
(frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \
|
||||
}
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
@ -368,13 +382,15 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
restoring all saved registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
struct frame_info *fi; \
|
||||
char raw_buffer[12]; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \
|
||||
if (fsr.regs[regnum]) \
|
||||
{ read_memory (fsr.regs[regnum], raw_buffer, 12); \
|
||||
@ -387,7 +403,9 @@ read_memory_integer (read_register (SP_REGNUM), 4)
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
set_current_frame (read_register (FP_REGNUM)); }
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
fmovem 0xff,-(sp)
|
||||
@ -420,7 +438,7 @@ taken for the arguments. */
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ *(int *)((char *) dummyname + 20) = nargs * 4; \
|
||||
*(int *)((char *) dummyname + 14) = fun; }
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on a sun. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) ((addr + 3) & -4)
|
3
gdb/m-sun3os4.h
Normal file
3
gdb/m-sun3os4.h
Normal file
@ -0,0 +1,3 @@
|
||||
#include "m-sun3.h"
|
||||
#define SUNOS4
|
||||
#define FPU
|
@ -1,5 +0,0 @@
|
||||
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on a sun. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) ((addr + 7) & -8)
|
3
gdb/m-sun4os4.h
Normal file
3
gdb/m-sun4os4.h
Normal file
@ -0,0 +1,3 @@
|
||||
#include "m-sparc.h"
|
||||
#define SUNOS4
|
||||
#define FPU
|
@ -1,5 +0,0 @@
|
||||
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on a sun. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) ((addr + 3) & -4)
|
58
gdb/m-umax.h
58
gdb/m-umax.h
@ -103,6 +103,12 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
NaF (*(float *) p) : \
|
||||
NaD (*(double *) p))
|
||||
|
||||
/* Largest integer type */
|
||||
#define LONGEST long
|
||||
|
||||
/* Name of the builtin type for the LONGEST type above. */
|
||||
#define BUILTIN_TYPE_LONGEST builtin_type_long
|
||||
|
||||
/* Say how long (ordinary) registers are. */
|
||||
|
||||
#define REGISTER_TYPE long
|
||||
@ -228,6 +234,14 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
builtin_type_int : \
|
||||
builtin_type_double)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function.
|
||||
|
||||
On this machine this is a no-op, because gcc isn't used on it
|
||||
yet. So this calling convention is not used. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP)
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
@ -263,24 +277,24 @@ anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
/* In the case of the ns32000 series, the frame's nominal address is the FP
|
||||
value, and at that address is saved previous FP value as a 4-byte word. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4))
|
||||
#define FRAME_CHAIN(thisframe) (read_memory_integer ((thisframe)->frame, 4))
|
||||
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe,0) >= first_object_file_end))
|
||||
(chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end))
|
||||
|
||||
#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
#define FRAME_SAVED_PC(frame,ignore) (read_memory_integer (frame + 4, 4))
|
||||
#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4))
|
||||
|
||||
/* Compute base of arguments. */
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) \
|
||||
((ns32k_get_enter_addr (fi.pc) > 1) ? \
|
||||
((fi).frame) : (read_register (SP_REGNUM) - 4))
|
||||
((ns32k_get_enter_addr ((fi)->pc) > 1) ? \
|
||||
((fi)->frame) : (read_register (SP_REGNUM) - 4))
|
||||
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame)
|
||||
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
|
||||
|
||||
/* Get the address of the enter opcode for this function, if it is active.
|
||||
Returns positive address > 1 if pc is between enter/exit,
|
||||
@ -306,12 +320,12 @@ extern CORE_ADDR ns32k_get_enter_addr ();
|
||||
int width; \
|
||||
\
|
||||
numargs = -1; \
|
||||
enter_addr = ns32k_get_enter_addr (fi.pc); \
|
||||
enter_addr = ns32k_get_enter_addr ((fi)->pc); \
|
||||
if (enter_addr > 0) \
|
||||
{ \
|
||||
pc = (enter_addr == 1) ? \
|
||||
SAVED_PC_AFTER_CALL () : \
|
||||
FRAME_SAVED_PC (fi.frame,0); \
|
||||
SAVED_PC_AFTER_CALL (fi) : \
|
||||
FRAME_SAVED_PC (fi); \
|
||||
insn = read_memory_integer (pc,2); \
|
||||
addr_mode = (insn >> 11) & 0x1f; \
|
||||
insn = insn & 0x7ff; \
|
||||
@ -350,19 +364,19 @@ extern CORE_ADDR ns32k_get_enter_addr ();
|
||||
register CORE_ADDR next_addr; \
|
||||
\
|
||||
bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \
|
||||
enter_addr = ns32k_get_enter_addr ((frame_info).pc); \
|
||||
enter_addr = ns32k_get_enter_addr ((frame_info)->pc); \
|
||||
if (enter_addr > 1) \
|
||||
{ \
|
||||
regmask = read_memory_integer (enter_addr+1, 1) & 0xff; \
|
||||
localcount = ns32k_localcount (enter_addr); \
|
||||
next_addr = (frame_info).frame + localcount; \
|
||||
next_addr = (frame_info)->frame + localcount; \
|
||||
for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \
|
||||
(frame_saved_regs).regs[regnum] = (regmask & 1) ? \
|
||||
(next_addr -= 4) : 0; \
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 4;\
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4;\
|
||||
(frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 4;\
|
||||
(frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4;\
|
||||
(frame_saved_regs).regs[FP_REGNUM] = \
|
||||
(read_memory_integer ((frame_info).frame, 4));\
|
||||
(read_memory_integer ((frame_info)->frame, 4));\
|
||||
} \
|
||||
else if (enter_addr == 1) \
|
||||
{ \
|
||||
@ -393,19 +407,23 @@ extern CORE_ADDR ns32k_get_enter_addr ();
|
||||
/* Discard from the stack the innermost frame, restoring all registers. */
|
||||
|
||||
#define POP_FRAME \
|
||||
{ register CORE_ADDR fp = read_register (FP_REGNUM); \
|
||||
{ register FRAME frame = get_current_frame (); \
|
||||
register CORE_ADDR fp; \
|
||||
register int regnum; \
|
||||
struct frame_saved_regs fsr; \
|
||||
struct frame_info fi; \
|
||||
fi = get_frame_info (fp); \
|
||||
get_frame_saved_regs (&fi, &fsr); \
|
||||
struct frame_info *fi; \
|
||||
fi = get_frame_info (frame); \
|
||||
fp = fi->frame; \
|
||||
get_frame_saved_regs (fi, &fsr); \
|
||||
for (regnum = 0; regnum < 8; regnum++) \
|
||||
if (fsr.regs[regnum]) \
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4)); \
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \
|
||||
write_register (SP_REGNUM, fp + 8); \
|
||||
}
|
||||
flush_cached_frames (); \
|
||||
set_current_frame (create_new_frame (read_register (FP_REGNUM),\
|
||||
read_pc ())); }
|
||||
|
||||
/* This sequence of words is the instructions
|
||||
enter 0xff,0 82 ff 00
|
||||
@ -424,7 +442,7 @@ extern CORE_ADDR ns32k_get_enter_addr ();
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, fun, nargs) \
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \
|
||||
{ \
|
||||
int flipped; \
|
||||
flipped = fun | 0xc0000000; \
|
||||
|
@ -1,4 +0,0 @@
|
||||
/* This is how the size of an individual .o file's text segment
|
||||
is rounded on the multimax. */
|
||||
|
||||
#define FILEADDR_ROUND(addr) ((addr + 3) & -4)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user