Initial revision

This commit is contained in:
K. Richard Pixley 1991-03-28 16:26:26 +00:00
parent 5a131cc7f0
commit bd5635a1e2
71 changed files with 63772 additions and 0 deletions

249
gdb/COPYING Normal file
View file

@ -0,0 +1,249 @@
GNU GENERAL PUBLIC LICENSE
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The license agreements of most software companies try to keep users
at the mercy of those companies. By contrast, our General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. The
General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it.
You can use it for your programs, too.
When we speak of free software, we are referring to freedom, not
price. Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of a such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must tell them their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work based
on the Program" means either the Program or any work containing the
Program or a portion of it, either verbatim or with modifications. Each
licensee is addressed as "you".
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this
General Public License and to the absence of any warranty; and give any
other recipients of the Program a copy of this General Public License
along with the Program. You may charge a fee for the physical act of
transferring a copy.
2. You may modify your copy or copies of the Program 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 the Program or any part thereof, either
with or without modifications, to be licensed at no charge to all
third parties under the terms of this General Public License (except
that you may choose to grant warranty protection to some or all
third parties, at your option).
c) If the modified program normally reads commands interactively when
run, you must cause it, when started running for such interactive use
in the simplest and most usual way, to print or display an
announcement including an appropriate copyright notice and a notice
that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these
conditions, and telling the user how to view a copy of this General
Public License.
d) You may charge a 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 independent work with the Program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other work under the scope of these terms.
3. You may copy and distribute the 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 charge
for the cost of distribution) 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.)
Source code for a work means the preferred form of the work for making
modifications to it. 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, or for standard header files or definitions files that
accompany that operating system.
4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
the Program is void, and will automatically terminate your rights to use
the Program under this License. However, parties who have received
copies, or rights to use copies, from you under this General Public
License will not have their licenses terminated so long as such parties
remain in full compliance.
5. By copying, distributing or modifying the Program (or any work based
on the Program) you indicate your acceptance of this license to do so,
and all its terms and conditions.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these
terms and conditions. You may not impose any further restrictions on the
recipients' exercise of the rights granted herein.
7. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of the license which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
the license, you may choose any version ever published by the Free Software
Foundation.
8. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision 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 generally.
NO WARRANTY
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE 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.
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19xx name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
program `Gnomovision' (a program to direct compilers to make passes
at assemblers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
That's all there is to it!

4297
gdb/ChangeLog Normal file

File diff suppressed because it is too large Load diff

4846
gdb/ChangeLog-3.x Normal file

File diff suppressed because it is too large Load diff

506
gdb/Makefile.in Normal file
View file

@ -0,0 +1,506 @@
##Copyright (C) 1989-1991 Free Software Foundation, Inc.
# This file is part of GDB.
# GDB is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 1, or (at your option)
# any later version.
# GDB is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with GDB; see the file COPYING. If not, write to
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
# Place to install binaries.
bindir=/usr/local/bin
# System V: If you compile gdb with a compiler which uses the coff
# encapsulation feature (this is a function of the compiler used, NOT
# of the m-?.h file selected by config.gdb), you must make sure that
# the GNU nm is the one that is used by munch.
# If you are compiling with GCC, make sure that either 1) You use the
# -traditional flag, or 2) You have the fixed include files where GCC
# can reach them. Otherwise the ioctl calls in inflow.c and readline.c
# will be incorrectly compiled. The "fixincludes" script in the gcc
# distribution will fix your include files up.
#CC=cc
#CC=gcc -traditional
GCC=gcc
VPATH=$(srcdir)
# It is also possible that you will need to add -I/usr/include/sys to the
# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which
# is where it should be according to Posix).
YACC=bison -y
# YACC=yacc
SHELL=/bin/sh
MAKE=make
# Set this up with gcc if you have gnu ld and the loader will print out
# line numbers for undefinded refs.
#CC-LD=gcc -static
CC-LD=${CC}
# define this to be "gmalloc.o" if you want to use the gnu malloc routine
# (useful for debugging memory allocation problems in gdb). To use your
# system malloc, uncomment the following two lines.
#GNU_MALLOC =
#MALLOC_CFLAGS = -DNO_MALLOC_CHECK
GNU_MALLOC = gmalloc.o mcheck.o
MALLOC_CFLAGS =
# Where is the "include" directory? Traditionally ../include or ./include
INCLUDE_DIR = ${srcdir}/../include
INCLUDE_DEP = $$(INCLUDE_DIR)
# Where is the BFD library? Traditionally ../bfd or ./bfd
BFD_DIR = ${srcdir}/../bfd
BFD_DEP = $$(BFD_DIR)
# All the includes used for CFLAGS and for lint.
# -I. for config files.
# -I${srcdir} for <obstack.h>, possibly regex.h also.
INCLUDE_CFLAGS = -I. -I${srcdir} -I$(INCLUDE_DIR) -I${srcdir}/vx-share
# {X,T}M_CFLAGS, if defined, has system-dependent CFLAGS.
# CFLAGS for both GDB and readline.
GLOBAL_CFLAGS = -g ${TM_CFLAGS} ${XM_CFLAGS}
#PROFILE_CFLAGS = -pg
CFLAGS = ${GLOBAL_CFLAGS} ${PROFILE_CFLAGS} ${MALLOC_CFLAGS} ${INCLUDE_CFLAGS}
# None of the things in CFLAGS will do any harm, and on some systems
# (e.g. SunOS4) it is important to use the M_CFLAGS.
LDFLAGS = $(CFLAGS)
# define this to be "obstack.o" if you don't have the obstack library installed
# so that the dependencies work right.
OBSTACK = obstack.o
# Requires GNU getopt_long features.
GETOPT = getopt.o getopt1.o
# Where is the getopt directory? Traditionally ../getopt or ./getopt
GETOPT_DIR = ${srcdir}/../getopt
GETOPT_DEP = $$(GETOPT_DIR)
# Flags that describe where you can find the termcap library.
# You may need to make other arrangements for USG.
TERMCAP = -ltermcap
# You must define REGEX and REGEX1 on USG machines.
# If your sysyem is missing alloca(), or, more likely, it's there but
# it doesn't work, define ALLOCA & ALLOCA1
# {X,T}M_CLIBS, if defined, has system-dependent libs
# For example, -lPW for System V to get alloca().
# FIXME STOPGAP FOR BFD LIBRARY: BFD stuff
CLIBS = ${TERMCAP} $(XM_CLIBS) ${TM_CLIBS} ${BFD_DIR}/libbfd.a
CDEPS = ${XM_CDEPS} ${TM_CDEPS} ${BFD_DIR}/libbfd.a
ADD_FILES = ${OBSTACK} ${REGEX} ${ALLOCA} ${GNU_MALLOC} ${GETOPT}
ADD_DEPS = ${OBSTACK} ${REGEX1} ${ALLOCA1} ${GNU_MALLOC} ${GETOPT}
VERSION = 3.94.2
DIST=gdb-$(VERSION)
LINT=/usr/5bin/lint
LINTFLAGS=
# Source files in the main directory.
# Files which are included via a tconfig/* or xconfig/* file
# should *not* be specified here; they're in "ALLDEPFILES".
SFILES_MAINDIR = \
blockframe.c breakpoint.c command.c core.c \
environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \
main.c printcmd.c \
remote.c source.c stack.c symmisc.c symtab.c symfile.c \
utils.c valarith.c valops.c valprint.c values.c expread.y \
signame.c cplus-dem.c mem-break.c target.c inftarg.c \
dbxread.c coffread.c \
ieee-float.c
# Source files in subdirectories (which will be handled separately by
# 'make gdb.tar.Z').
# Files which are included via a tconfig/* or xconfig/* file
# should *not* be specified here; they're in "ALLDEPFILES".
SFILES_SUBDIR = \
${srcdir}/vx-share/dbgRpcLib.h \
${srcdir}/vx-share/ptrace.h \
${srcdir}/vx-share/reg.h \
${srcdir}/vx-share/vxTypes.h \
${srcdir}/vx-share/vxWorks.h \
${srcdir}/vx-share/wait.h \
${srcdir}/vx-share/xdr_ld.h \
${srcdir}/vx-share/xdr_ptrace.h \
${srcdir}/vx-share/xdr_rdb.h \
${srcdir}/vx-share/xdr_regs.h \
${srcdir}/nindy-share/Makefile \
${srcdir}/nindy-share/VERSION \
${srcdir}/nindy-share/b.out.h \
${srcdir}/nindy-share/block_io.h \
${srcdir}/nindy-share/coff.h \
${srcdir}/nindy-share/demux.h \
${srcdir}/nindy-share/env.h \
${srcdir}/nindy-share/stop.h \
${srcdir}/nindy-share/ttycntl.h
# All source files that go into linking GDB, except config-specified files.
SFILES = $(SFILES_MAINDIR) $(SFILES_SUBDIR)
# All source files that lint should look at
LINTFILES = $(SFILES) expread.tab.c init.c
# Any additional files specified on these lines should also be added to
# the OTHERS = definition below, so they go in the tar files.
SFILES_STAND = $(SFILES) standalone.c
SFILES_KGDB = $(SFILES) stuff.c kdb-start.c
# Header files that are not named in tconfig/* or xconfig/* go here.
HFILES= breakpoint.h command.h defs.h environ.h \
expression.h frame.h gdbcmd.h gdbcore.h \
getpagesize.h ieee-float.h inferior.h param-no-tm.h param.h \
signals.h signame.h symfile.h symtab.h \
target.h tdesc.h terminal.h tm-68k.h tm-i960.h tm-sunos.h \
value.h
OPCODES = pn-opcode.h np1-opcode.h sparc-opcode.h vax-opcode.h m68k-opcode.h \
ns32k-opcode.h convex-opcode.h pyr-opcode.h mips-opcode.h \
am29k-opcode.h
REMOTE_EXAMPLES = remote-sa.m68k.shar remote-multi.shar
MALLOCSRC = gmalloc.c mcheck.c ansidecl.h stdlib.h gmalloc.h stddef.h
GETOPTSRC = $(GETOPT_DIR)/getopt.c $(GETOPT_DIR)/getopt1.c
POSSLIBS_MAINDIR = obstack.h obstack.c regex.c regex.h alloca.c \
$(MALLOCSRC)
POSSLIBS = $(POSSLIBS_MAINDIR) $(GETOPTSRC)
TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c
# tdesc-lib cannot be named simply tdesc, because if if it were GNU make
# would try to make it from tdesc.c.
# tdesc-lib removed from the list due to Motorola copyrights...gnu@cygnus.com
OTHERS = Makefile.dist depend alldeps.mak Makefile.srcdir \
createtags munch config.gdb config.status \
ChangeLog ChangeLog-3.x \
README TODO TAGS WHATS.NEW \
gdb.texinfo gdb-int.texinfo gdbrc.tex threecol.tex \
.gdbinit COPYING expread.tab.c stab.def \
copying.c Projects Convex.notes copying.awk \
saber.suppress standalone.c stuff.c kdb-start.c \
hp-include # tests
DEPFILES= ${TDEPFILES} ${XDEPFILES}
SOURCES=$(SFILES) $(ALLDEPFILES)
TAGFILES = $(SOURCES) ${HFILES} ${OPCODES} ${ALLPARAM} ${POSSLIBS}
TAGFILES_MAINDIR = $(SFILES_MAINDIR) $(ALLDEPFILES_MAINDIR) \
${HFILES} ${OPCODES} ${ALLPARAM} ${POSSLIBS_MAINDIR}
TARFILES = ${TAGFILES_MAINDIR} ${OTHERS} ${REMOTE_EXAMPLES}
OBS = main.o blockframe.o breakpoint.o findvar.o stack.o source.o \
values.o eval.o valops.o valarith.o valprint.o printcmd.o \
symtab.o symfile.o symmisc.o infcmd.o infrun.o remote.o \
command.o utils.o expread.o expprint.o environ.o version.o \
copying.o $(DEPFILES) signame.o cplus-dem.o mem-break.o target.o \
inftarg.o ieee-float.o \
dbxread.o coffread.o # mipsread.o
RAPP_OBS = rgdb.o rudp.o rserial.o serial.o udp.o $(XDEPFILES)
TSOBS = core.o inflow.o
NTSOBS = standalone.o
TSSTART = /lib/crt0.o
NTSSTART = kdb-start.o
RL_LIB = readline/libreadline.a
RL_LIB_DEP = $(RL_LIB)
# Prevent Sun make from putting in the machine type. Setting
# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1.
.c.o:
${CC} -c ${CFLAGS} $<
all: gdb
install: gdb
cp gdb $(bindir)/gdb.new
mv $(bindir)/gdb.new $(bindir)/gdb
$(M_INSTALL)
init.c: $(srcdir)/munch $(MUNCH_DEFINE) $(OBS) $(TSOBS)
$(srcdir)/munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) > init.c
gdb: $(OBS) $(TSOBS) ${ADD_DEPS} ${RL_LIB_DEP} ${CDEPS} init.o
${CC-LD} $(LDFLAGS) -o gdb init.o $(OBS) $(TSOBS) $(ADD_FILES) \
${RL_LIB} $(CLIBS)
saber_gdb: $(SFILES) $(GETOPTSRC) $(DEPFILES) copying.c obstack.c version.c
#setopt load_flags $(CFLAGS) -I$(BFD_DIR)
#load ./init.c $(SFILES)
#unload ${srcdir}/expread.y
#load ${srcdir}/expread.tab.c readline/libreadline.a
#load copying.c version.c
#load obstack.c $(GETOPTSRC)
#load `echo " "$(DEPFILES) | sed -e 's/\.o/.c/g' -e 's, , ../,g'`
#load ${BFD_DIR}/libbfd.a -ltermcap
##void mcheck(a) void (*a)(); { }
# This is useful when debugging GDB, because some Unix's don't let you run GDB
# on itself without copying the executable. So "make gdb1" will make
# gdb and put a copy in gdb1, and you can run it with "gdb gdb1".
# Removing gdb1 before the copy is the right thing if gdb1 is open
# in another process.
gdb1: gdb
rm -f gdb1
cp gdb gdb1
# This is a remote stub which runs under unix and starts up an
# inferior process. This is at least useful for debugging GDB's
# remote support.
rapp: $(RAPP_OBS)
rm -f rapp_init.c
${srcdir}/munch ${RAPP_OBS} > rapp_init.c
${CC-LD} $(LDFLAGS) -o $@ rapp_init.c $(RAPP_OBS)
Makefiles= Makefile.srcdir $(M_MAKEFILE) \
${srcdir}/alldeps.mak ${srcdir}/Makefile.dist
MAKE_MAKEFILE= echo "M_MAKEFILE=$(M_MAKEFILE)" | \
cat - ${Makefiles} ${srcdir}/depend >Makefile
Makefile: $(Makefiles)
$(MAKE_MAKEFILE)
alldeps.mak: ${srcdir}/tconfig ${srcdir}/xconfig
rm -f alldeps.mak alldeps.tmp allparam.tmp allconfig.tmp
for i in `ls -d ${srcdir}/tconfig/*[0-9A-Za-z] \
${srcdir}/xconfig/*[0-9A-Za-z] | grep -v RCS` ; do \
echo $$i >>allconfig.tmp; \
awk <$$i ' \
$$1 == "TDEPFILES=" || $$1 == "XDEPFILES=" { \
for (i = 2; i <= NF; i++) \
print $$i >> "alldeps.tmp" ; \
} \
$$1 == "TM_FILE=" || $$1 == "XM_FILE=" { \
print $$2 >> "allparam.tmp" }' ; \
done
sort <alldeps.tmp | uniq | \
sed -e 's/arm-convert.o/arm-convert.s/' \
-e 's!^Onindy.o!nindy-share/Onindy.c!' \
-e 's!^nindy.o!nindy-share/nindy.c!' \
-e 's!ttybreak.o!nindy-share/ttybreak.c!' \
-e 's!ttyflush.o!nindy-share/ttyflush.c!' \
-e 's!xdr_ld.o!vx-share/xdr_ld.c!' \
-e 's!xdr_ptrace.o!vx-share/xdr_ptrace.c!' \
-e 's!xdr_rdb.o!vx-share/xdr_rdb.c!' \
-e 's!xdr_regs.o!vx-share/xdr_regs.c!' \
-e 's/\.o/.c/' \
>alldeps2.tmp
echo 'ALLDEPFILES = $$(ALLDEPFILES_MAINDIR) $$(ALLDEPFILES_SUBDIR)' \
>>alldeps.mak;
grep -v / alldeps2.tmp | \
awk 'BEGIN {printf "ALLDEPFILES_MAINDIR="} \
NR == 0 {printf $$0;} \
NR != 0 {printf "\\\n" $$0} \
END {printf "\n\n"}' >>alldeps.mak;
grep / alldeps2.tmp | \
awk 'BEGIN {printf "ALLDEPFILES_SUBDIR="} \
NR == 0 {printf $$0;} \
NR != 0 {printf "\\\n" $$0} \
END {printf "\n\n"}' >>alldeps.mak;
sort <allparam.tmp | uniq | awk 'BEGIN {printf "ALLPARAM="} \
NR == 0 {printf $$0;} \
NR != 0 {printf "\\\n" $$0} \
END {printf "\n\n"}' >>alldeps.mak;
sort <allconfig.tmp | uniq | awk 'BEGIN {printf "ALLCONFIG="} \
NR == 0 {printf $$0;} \
NR != 0 {printf "\\\n" $$0} \
END {printf "\n\n"}' >>alldeps.mak;
rm -f alldeps.tmp alldeps2.tmp allparam.tmp allconfig.tmp
# The sed script makes everything which depends on {x,t}m.h depend on
# config.status as well, in case someone reconfigures gdb out from
# under an already compiled gdb.
depend: $(SOURCES) Makefile.dist
@echo Ignore errors about non-existent system-supplied include files
@echo for systems other than the one you are using.
@echo "If xm.h and tm.h don't exist, the error messages saying so"
@echo can safely be ignored.
@echo Also ignore parse errors in valops.c, and any errors in
@echo arm-convert.s.
-$(GCC) -MM $(CFLAGS) -I$(BFD_DIR) \
`ls $(SOURCES) | sort -u` >depend.tmp
<depend.tmp sed -e 's/ [xt]m.h/& config.status/g' \
-e 's; vx-share/; $${srcdir}/vx-share/;g' \
-e 's; nindy-share/; $${srcdir}/nindy-share/;g' \
-e 's; $(INCLUDE_DIR)/; $(INCLUDE_DEP)/;g' \
-e 's; [a-z0-9./]*bfd/; $(BFD_DEP)/;g' \
-e 's; [a-z0-9./]*getopt/; $(GETOPT_DEP)/;g' \
-e 's; \./; $${srcdir}/;g' \
>depend
$(MAKE_MAKEFILE)
rm depend.tmp
config.status:
@echo "You must configure gdb. Look at the README file for details."
@false
# These are not generated by "make depend" because they only are there
# for some machines.
tm-isi.h tm-sun3.h tm-news.h tm-hp300bsd.h tm-altos.h : tm-68k.h
tm-hp300hpux.h tm-sun2.h tm-3b1.h : tm-68k.h
xm-news1000.h : xm-news.h
xm-i386-sv32.h : xm-i386.h
tm-i386gas.h: tm-i386.h
xm-sun4os4.h : xm-sparc.h
tm-sun4os4.h : tm-sparc.h
kdb : $(NTSSTART) $(OBS) $(NTSOBS) ${ADD_DEPS} ${RL_LIB_DEP}
rm -f init.c
$(srcdir)/munch ${MUNCH_DEFINE} $(OBS) $(NTSOBS) > init.c
$(CC) $(LDFLAGS) -c init.c $(CLIBS)
ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o $(ADD_FILES) \
${RL_LIB} -lc $(CLIBS)
# Put the proper machine-specific files first.
# createtags will edit the .o in DEPFILES into .c
TAGS: ${TAGFILES}
$(srcdir)/createtags $(TM_FILE) ${XM_FILE} $(DEPFILES) ${TAGFILES}
tags: TAGS
# FIXME: Get alldeps.mak up to date, config.gdb none, THEN make gdb.tar.Z!
gdb.tar.Z: ${TARFILES}
rm -f gdb.tar; rm -rf $(DIST)
cd readline ; make readline.tar
mkdir $(DIST)
cd $(DIST) ; for i in ${TARFILES} ; do ln -s ../$$i . ; done
mkdir $(DIST)/readline
cd $(DIST)/readline ; tar xf ../../readline/readline.tar
mkdir $(DIST)/xconfig ${DIST}/tconfig
cd $(DIST)/tconfig ; \
for i in $(ALLCONFIG) ; do ln -s ../../$$i ../$$i ; done
mkdir $(DIST)/vx-share $(DIST)/nindy-share
cd $(DIST)/tconfig ; \
for i in $(SFILES_SUBDIR) $(ALLDEPFILES_SUBDIR); \
do ln -s ../../$$i ../$$i ; done
tar chf - $(DIST) | compress >gdb.tar.Z
rm -rf $(DIST)
clean:
rm -f ${OBS} ${TSOBS} ${NTSOBS} ${ADD_FILES}
rm -f init.c init.o version.c
rm -f gdb core gdb.tar gdb.tar.Z make.log
rm -f gdb[0-9]
cd readline ; make clean
distclean: clean expread.tab.c TAGS
rm -f tm.h xm.h config.status
rm -f y.output yacc.acts yacc.tmp
rm -f ${TESTS} Makefile
realclean: clean
rm -f expread.tab.c TAGS
rm -f tm.h xm.h config.status
rm -f Makefile
gdb.dvi : gdb.texinfo
tex gdb.texinfo
texindex gdb.??
tex gdb.texinfo
# Make copying.c from COPYING
copying.c : COPYING copying.awk
awk -f copying.awk < COPYING > copying.c
version.c : Makefile.dist
echo 'char *version = "$(VERSION)";' >version.c
${srcdir}/expread.tab.c : $(srcdir)/expread.y
@echo 'Expect 4 shift/reduce conflict.'
${YACC} $(srcdir)/expread.y
mv y.tab.c ${srcdir}/expread.tab.c
expread.o : ${srcdir}/expread.tab.c defs.h param.h symtab.h \
frame.h expression.h
$(CC) -c ${CFLAGS} `echo ${srcdir}/expread.tab.c | sed 's,^\./,,'`
mv expread.tab.o expread.o
# dbxread, coffread, mipsread have dependencies on BFD header files.
dbxread.o: ${srcdir}/dbxread.c
${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/dbxread.c
coffread.o: ${srcdir}/coffread.c
${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/coffread.c
mipsread.o: ${srcdir}/mipsread.c
${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/mipsread.c
# Drag in the files that are in another directory.
getopt1.o: $(GETOPT_DIR)/getopt1.c
${CC} -c ${CFLAGS} $(GETOPT_DIR)/getopt1.c
getopt.o: $(GETOPT_DIR)/getopt.c
${CC} -c ${CFLAGS} $(GETOPT_DIR)/getopt.c
xdr_ld.o: ${srcdir}/vx-share/xdr_ld.c
${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_ld.c
xdr_ptrace.o: ${srcdir}/vx-share/xdr_ptrace.c
${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_ptrace.c
xdr_rdb.o: ${srcdir}/vx-share/xdr_rdb.c
${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_rdb.c
xdr_regs.o: ${srcdir}/vx-share/xdr_regs.c
${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_regs.c
nindy.o: ${srcdir}/nindy-share/nindy.c
${CC} -c ${CFLAGS} ${srcdir}/nindy-share/nindy.c
Onindy.o: ${srcdir}/nindy-share/Onindy.c
${CC} -c ${CFLAGS} ${srcdir}/nindy-share/Onindy.c
ttybreak.o: ${srcdir}/nindy-share/ttybreak.c
${CC} -c ${CFLAGS} ${srcdir}/nindy-share/ttybreak.c
ttyflush.o: ${srcdir}/nindy-share/ttyflush.c
${CC} -c ${CFLAGS} ${srcdir}/nindy-share/ttyflush.c
tdesc-lib/libdc.o : force_update
cd tdesc-lib ; ${MAKE} "SYSV_DEFINE=${SYSV_DEFINE}"
# In LOCAL_INCLUDES, -I${srcdir} is right if srcdir is an absolute path,
# and -I../${srcdir} is right if it is relative (e.g. ".."), so search both.
readline/libreadline.a : force_update
cd readline ; ${MAKE} "SYSV=${SYSV_DEFINE}"\
"VPATH=${srcdir}/readline:../${srcdir}/readline"\
"LOCAL_INCLUDES=-I../ -I${srcdir}/ -I../${srcdir}/"\
"DEBUG_FLAGS=${GLOBAL_CFLAGS}" "CC=${CC}" libreadline.a
lint: $(LINTFILES)
$(LINT) $(INCLUDE_CFLAGS) $(LINTFLAGS) $(LINTFILES)
gdb.cxref: $(SFILES)
cxref -I. $(SFILES) >gdb.cxref
force_update :
# When used with GDB, the demangler should never look for leading underscores
# because GDB strips them off during symbol read-in. Thus -Dnounderscore.
cplus-dem.o : cplus-dem.c
${CC} -c -Dnounderscore `echo ${srcdir}/cplus-dem.c | sed 's,^\./,,'`

259
gdb/README Normal file
View file

@ -0,0 +1,259 @@
This is GDB, the GNU source-level debugger, presently running under
un*x. This is a pre-alpha version of GDB version 4, and has NOT been
extensively tested. It surely has some bugs, both bugs that were
present in version 3 and new bugs. I have filed all the bug reports
and fixes mailed to bug-gdb, and the fixes in particular will move
into these sources as I find the time.
=> THIS VERSION IS PARTICULARLY FRAGILE! <=
It depends on a preliminary version of a new "binary file
descriptor" library and a new global "include" directory, which
are packaged separately from GDB. You must obtain, configure
and build this library manually, then configure and build gdb.
When building gdb's for multiple platforms, you must manually
rebuild the bfd library separately for each platform. Yes, of
course, we are working on this! FIXME!
Configure bfd for your host system by:
cd ../bfd
edit Makefile
make
Then you can cd ../gdb-whatever, and config and build gdb.
This release moves the generic GNU include files, the BFD library,
and the getopt routines into the parent directory of gdb. The idea
is that a variety of GNU tools can share a common copy of these things.
A summary of features new since gdb-3.5 is in the file `WHATS.NEW'.
The best way to build GDB, in my opinion, is in a subdirectory. I use
a naming convention "=XXX" where XXX is the machine type I'm building
for. Nothing depends on this, it's just how I remember which
subdirectories are what. So, once you have the BFD library built for
that machine, you can do:
cd gdb-x.yy (the directory where this README is)
mkdir =XXX (e.g. mkdir =vax)
cd =XXX
../config.gdb machine
make
Machine is like "vax" or "sun4". For more information type `../config.gdb'.
Once you have done that, just `make' will do everything, producing an
executable `gdb' in this directory.
You can also build gdb binaries in a completely different directory from its
sources, by specifying "srcdir=YYY" to config.gdb, giving it an absolute
or relative path to the source directory.
GDB can be used as a cross-debugger, running on a machine of one type
while debugging a program running on a machine of another type. You
configure it this way by specifying `config.gdb host target' where host
is where GDB runs, and target is where your program runs.
If you want a new (current to this release) version of the manual, you
will have to use the gdb.texinfo file provided with this distribution.
For details see the texinfo manual (distributed with emacs and as a
printed manual).
About languages other than C...
C++ support has been integrated into gdb. GDB should work with FORTRAN
programs (if you have problem, please send a bug report; note that you
may have to refer to some FORTRAN variables with a trailing
underscore), but I am not aware of anyone who is working on getting it
to use the syntax of any language other than C or C++. Pascal programs
which use sets, subranges, file variables, or nested functions will not
currently work.
About kernel debugging...
I have't done this myself so I can't really offer any advice.
Remote debugging over serial lines is more like to be in a currently
functioning state than the standalone gdb (kdb). FIXME.
About remote debugging...
[This section seems to be out of date, I have never seen the "rapp"
program, though I would like to. FIXME.]
`rapp' runs under unix and acts as a remote stub (like remote-multi.shar
distributed with GDB version 3). Currently it just works over UDP
(network), not over a serial line. To get it running
* Compile GDB on the host machine as usual
* Compile rapp on the target machine, giving for both host and target
the type of the target machine
* Install "gdb" in /etc/services on both machines.
This will get reworked before the initial release of 4.x. FIXME.
The two files remote-multi.shar and remote-sa.m68k.shar contain two
examples of a remote stub to be used with remote.c. The the -multi
file is a general stub that can probably be running on various
different flavors of unix to allow debugging over a serial line from
one machine to another. The remote-sa.m68k.shar is designed to run
standalone on a 68k type cpu and communicate properley with the
remote.c stub over a serial line.
The files remote-eb.c and remote-nindy.c are two examples of remote
interfaces for talking to existing ROM monitors (for the AMD 29000 and the
Intel 960 repsectively). There is also a remote interface for the
VxWorks realtime kernel, which communicates over TCP/IP, in remote-vx.c
and the vx-share subdirectory.
About reporting bugs...
The correct address for reporting bugs found with gdb is
"bug-gdb@prep.ai.mit.edu". Please email all bugs to that address.
About xgdb...
Hopefully a new xgdb will be in 4.x.
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. See
XGDB-README for one person's opinion about what is wrong with the
current xgdb. Someone is working on writing a new XGDB, so improving
(e.g. by fixing it so that it will work, if it doesn't currently) the
current one is not worth 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
(Try typing M-x gdb RETURN). Comments on this mode are welcome.
About the machine-dependent files...
tconfig/<machine>
This contains Makefile stuff for when the target system is <machine>.
It also specifies the name of the tm-XXX.h file for this machine.
xconfig/<machine>
This contains Makefile stuff for when the host system is <machine>.
It also specifies the name of the xm-XXX.h file for this machine.
tm-XXX.h (tm.h is a link to this file, created by config.gdb).
This file contains macro definitions that express information
about the target machine's registers, stack frame format and instructions.
xm-XXX.h (xm.h is a link to this file, created by config.gdb).
This contains macro definitions describing the host system environment,
such as byte order, host C compiler and library, ptrace support,
and core file structure.
<machine>-opcode.h
<machine>-pinsn.c
These files contain the information necessary to print instructions
for your cpu type. <machine>-opcode.h includes some large initialized
data structures, which is strange for a ".h" file, but it's OK since
it is only included in one place. <machine>-opcode.h is shared
between the debugger and the assembler (if the GNU assembler has been
ported to that machine), whereas <machine>-pinsn.c is specific to GDB.
<machine>-tdep.c
This file contains any miscellaneous code required for this machine
as a target. On some machines it doesn't exist at all. Its existence
is specified in the tconfig/XXX file.
<machine>-xdep.c
This file contains any miscellaneous code required for this machine
as a host. On some machines it doesn't exist at all. Its existence
is specified in the xconfig/XXX file.
infptrace.c
This is the low level interface to inferior processes for systems
using the Unix ptrace call in a vanilla way. Some systems have their
own routines in <machine>-xdep.c. Whether or not it is used
is specified in the xconfig/XXX file.
coredep.c
Machine and system-dependent aspects of reading core files. Some
machines use coredep.c; some have the routines in <machine>-xdep.c.
Whether or not it is used is specified in the xconfig/XXX file.
Now that BFD is used to read core files, virtually all machines should
use coredep.c and should just provide fetch_core_registers in
<machine>-xdep.c.
exec.c
Machine and system-dependent aspects of reading executable files.
Some machines use exec.c; some have the routines in <machine>-tdep.c
Since BFD, virtually all machines should use exec.c.
About writing code for GDB...
We appreciate having users contribute code that is of general use, but
for it to be included in future GDB releases it must be cleanly
written. We do not want to include changes that will needlessly make
future maintainance difficult. It is not much harder to do things
right, and in the long term it is worth it to the GNU project, and
probably to you individually as well.
Please code according to the GNU coding standards. If you do not have
a copy, you can request one by sending mail to gnu@prep.ai.mit.edu.
If you make substantial changes, you'll have to file a copyright
assignment with the Free Software Foundation before we can produce a
release that includes your changes. Send mail requesting the copyright
assignment to gnu@prep.ai.mit.edu. Do this early, like before the
changes actually work, or even before you start them, because a manager
or lawyer on your end will probably make this a slow process.
Please try to avoid making machine-specific changes to
machine-independent files. If this is unavoidable, put a hook in the
machine-independent file which calls a (possibly) machine-dependent
macro (for example, the IGNORE_SYMBOL macro can be used for any
symbols which need to be ignored on a specific machine. Calling
IGNORE_SYMBOL in dbxread.c is a lot cleaner than a maze of #if
defined's). The machine-independent code should do whatever "most"
machines want if the macro is not defined in param.h. Using #if
defined can sometimes be OK (e.g. SET_STACK_LIMIT_HUGE) but should be
conditionalized on a specific feature of an operating system (set in
tm.h or xm.h) rather than something like #if defined(vax) or #if
defined(SYSV). If you use an #ifdef on some symbol that is defined
in a header file (e.g. #ifdef TIOCSETP), *please* make sure that you
have #include'd the relevant header file in that module!
It is better to replace entire routines which may be system-specific,
rather than put in a whole bunch of hooks which are probably not going
to be helpful for any purpose other than your changes. For example,
if you want to modify dbxread.c to deal with DBX debugging symbols
which are in COFF files rather than BSD a.out files, do something
along the lines of a macro GET_NEXT_SYMBOL, which could have
different definitions for COFF and a.out, rather than trying to put
the necessary changes throughout all the code in dbxread.c that
currently assumes BSD format.
Please avoid duplicating code. For example, in GDB 3.x all the stuff
in infptrace.c was duplicated in *-dep.c, and so changing something
was very painful. Thus in GDB 4.x these have all been consolidated
into infptrace.c. infptrace.c can deal with variations between
systems the same way any system-independent file would (hooks, #if
defined, etc.), and machines which are radically different don't need
to use infptrace.c at all. The same was true of core_file_command
and exec_file_command.
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, 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.
When you run gdb in this directory, it will read a ".gdbinit" file that
sets up some simple things to make debugging gdb easier. 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 details.
(this is for editing this file with GNU emacs)
Local Variables:
mode: text
End:

406
gdb/arm-tdep.c Normal file
View file

@ -0,0 +1,406 @@
/* Copyright (C) 1988, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#include "arm-opcode.h"
#include <stdio.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/ptrace.h>
#include <machine/reg.h>
#define N_TXTADDR(hdr) 0x8000
#define N_DATADDR(hdr) (hdr.a_text + 0x8000)
#include "gdbcore.h"
#include <sys/user.h> /* After a.out.h */
#include <sys/file.h>
#include <sys/stat.h>
#include <errno.h>
/* Work with core dump and executable files, for GDB.
This code would be in core.c if it weren't machine-dependent. */
/* Structure to describe the chain of shared libraries used
by the execfile.
e.g. prog shares Xt which shares X11 which shares c. */
struct shared_library {
struct exec_header header;
char name[SHLIBLEN];
CORE_ADDR text_start; /* CORE_ADDR of 1st byte of text, this file */
long data_offset; /* offset of data section in file */
int chan; /* file descriptor for the file */
struct shared_library *shares; /* library this one shares */
};
static struct shared_library *shlib = 0;
/* Hook for `exec_file_command' command to call. */
extern void (*exec_file_display_hook) ();
static CORE_ADDR unshared_text_start;
/* extended header from exec file (for shared library info) */
static struct exec_header exec_header;
void
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;
unshared_text_start = 0;
text_end = 0;
exec_data_start = 0;
exec_data_end = 0;
if (execchan >= 0)
close (execchan);
execchan = -1;
if (shlib) {
close_shared_library(shlib);
shlib = 0;
}
/* Now open and digest the file the user requested, if any. */
if (filename)
{
filename = tilde_expand (filename);
make_cleanup (free, filename);
execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
&execfile);
if (execchan < 0)
perror_with_name (filename);
{
struct stat st_exec;
#ifdef HEADER_SEEK_FD
HEADER_SEEK_FD (execchan);
#endif
val = myread (execchan, &exec_header, sizeof exec_header);
exec_aouthdr = exec_header.a_exec;
if (val < 0)
perror_with_name (filename);
text_start = 0x8000;
/* Look for shared library if needed */
if (exec_header.a_exec.a_magic & MF_USES_SL)
shlib = open_shared_library(exec_header.a_shlibname, text_start);
text_offset = N_TXTOFF (exec_aouthdr);
exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
if (shlib) {
unshared_text_start = shared_text_end(shlib) & ~0x7fff;
stack_start = shlib->header.a_exec.a_sldatabase;
stack_end = STACK_END_ADDR;
} else
unshared_text_start = 0x8000;
text_end = unshared_text_start + exec_aouthdr.a_text;
exec_data_start = unshared_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;
}
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);
}
/* 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, EIO if addresss out of bounds. */
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 define the shared library data. */
else if (memaddr >= stack_start && memaddr < stack_end)
{
if (corechan < 0) {
struct shared_library *lib;
for (lib = shlib; lib; lib = lib->shares)
if (memaddr >= lib->header.a_exec.a_sldatabase &&
memaddr < lib->header.a_exec.a_sldatabase +
lib->header.a_exec.a_data)
break;
if (lib) {
i = min (len, lib->header.a_exec.a_sldatabase +
lib->header.a_exec.a_data - memaddr);
fileptr = lib->data_offset + memaddr -
lib->header.a_exec.a_sldatabase;
xferfile = execfile;
xferchan = lib->chan;
}
} else {
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)
{
struct shared_library *lib;
for (lib = shlib; lib; lib = lib->shares)
if (memaddr >= lib->text_start &&
memaddr < lib->text_start + lib->header.a_exec.a_text)
break;
if (lib) {
i = min (len, lib->header.a_exec.a_text +
lib->text_start - memaddr);
fileptr = memaddr - lib->text_start + text_offset;
xferfile = &execfile;
xferchan = lib->chan;
} else {
i = min (len, text_end - memaddr);
fileptr = memaddr - unshared_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 (corechan >= 0
&& memaddr >= data_end && memaddr < stack_start)
{
i = min (len, stack_start - memaddr);
}
else if (corechan < 0 && memaddr >= exec_data_end)
{
i = min (len, - 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 shouldn't happen; we catch the endpoints. */
fatal ("Internal: Bad case logic in xfer_core_file.");
}
/* 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.
Actually, we never right. */
else
{
bzero (myaddr, i);
returnval = EIO;
}
memaddr += i;
myaddr += i;
len -= i;
}
return returnval;
}
/* APCS (ARM procedure call standard) defines the following prologue:
mov ip, sp
[stmfd sp!, {a1,a2,a3,a4}]
stmfd sp!, {...,fp,ip,lr,pc}
[stfe f7, [sp, #-12]!]
[stfe f6, [sp, #-12]!]
[stfe f5, [sp, #-12]!]
[stfe f4, [sp, #-12]!]
sub fp, ip, #nn // nn == 20 or 4 depending on second ins
*/
CORE_ADDR
skip_prologue(pc)
CORE_ADDR pc;
{
union insn_fmt op;
CORE_ADDR skip_pc = pc;
op.ins = read_memory_integer(skip_pc, 4);
/* look for the "mov ip,sp" */
if (op.generic.type != TYPE_ARITHMETIC ||
op.arith.opcode != OPCODE_MOV ||
op.arith.dest != SPTEMP ||
op.arith.operand2 != SP) return pc;
skip_pc += 4;
/* skip the "stmfd sp!,{a1,a2,a3,a4}" if its there */
op.ins = read_memory_integer(skip_pc, 4);
if (op.generic.type == TYPE_BLOCK_BRANCH &&
op.generic.subtype == SUBTYPE_BLOCK &&
op.block.mask == 0xf &&
op.block.base == SP &&
op.block.is_load == 0 &&
op.block.writeback == 1 &&
op.block.increment == 0 &&
op.block.before == 1) skip_pc += 4;
/* skip the "stmfd sp!,{...,fp,ip,lr,pc} */
op.ins = read_memory_integer(skip_pc, 4);
if (op.generic.type != TYPE_BLOCK_BRANCH ||
op.generic.subtype != SUBTYPE_BLOCK ||
/* the mask should look like 110110xxxxxx0000 */
(op.block.mask & 0xd800) != 0xd800 ||
op.block.base != SP ||
op.block.is_load != 0 ||
op.block.writeback != 1 ||
op.block.increment != 0 ||
op.block.before != 1) return pc;
skip_pc += 4;
/* check for "sub fp,ip,#nn" */
op.ins = read_memory_integer(skip_pc, 4);
if (op.generic.type != TYPE_ARITHMETIC ||
op.arith.opcode != OPCODE_SUB ||
op.arith.dest != FP ||
op.arith.operand1 != SPTEMP) return pc;
return skip_pc + 4;
}
static void
print_fpu_flags(flags)
int flags;
{
if (flags & (1 << 0)) fputs("IVO ", stdout);
if (flags & (1 << 1)) fputs("DVZ ", stdout);
if (flags & (1 << 2)) fputs("OFL ", stdout);
if (flags & (1 << 3)) fputs("UFL ", stdout);
if (flags & (1 << 4)) fputs("INX ", stdout);
putchar('\n');
}
void
arm_float_info()
{
register unsigned long status = read_register(FPS_REGNUM);
int type;
type = (status >> 24) & 127;
printf("%s FPU type %d\n",
(status & (1<<31)) ? "Hardware" : "Software",
type);
fputs("mask: ", stdout);
print_fpu_flags(status >> 16);
fputs("flags: ", stdout);
print_fpu_flags(status);
}

650
gdb/blockframe.c Normal file
View file

@ -0,0 +1,650 @@
/* Get info from stack frames;
convert between frames, blocks, functions and pc values.
Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "param.h"
#include "symtab.h"
#include "frame.h"
#include "gdbcore.h"
#include "value.h" /* for read_register */
#include "target.h" /* for target_has_stack */
/* Required by INIT_EXTRA_FRAME_INFO on 88k. */
#include <setjmp.h>
#include <obstack.h>
CORE_ADDR read_pc (); /* In infcmd.c */
/* Start and end of object file containing the entry point.
STARTUP_FILE_END is the first address of the next file.
This file is assumed to be a startup file
and frames with pc's inside it
are treated as nonexistent.
Setting these variables is necessary so that backtraces do not fly off
the bottom of the stack. */
CORE_ADDR startup_file_start;
CORE_ADDR startup_file_end;
/* Is ADDR outside the startup file? Note that if your machine
has a way to detect the bottom of the stack, there is no need
to call this function from FRAME_CHAIN_VALID; the reason for
doing so is that some machines have no way of detecting bottom
of stack. */
int
outside_startup_file (addr)
CORE_ADDR addr;
{
return !(addr >= startup_file_start && addr < startup_file_end);
}
/* Address of innermost stack frame (contents of FP register) */
static FRAME current_frame;
/*
* 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);
}
/* Return the frame that FRAME calls (0 if FRAME is the innermost
frame). */
FRAME
get_next_frame (frame)
FRAME frame;
{
/* We're allowed to know that FRAME and "struct frame_info *" are
the same */
return frame->next;
}
/*
* 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;
}
/* If a machine allows frameless functions, it should define a macro
FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) in param.h. FI is the struct
frame_info for the frame, and FRAMELESS should be set to nonzero
if it represents a frameless function invocation. */
/* Return nonzero if the function for this frame has a prologue. Many
machines can define FRAMELESS_FUNCTION_INVOCATION to just call this
function. */
int
frameless_look_for_prologue (frame)
FRAME frame;
{
CORE_ADDR func_start, after_prologue;
func_start = (get_pc_function_start (frame->pc) +
FUNCTION_START_OFFSET);
if (func_start)
{
after_prologue = func_start;
SKIP_PROLOGUE (after_prologue);
return after_prologue == func_start;
}
else
/* If we can't find the start of the function, we don't really
know whether the function is frameless, but we should be able
to get a reasonable (i.e. best we can do under the
circumstances) backtrace by saying that it isn't. */
return 0;
}
#if !defined (INIT_FRAME_PC)
#define INIT_FRAME_PC(fromleaf, prev) \
prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
#endif
/* Return a structure containing various interesting information
about the frame that called NEXT_FRAME. Returns NULL
if there is no such frame. */
struct frame_info *
get_prev_frame_info (next_frame)
FRAME next_frame;
{
FRAME_ADDR address;
struct frame_info *prev;
int fromleaf = 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)
{
if (!current_frame)
{
error ("You haven't set up a process's stack to examine.");
}
return current_frame;
}
/* If we have the prev one, return it */
if (next_frame->prev)
return next_frame->prev;
/* On some machines it is possible to call a function without
setting up a stack frame for it. On these machines, we
define this macro to take two args; a frameinfo pointer
identifying a frame and a variable to set or clear if it is
or isn't leafless. */
#ifdef FRAMELESS_FUNCTION_INVOCATION
/* Still don't want to worry about this except on the innermost
frame. This macro will set FROMLEAF if NEXT_FRAME is a
frameless function invocation. */
if (!(next_frame->next))
{
FRAMELESS_FUNCTION_INVOCATION (next_frame, fromleaf);
if (fromleaf)
address = next_frame->frame;
}
#endif
if (!fromleaf)
{
/* Two macros defined in tm.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 or a leaf
called by the outermost frame. This means that if start
calls main without a frame, we'll return 0 (which is fine
anyway).
Nope; there's a problem. This also returns when the current
routine is a leaf of main. This is unacceptable. We move
this to after the ffi test; I'd rather have backtraces from
start go curfluy than have an abort called from main not show
main. */
address = FRAME_CHAIN (next_frame);
if (!FRAME_CHAIN_VALID (address, next_frame))
return 0;
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. */
INIT_FRAME_PC(fromleaf, prev);
return prev;
}
CORE_ADDR
get_frame_pc (frame)
FRAME frame;
{
struct frame_info *fi;
fi = get_frame_info (frame);
return fi->pc;
}
#if defined (FRAME_FIND_SAVED_REGS)
/* 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;
{
FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr);
}
#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;
CORE_ADDR pc;
fi = get_frame_info (frame);
pc = fi->pc;
if (fi->next_frame != 0)
/* We are not in the innermost frame. We need to subtract one to
get the correct block, in case the call instruction was the
last instruction of the block. If there are any machines on
which the saved pc does not point to after the call insn, we
probably want to make fi->pc point after the call insn anyway. */
--pc;
return block_for_pc (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 blockvector immediately containing the innermost lexical block
containing the specified pc value, or 0 if there is none.
PINDEX is a pointer to the index value of the block. If PINDEX
is NULL, we don't pass this information back to the caller. */
struct blockvector *
blockvector_for_pc (pc, pindex)
register CORE_ADDR pc;
int *pindex;
{
register struct block *b;
register int bot, top, half;
register struct symtab *s;
struct blockvector *bl;
/* First search all symtabs for one whose file contains our pc */
s = find_pc_symtab (pc);
if (s == 0)
return 0;
bl = BLOCKVECTOR (s);
b = BLOCKVECTOR_BLOCK (bl, 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)
{
if (pindex)
*pindex = bot;
return bl;
}
bot--;
}
return 0;
}
/* Return the innermost lexical block containing the specified pc value,
or 0 if there is none. */
struct block *
block_for_pc (pc)
register CORE_ADDR pc;
{
register struct blockvector *bl;
int index;
bl = blockvector_for_pc (pc, &index);
if (bl)
return BLOCKVECTOR_BLOCK (bl, index);
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);
}
/* These variables are used to cache the most recent result
* of find_pc_partial_function. */
static CORE_ADDR cache_pc_function_low = 0;
static CORE_ADDR cache_pc_function_high = 0;
static char *cache_pc_function_name = 0;
/* Clear cache, e.g. when symbol table is discarded. */
void
clear_pc_function_cache()
{
cache_pc_function_low = 0;
cache_pc_function_high = 0;
cache_pc_function_name = (char *)0;
}
/* Finds the "function" (text symbol) that is smaller than PC
but greatest of all of the potential text symbols. Sets
*NAME and/or *ADDRESS conditionally if that pointer is non-zero.
Returns 0 if it couldn't find anything, 1 if it did. On a zero
return, *NAME and *ADDRESS are always set to zero. On a 1 return,
*NAME and *ADDRESS contain real information. */
int
find_pc_partial_function (pc, name, address)
CORE_ADDR pc;
char **name;
CORE_ADDR *address;
{
struct partial_symtab *pst;
struct symbol *f;
int miscfunc;
struct partial_symbol *psb;
if (pc >= cache_pc_function_low && pc < cache_pc_function_high)
{
if (address)
*address = cache_pc_function_low;
if (name)
*name = cache_pc_function_name;
return 1;
}
pst = find_pc_psymtab (pc);
if (pst)
{
if (pst->readin)
{
/* The information we want has already been read in.
We can go to the already readin symbols and we'll get
the best possible answer. */
f = find_pc_function (pc);
if (!f)
{
return_error:
/* No available symbol. */
if (name != 0)
*name = 0;
if (address != 0)
*address = 0;
return 0;
}
cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
cache_pc_function_name = SYMBOL_NAME (f);
if (name)
*name = cache_pc_function_name;
if (address)
*address = cache_pc_function_low;
return 1;
}
/* Get the information from a combination of the pst
(static symbols), and the misc function vector (extern
symbols). */
miscfunc = find_pc_misc_function (pc);
psb = find_pc_psymbol (pst, pc);
if (!psb && miscfunc == -1)
{
goto return_error;
}
if (psb
&& (miscfunc == -1
|| (SYMBOL_VALUE_ADDRESS (psb)
>= misc_function_vector[miscfunc].address)))
{
/* This case isn't being cached currently. */
if (address)
*address = SYMBOL_VALUE_ADDRESS (psb);
if (name)
*name = SYMBOL_NAME (psb);
return 1;
}
}
else
/* Must be in the misc function stuff. */
{
miscfunc = find_pc_misc_function (pc);
if (miscfunc == -1)
goto return_error;
}
{
if (misc_function_vector[miscfunc].type == mf_text)
cache_pc_function_low = misc_function_vector[miscfunc].address;
else
/* It is a transfer table for Sun shared libraries. */
cache_pc_function_low = pc - FUNCTION_START_OFFSET;
}
cache_pc_function_name = misc_function_vector[miscfunc].name;
if (miscfunc < misc_function_count && 1 /* FIXME mf_text again? */ )
cache_pc_function_high = misc_function_vector[miscfunc+1].address;
else
cache_pc_function_high = cache_pc_function_low + 1;
if (address)
*address = cache_pc_function_low;
if (name)
*name = cache_pc_function_name;
return 1;
}
/* 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;
/* Note that the last thing in the vector is always _etext. */
/* Actually, "end", now that non-functions
go on the misc_function_vector. */
/* 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;
/* Note that the following search will not return hi if
pc == misc_function_vector[hi].address. If "end" points to the
first unused location, this is correct and the above test
simply needs to be changed to
"pc >= misc_function_vector[hi].address". */
do {
new = (lo + hi) >> 1;
if (misc_function_vector[new].address == pc)
return new; /* an exact match */
else if (misc_function_vector[new].address > pc)
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);
}

2259
gdb/breakpoint.c Normal file

File diff suppressed because it is too large Load diff

129
gdb/breakpoint.h Normal file
View file

@ -0,0 +1,129 @@
/* Copyright (C) 1990 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (BREAKPOINT_H)
#define BREAKPOINT_H 1
/* This is the maximum number of bytes a breakpoint instruction can take.
Feel free to increase it. It's just used in a few places to size
arrays that should be independent of the target architecture. */
#define BREAKPOINT_MAX 10
extern void breakpoint_re_set ();
extern void clear_momentary_breakpoints ();
extern void set_momentary_breakpoint ();
extern void set_ignore_count ();
extern void set_default_breakpoint ();
extern void mark_breakpoints_out ();
extern void breakpoint_auto_delete ();
extern void breakpoint_clear_ignore_counts ();
/* The following are for displays, which aren't really breakpoints, but
here is as good a place as any for them. */
extern void disable_current_display ();
extern void do_displays ();
extern void disable_display ();
extern void clear_displays ();
/* The follow stuff is an abstract data type "bpstat" ("breakpoint status").
This provides the ability to determine whether we have stopped at a
breakpoint, and what we should do about it. */
typedef struct bpstat__struct *bpstat;
/* Interface: */
/* Clear a bpstat so that it says we are not at any breakpoint.
Also free any storage that is part of a bpstat. */
void bpstat_clear();
/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that
is part of the bpstat is copied as well. */
bpstat bpstat_copy();
/* Get a bpstat associated with having just stopped at address *PC
and frame address FRAME_ADDRESS. Update *PC to point at the
breakpoint (if we hit a breakpoint). */
bpstat bpstat_stop_status (/* CORE_ADDR *pc; FRAME_ADDR frame_address */);
/* Nonzero if we should print the frame. */
#define bpstat_should_print(bs) ((bs) != NULL && (bs)->print)
/* Nonzero if we should stop. */
#define bpstat_stop(bs) ((bs) != NULL && (bs)->stop)
/* Nonzero if we hit a momentary breakpoint. */
#define bpstat_momentary_breakpoint(bs) ((bs) != NULL && (bs)->momentary)
/* Nonzero if a signal that we got in wait() was due to circumstances
explained by the BS. */
/* Currently that is true iff we have hit a breakpoint. */
#define bpstat_explains_signal(bs) ((bs) != NULL)
/* Nonzero if we should step constantly (e.g. watchpoints on machines
without hardware support). This isn't related to a specific bpstat,
just to things like whether watchpoints are set. */
int bpstat_should_step (/* void */);
/* Print a message indicating what happened. Returns nonzero to
say that only the source line should be printed after this (zero
return means print the frame as well as the source line). */
int bpstat_print (/* bpstat bs */);
/* Return the breakpoint number of the first breakpoint we are stopped
at. *BSP upon return is a bpstat which points to the remaining
breakpoints stopped at (but which is not guaranteed to be good for
anything but further calls to bpstat_num).
Return 0 if passed a bpstat which does not indicate any breakpoints. */
int bpstat_num (/* bpstat *bsp; */);
/* Perform actions associated with having stopped at *BSP. */
void bpstat_do_actions (/* bpstat bs; */);
/* Modify BS so that the actions will not be performed. */
void bpstat_clear_actions (/* bpstat bs; */);
/* Implementation: */
#include "value.h"
struct bpstat__struct
{
/* Linked list because there can be two breakpoints at the
same place, and a bpstat reflects the fact that both have been hit. */
bpstat next;
/* Breakpoint that we are at. */
struct breakpoint *breakpoint_at;
/* Commands left to be done. */
struct command_line *commands;
/* Old value associated with a watchpoint. */
value old_val;
/* Nonzero if we should print the frame. Only significant for the first
bpstat in the chain. */
char print;
/* Nonzero if we should stop. Only significant for the first bpstat in
the chain. */
char stop;
/* Nonzero if we hit a momentary breakpoint. Only significant for the
first bpstat in the chain. */
char momentary;
};
#endif /* breakpoint.h not already included. */

1969
gdb/coffread.c Normal file

File diff suppressed because it is too large Load diff

151
gdb/command.h Normal file
View file

@ -0,0 +1,151 @@
/* Header file for command-reading library command.c.
Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _COMMAND_H_INCLUDED
#define _COMMAND_H_INCLUDED
/* Not a set/show command. Note that some commands which begin with
"set" or "show" might be in this category, if their syntax does
not fall into one of the following categories. */
typedef enum cmd_types {
not_set_cmd,
set_cmd,
show_cmd,
} cmd_types;
/* Types of "set" or "show" command. */
typedef enum var_types {
/* "on" or "off". *VAR is an integer which is nonzero for on,
zero for off. */
var_boolean,
/* Unsigned Integer. *VAR is an unsigned int. The user can type 0
to mean "unlimited", which is stored in *VAR as UINT_MAX. */
var_uinteger,
/* String which the user enters with escapes (e.g. the user types \n and
it is a real newline in the stored string).
*VAR is a malloc'd string, or NULL if the string is empty. */
var_string,
/* String which stores what the user types verbatim.
*VAR is a malloc'd string, or NULL if the string is empty. */
var_string_noescape,
/* String which stores a filename.
*VAR is a malloc'd string, or NULL if the string is empty. */
var_filename,
/* ZeroableInteger. *VAR is an int. Like Unsigned Integer except
that zero really means zero. */
var_zinteger,
} var_types;
/* This structure records one command'd definition. */
struct cmd_list_element
{
/* Points to next command in this list. */
struct cmd_list_element *next;
/* Name of this command. */
char *name;
/* Command class; class values are chosen by application program. */
enum command_class class;
/* Function definition of this command.
Zero for command class names and for help topics that
are not really commands. */
void (*function) ();
# define NO_FUNCTION ((void (*)()) 0 )
/* Documentation of this command (or help topic).
First line is brief documentation; remaining lines form, with it,
the full documentation. First line should end with a period.
Entire string should also end with a period, not a newline. */
char *doc;
/* Auxiliary information.
It is up to the calling program to decide what this means. */
char *aux;
/* Nonzero identifies a prefix command. For them, the address
of the variable containing the list of subcommands. */
struct cmd_list_element **prefixlist;
/* For prefix commands only:
String containing prefix commands to get here: this one
plus any others needed to get to it. Should end in a space.
It is used before the word "command" in describing the
commands reached through this prefix. */
char *prefixname;
/* For prefix commands only:
nonzero means do not get an error if subcommand is not
recognized; call the prefix's own function in that case. */
char allow_unknown;
/* Nonzero says this is an abbreviation, and should not
be mentioned in lists of commands.
This allows "br<tab>" to complete to "break", which it
otherwise wouldn't. */
char abbrev_flag;
/* Completion routine for this command. */
char **(*completer)();
/* Type of "set" or "show" command (or SET_NOT_SET if not "set"
or "show"). */
cmd_types type;
/* Pointer to variable affected by "set" and "show". Doesn't matter
if type is not_set. */
char *var;
/* What kind of variable is *VAR? */
var_types var_type;
/* Pointer to command strings of user-defined commands */
struct command_line *user_commands;
};
/* Forward-declarations of the entry-points of command.c. */
extern struct cmd_list_element *add_cmd ();
extern struct cmd_list_element *add_alias_cmd ();
extern struct cmd_list_element *add_prefix_cmd ();
extern struct cmd_list_element *add_abbrev_prefix_cmd ();
extern struct cmd_list_element *lookup_cmd (), *lookup_cmd_1 ();
extern void add_com ();
extern void add_com_alias ();
extern void add_info ();
extern void add_info_alias ();
extern char **complete_on_cmdlist ();
extern void delete_cmd ();
extern void help_cmd ();
extern struct cmd_list_element *add_set_cmd ();
extern struct cmd_list_element *add_show_from_set ();
/* Do a "set" or "show" command. ARG is NULL if no argument, or the text
of the argument, and FROM_TTY is nonzero if this command is being entered
directly by the user (i.e. these are just like any other
command). C is the command list element for the command. */
extern void do_setshow_command ();
/* Do a "show" command for each thing on a command list. */
extern void cmd_show_list ();
extern void error_no_arg (); /* Print error for missing argument */
extern void dont_repeat (); /* Avoid auto-repeat of command */
#endif /* _COMMAND_H_INCLUDED */

55
gdb/copying.awk Normal file
View file

@ -0,0 +1,55 @@
BEGIN {
FS="\"";
print "/* Do not modify this file; it is created automatically";
print " by copying.awk. */";
print "#include \"defs.h\""
print "#include \"command.h\""
print "extern int immediate_quit;";
print "static void";
print "copying_info ()";
print "{";
print " immediate_quit++;";
}
NR == 1,/^[ ]*NO WARRANTY[ ]*$/ {
if (! ($0 ~ /^[ ]*NO WARRANTY[ ]*$/))
{
printf " printf_filtered (\"";
for (i = 1; i < NF; i++)
printf "%s\\\"", $i;
printf "%s\\n\");\n", $NF;
}
}
/^[ ]*NO WARRANTY[ ]*$/ {
print " immediate_quit--;";
print "}";
print "";
print "static void";
print "warranty_info ()";
print "{";
print " immediate_quit++;";
}
/^[ ]*NO WARRANTY[ ]*$/, /^[ ]*END OF TERMS AND CONDITIONS[ ]*$/{
if (! ($0 ~ /^[ ]*END OF TERMS AND CONDITIONS[ ]*$/))
{
printf " printf_filtered (\"";
for (i = 1; i < NF; i++)
printf "%s\\\"", $i;
printf "%s\\n\");\n", $NF;
}
}
END {
print " immediate_quit--;";
print "}";
print "";
print "void"
print "_initialize_copying ()";
print "{";
print " add_info (\"copying\", copying_info,";
print " \"Conditions for redistributing copies of GDB.\");";
print " add_info (\"warranty\", warranty_info,";
print " \"Various kinds of warranty you do not have.\");";
print "}";
}

217
gdb/copying.c Normal file
View file

@ -0,0 +1,217 @@
/* Do not modify this file; it is created automatically
by copying.awk. */
#include "defs.h"
#include "command.h"
extern int immediate_quit;
static void
copying_info ()
{
immediate_quit++;
printf_filtered ("\n");
printf_filtered (" GNU GENERAL PUBLIC LICENSE\n");
printf_filtered (" Version 1, February 1989\n");
printf_filtered ("\n");
printf_filtered (" Copyright (C) 1989 Free Software Foundation, Inc.\n");
printf_filtered (" 675 Mass Ave, Cambridge, MA 02139, USA\n");
printf_filtered (" Everyone is permitted to copy and distribute verbatim copies\n");
printf_filtered (" of this license document, but changing it is not allowed.\n");
printf_filtered ("\n");
printf_filtered (" Preamble\n");
printf_filtered ("\n");
printf_filtered (" The license agreements of most software companies try to keep users\n");
printf_filtered ("at the mercy of those companies. By contrast, our General Public\n");
printf_filtered ("License is intended to guarantee your freedom to share and change free\n");
printf_filtered ("software--to make sure the software is free for all its users. The\n");
printf_filtered ("General Public License applies to the Free Software Foundation's\n");
printf_filtered ("software and to any other program whose authors commit to using it.\n");
printf_filtered ("You can use it for your programs, too.\n");
printf_filtered ("\n");
printf_filtered (" When we speak of free software, we are referring to freedom, not\n");
printf_filtered ("price. Specifically, the General Public License is designed to make\n");
printf_filtered ("sure that you have the freedom to give away or sell copies of free\n");
printf_filtered ("software, that you receive source code or can get it if you want it,\n");
printf_filtered ("that you can change the software or use pieces of it in new free\n");
printf_filtered ("programs; and that you know you can do these things.\n");
printf_filtered ("\n");
printf_filtered (" To protect your rights, we need to make restrictions that forbid\n");
printf_filtered ("anyone to deny you these rights or to ask you to surrender the rights.\n");
printf_filtered ("These restrictions translate to certain responsibilities for you if you\n");
printf_filtered ("distribute copies of the software, or if you modify it.\n");
printf_filtered ("\n");
printf_filtered (" For example, if you distribute copies of a such a program, whether\n");
printf_filtered ("gratis or for a fee, you must give the recipients all the rights that\n");
printf_filtered ("you have. You must make sure that they, too, receive or can get the\n");
printf_filtered ("source code. And you must tell them their rights.\n");
printf_filtered ("\n");
printf_filtered (" We protect your rights with two steps: (1) copyright the software, and\n");
printf_filtered ("(2) offer you this license which gives you legal permission to copy,\n");
printf_filtered ("distribute and/or modify the software.\n");
printf_filtered ("\n");
printf_filtered (" Also, for each author's protection and ours, we want to make certain\n");
printf_filtered ("that everyone understands that there is no warranty for this free\n");
printf_filtered ("software. If the software is modified by someone else and passed on, we\n");
printf_filtered ("want its recipients to know that what they have is not the original, so\n");
printf_filtered ("that any problems introduced by others will not reflect on the original\n");
printf_filtered ("authors' reputations.\n");
printf_filtered ("\n");
printf_filtered (" The precise terms and conditions for copying, distribution and\n");
printf_filtered ("modification follow.\n");
printf_filtered (" \n");
printf_filtered (" GNU GENERAL PUBLIC LICENSE\n");
printf_filtered (" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n");
printf_filtered ("\n");
printf_filtered (" 0. This License Agreement applies to any program or other work which\n");
printf_filtered ("contains a notice placed by the copyright holder saying it may be\n");
printf_filtered ("distributed under the terms of this General Public License. The\n");
printf_filtered ("\"Program\", below, refers to any such program or work, and a \"work based\n");
printf_filtered ("on the Program\" means either the Program or any work containing the\n");
printf_filtered ("Program or a portion of it, either verbatim or with modifications. Each\n");
printf_filtered ("licensee is addressed as \"you\".\n");
printf_filtered ("\n");
printf_filtered (" 1. You may copy and distribute verbatim copies of the Program's source\n");
printf_filtered ("code as you receive it, in any medium, provided that you conspicuously and\n");
printf_filtered ("appropriately publish on each copy an appropriate copyright notice and\n");
printf_filtered ("disclaimer of warranty; keep intact all the notices that refer to this\n");
printf_filtered ("General Public License and to the absence of any warranty; and give any\n");
printf_filtered ("other recipients of the Program a copy of this General Public License\n");
printf_filtered ("along with the Program. You may charge a fee for the physical act of\n");
printf_filtered ("transferring a copy.\n");
printf_filtered ("\n");
printf_filtered (" 2. You may modify your copy or copies of the Program or any portion of\n");
printf_filtered ("it, and copy and distribute such modifications under the terms of Paragraph\n");
printf_filtered ("1 above, provided that you also do the following:\n");
printf_filtered ("\n");
printf_filtered (" a) cause the modified files to carry prominent notices stating that\n");
printf_filtered (" you changed the files and the date of any change; and\n");
printf_filtered ("\n");
printf_filtered (" b) cause the whole of any work that you distribute or publish, that\n");
printf_filtered (" in whole or in part contains the Program or any part thereof, either\n");
printf_filtered (" with or without modifications, to be licensed at no charge to all\n");
printf_filtered (" third parties under the terms of this General Public License (except\n");
printf_filtered (" that you may choose to grant warranty protection to some or all\n");
printf_filtered (" third parties, at your option).\n");
printf_filtered ("\n");
printf_filtered (" c) If the modified program normally reads commands interactively when\n");
printf_filtered (" run, you must cause it, when started running for such interactive use\n");
printf_filtered (" in the simplest and most usual way, to print or display an\n");
printf_filtered (" announcement including an appropriate copyright notice and a notice\n");
printf_filtered (" that there is no warranty (or else, saying that you provide a\n");
printf_filtered (" warranty) and that users may redistribute the program under these\n");
printf_filtered (" conditions, and telling the user how to view a copy of this General\n");
printf_filtered (" Public License.\n");
printf_filtered ("\n");
printf_filtered (" d) You may charge a fee for the physical act of transferring a\n");
printf_filtered (" copy, and you may at your option offer warranty protection in\n");
printf_filtered (" exchange for a fee.\n");
printf_filtered ("\n");
printf_filtered ("Mere aggregation of another independent work with the Program (or its\n");
printf_filtered ("derivative) on a volume of a storage or distribution medium does not bring\n");
printf_filtered ("the other work under the scope of these terms.\n");
printf_filtered (" \n");
printf_filtered (" 3. You may copy and distribute the Program (or a portion or derivative of\n");
printf_filtered ("it, under Paragraph 2) in object code or executable form under the terms of\n");
printf_filtered ("Paragraphs 1 and 2 above provided that you also do one of the following:\n");
printf_filtered ("\n");
printf_filtered (" a) accompany it with the complete corresponding machine-readable\n");
printf_filtered (" source code, which must be distributed under the terms of\n");
printf_filtered (" Paragraphs 1 and 2 above; or,\n");
printf_filtered ("\n");
printf_filtered (" b) accompany it with a written offer, valid for at least three\n");
printf_filtered (" years, to give any third party free (except for a nominal charge\n");
printf_filtered (" for the cost of distribution) a complete machine-readable copy of the\n");
printf_filtered (" corresponding source code, to be distributed under the terms of\n");
printf_filtered (" Paragraphs 1 and 2 above; or,\n");
printf_filtered ("\n");
printf_filtered (" c) accompany it with the information you received as to where the\n");
printf_filtered (" corresponding source code may be obtained. (This alternative is\n");
printf_filtered (" allowed only for noncommercial distribution and only if you\n");
printf_filtered (" received the program in object code or executable form alone.)\n");
printf_filtered ("\n");
printf_filtered ("Source code for a work means the preferred form of the work for making\n");
printf_filtered ("modifications to it. For an executable file, complete source code means\n");
printf_filtered ("all the source code for all modules it contains; but, as a special\n");
printf_filtered ("exception, it need not include source code for modules which are standard\n");
printf_filtered ("libraries that accompany the operating system on which the executable\n");
printf_filtered ("file runs, or for standard header files or definitions files that\n");
printf_filtered ("accompany that operating system.\n");
printf_filtered ("\n");
printf_filtered (" 4. You may not copy, modify, sublicense, distribute or transfer the\n");
printf_filtered ("Program except as expressly provided under this General Public License.\n");
printf_filtered ("Any attempt otherwise to copy, modify, sublicense, distribute or transfer\n");
printf_filtered ("the Program is void, and will automatically terminate your rights to use\n");
printf_filtered ("the Program under this License. However, parties who have received\n");
printf_filtered ("copies, or rights to use copies, from you under this General Public\n");
printf_filtered ("License will not have their licenses terminated so long as such parties\n");
printf_filtered ("remain in full compliance.\n");
printf_filtered ("\n");
printf_filtered (" 5. By copying, distributing or modifying the Program (or any work based\n");
printf_filtered ("on the Program) you indicate your acceptance of this license to do so,\n");
printf_filtered ("and all its terms and conditions.\n");
printf_filtered ("\n");
printf_filtered (" 6. Each time you redistribute the Program (or any work based on the\n");
printf_filtered ("Program), the recipient automatically receives a license from the original\n");
printf_filtered ("licensor to copy, distribute or modify the Program subject to these\n");
printf_filtered ("terms and conditions. You may not impose any further restrictions on the\n");
printf_filtered ("recipients' exercise of the rights granted herein.\n");
printf_filtered (" \n");
printf_filtered (" 7. The Free Software Foundation may publish revised and/or new versions\n");
printf_filtered ("of the General Public License from time to time. Such new versions will\n");
printf_filtered ("be similar in spirit to the present version, but may differ in detail to\n");
printf_filtered ("address new problems or concerns.\n");
printf_filtered ("\n");
printf_filtered ("Each version is given a distinguishing version number. If the Program\n");
printf_filtered ("specifies a version number of the license which applies to it and \"any\n");
printf_filtered ("later version\", you have the option of following the terms and conditions\n");
printf_filtered ("either of that version or of any later version published by the Free\n");
printf_filtered ("Software Foundation. If the Program does not specify a version number of\n");
printf_filtered ("the license, you may choose any version ever published by the Free Software\n");
printf_filtered ("Foundation.\n");
printf_filtered ("\n");
printf_filtered (" 8. If you wish to incorporate parts of the Program into other free\n");
printf_filtered ("programs whose distribution conditions are different, write to the author\n");
printf_filtered ("to ask for permission. For software which is copyrighted by the Free\n");
printf_filtered ("Software Foundation, write to the Free Software Foundation; we sometimes\n");
printf_filtered ("make exceptions for this. Our decision will be guided by the two goals\n");
printf_filtered ("of preserving the free status of all derivatives of our free software and\n");
printf_filtered ("of promoting the sharing and reuse of software generally.\n");
printf_filtered ("\n");
immediate_quit--;
}
static void
warranty_info ()
{
immediate_quit++;
printf_filtered (" NO WARRANTY\n");
printf_filtered ("\n");
printf_filtered (" 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n");
printf_filtered ("FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n");
printf_filtered ("OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n");
printf_filtered ("PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n");
printf_filtered ("OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n");
printf_filtered ("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n");
printf_filtered ("TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n");
printf_filtered ("PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n");
printf_filtered ("REPAIR OR CORRECTION.\n");
printf_filtered ("\n");
printf_filtered (" 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n");
printf_filtered ("WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n");
printf_filtered ("REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n");
printf_filtered ("INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n");
printf_filtered ("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n");
printf_filtered ("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n");
printf_filtered ("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n");
printf_filtered ("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n");
printf_filtered ("POSSIBILITY OF SUCH DAMAGES.\n");
printf_filtered ("\n");
immediate_quit--;
}
void
_initialize_copying ()
{
add_info ("copying", copying_info,
"Conditions for redistributing copies of GDB.");
add_info ("warranty", warranty_info,
"Various kinds of warranty you do not have.");
}

5348
gdb/dbxread.c Normal file

File diff suppressed because it is too large Load diff

173
gdb/defs.h Normal file
View file

@ -0,0 +1,173 @@
/* Basic definitions for GDB, the GNU debugger.
Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* An address in the program being debugged. Host byte order. */
typedef unsigned int CORE_ADDR;
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
/* The character C++ uses to build identifiers that must be unique from
the program's identifiers (such as $this and $$vptr). */
#define CPLUS_MARKER '$' /* May be overridden to '.' for SysV */
/*
* Allow things in gdb to be declared "const". If compiling ANSI, it
* just works. If compiling with gcc but non-ansi, redefine to __const__.
* If non-ansi, non-gcc, then eliminate "const" entirely, making those
* objects be read-write rather than read-only.
*/
#ifndef __STDC__
# ifdef __GNUC__
# define const __const__
# define volatile __volatile__
# else
# define const /*nothing*/
# define volatile /*nothing*/
# endif /* GNUC */
#endif /* STDC */
extern char *savestring ();
extern char *strsave ();
extern char *concat ();
#ifdef __STDC__
extern void *xmalloc (), *xrealloc ();
#else
extern char *xmalloc (), *xrealloc ();
#endif
extern void free ();
extern int parse_escape ();
extern char *reg_names[];
/* Indicate that these routines do not return to the caller. */
extern volatile void error(), fatal();
/* Various possibilities for alloca. */
#ifdef __GNUC__
# define alloca __builtin_alloca
#else
# ifdef sparc
# include <alloca.h>
# endif
extern char *alloca ();
# endif
extern int errno; /* System call error return status */
extern int quit_flag;
extern int immediate_quit;
extern void quit ();
#define QUIT { if (quit_flag) quit (); }
/* Notes on classes: class_alias is for alias commands which are not
abbreviations of the original command. */
enum command_class
{
/* Special args to help_list */
all_classes = -2, all_commands = -1,
/* Classes of commands */
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
if an error happens (descriptors to be closed, memory to be freed, etc.)
Each link in the chain records a function to call and an
argument to give it.
Use make_cleanup to add an element to the cleanup chain.
Use do_cleanups to do all cleanup actions back to a given
point in the chain. Use discard_cleanups to remove cleanups
from the chain back to a given point, not doing them. */
struct cleanup
{
struct cleanup *next;
void (*function) ();
int arg;
};
/* From utils.c. */
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 ();
extern int myread ();
extern int query ();
extern int lines_to_list ();
extern void reinitialize_more_filter ();
extern void fputs_filtered ();
extern void puts_filtered ();
extern void fprintf_filtered ();
extern void printf_filtered ();
extern void print_spaces ();
extern void print_spaces_filtered ();
extern char *n_spaces ();
extern void printchar ();
extern void fprint_symbol ();
extern void fputs_demangled ();
extern void perror_with_name ();
extern void print_sys_errmsg ();
/* From printcmd.c */
extern void print_address_symbolic ();
extern void print_address ();
/* From readline (but not in any readline .h files). */
extern char *tilde_expand ();
/* Structure for saved commands lines
(for breakpoints, defined commands, etc). */
struct command_line
{
struct command_line *next;
char *line;
};
extern struct command_line *read_command_lines ();
extern void free_command_lines ();
/* String containing the current directory (what getwd would return). */
char *current_directory;
/* Default radixes for input and output. Only some values supported. */
extern unsigned input_radix;
extern unsigned output_radix;
/* Baud rate specified for communication with serial target systems. */
char *baud_rate;
#if !defined (UINT_MAX)
#define UINT_MAX 0xffffffff
#endif
#if !defined (LONG_MAX)
#define LONG_MAX 0x7fffffff
#endif
/* Just like CHAR_BIT in <limits.h> but describes the target machine. */
#if !defined (TARGET_CHAR_BIT)
#define TARGET_CHAR_BIT 8
#endif

187
gdb/environ.c Normal file
View file

@ -0,0 +1,187 @@
/* environ.c -- library for manipulating environments for GNU.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#include "environ.h"
#include <string.h>
extern char *xmalloc ();
extern char *xrealloc ();
extern void free ();
/* Return a new environment object. */
struct environ *
make_environ ()
{
register struct environ *e;
e = (struct environ *) xmalloc (sizeof (struct environ));
e->allocated = 10;
e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *));
e->vector[0] = 0;
return e;
}
/* Free an environment and all the strings in it. */
void
free_environ (e)
register struct environ *e;
{
register char **vector = e->vector;
while (*vector)
free (*vector++);
free (e);
}
/* Copy the environment given to this process into E.
Also copies all the strings in it, so we can be sure
that all strings in these environments are safe to free. */
void
init_environ (e)
register struct environ *e;
{
extern char **environ;
register int i;
for (i = 0; environ[i]; i++) /*EMPTY*/;
if (e->allocated < i)
{
e->allocated = max (i, e->allocated + 10);
e->vector = (char **) xrealloc ((char *)e->vector,
(e->allocated + 1) * sizeof (char *));
}
bcopy (environ, e->vector, (i + 1) * sizeof (char *));
while (--i >= 0)
{
register int len = strlen (e->vector[i]);
register char *new = (char *) xmalloc (len + 1);
bcopy (e->vector[i], new, len + 1);
e->vector[i] = new;
}
}
/* Return the vector of environment E.
This is used to get something to pass to execve. */
char **
environ_vector (e)
struct environ *e;
{
return e->vector;
}
/* Return the value in environment E of variable VAR. */
char *
get_in_environ (e, var)
struct environ *e;
char *var;
{
register int len = strlen (var);
register char **vector = e->vector;
register char *s;
for (; s = *vector; vector++)
if (!strncmp (s, var, len)
&& s[len] == '=')
return &s[len + 1];
return 0;
}
/* Store the value in E of VAR as VALUE. */
void
set_in_environ (e, var, value)
struct environ *e;
char *var;
char *value;
{
register int i;
register int len = strlen (var);
register char **vector = e->vector;
register char *s;
for (i = 0; s = vector[i]; i++)
if (!strncmp (s, var, len)
&& s[len] == '=')
break;
if (s == 0)
{
if (i == e->allocated)
{
e->allocated += 10;
vector = (char **) xrealloc ((char *)vector,
(e->allocated + 1) * sizeof (char *));
e->vector = vector;
}
vector[i + 1] = 0;
}
else
free (s);
s = (char *) xmalloc (len + strlen (value) + 2);
strcpy (s, var);
strcat (s, "=");
strcat (s, value);
vector[i] = s;
/* Certain variables get exported back to the parent (e.g. our)
environment, too. */
if (!strcmp(var, "PATH") /* Object file location */
|| !strcmp (var, "G960BASE") /* Intel 960 downloads */
|| !strcmp (var, "G960BIN") /* Intel 960 downloads */
) {
putenv (strsave (s));
}
return;
}
/* Remove the setting for variable VAR from environment E. */
void
unset_in_environ (e, var)
struct environ *e;
char *var;
{
register int len = strlen (var);
register char **vector = e->vector;
register char *s;
for (; s = *vector; vector++)
if (!strncmp (s, var, len)
&& s[len] == '=')
{
free (s);
bcopy (vector + 1, vector,
(e->allocated - (vector - e->vector)) * sizeof (char *));
e->vector[e->allocated - 1] = 0;
return;
}
}

39
gdb/environ.h Normal file
View file

@ -0,0 +1,39 @@
/* Header for environment manipulation library.
Copyright (C) 1989, Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* We manipulate environments represented as these structures. */
struct environ
{
/* Number of usable slots allocated in VECTOR.
VECTOR always has one slot not counted here,
to hold the terminating zero. */
int allocated;
/* A vector of slots, ALLOCATED + 1 of them.
The first few slots contain strings "VAR=VALUE"
and the next one contains zero.
Then come some unused slots. */
char **vector;
};
struct environ *make_environ ();
void free_environ ();
void init_environ ();
char *get_in_environ ();
void set_in_environ ();
void unset_in_environ ();
char **environ_vector ();

1042
gdb/eval.c Normal file

File diff suppressed because it is too large Load diff

350
gdb/exec.c Normal file
View file

@ -0,0 +1,350 @@
/* Work with executable files, for GDB.
Copyright (C) 1988, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <fcntl.h>
#include "gdbcore.h"
#ifdef STILL_NEEDED_FOR_DECSTATION
#include <sys/dir.h> /* For DECstations */
#include <sys/user.h> /* After a.out.h */
#include <sys/file.h>
#endif
#include <sys/stat.h>
extern char *getenv();
extern void child_create_inferior (), child_attach ();
extern void symbol_file_command ();
/* The Binary File Descriptor handle for the executable file. */
bfd *exec_bfd = NULL;
/* The base and bounds of the table of the exec file's sections. */
struct section_table *exec_sections, *exec_sections_end;
/* Forward decl */
extern struct target_ops exec_ops;
void
exec_close (quitting)
int quitting;
{
if (exec_bfd) {
bfd_close (exec_bfd);
exec_bfd = NULL;
}
}
void
exec_file_command (filename, from_tty)
char *filename;
int from_tty;
{
/* Remove any previous exec file. */
unpush_target (&exec_ops);
/* Now open and digest the file the user requested, if any. */
if (filename)
{
char *scratch_pathname;
int scratch_chan;
filename = tilde_expand (filename);
make_cleanup (free, filename);
/* FIXME, if writeable is set, open for read/write. */
scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
&scratch_pathname);
if (scratch_chan < 0)
perror_with_name (filename);
exec_bfd = bfd_fdopenr (scratch_pathname, NULL, scratch_chan);
if (!exec_bfd)
error ("Could not open `%s' as an executable file: %s",
scratch_pathname, bfd_errmsg (bfd_error));
if (!bfd_check_format (exec_bfd, bfd_object))
error ("\"%s\": not in executable format: %s.",
scratch_pathname, bfd_errmsg (bfd_error));
#if FIXME
/* This code needs to be incorporated into BFD */
#ifdef COFF_ENCAPSULATE
/* If we have a coff header, it can give us better values for
text_start and exec_data_start. This is particularly useful
for remote debugging of embedded systems. */
if (N_FLAGS(exec_aouthdr) & N_FLAGS_COFF_ENCAPSULATE)
{
struct coffheader ch;
int val;
val = lseek (execchan, -(sizeof (AOUTHDR) + sizeof (ch)), 1);
if (val == -1)
perror_with_name (filename);
val = myread (execchan, &ch, sizeof (ch));
if (val < 0)
perror_with_name (filename);
text_start = ch.text_start;
exec_data_start = ch.data_start;
} else
#endif
{
text_start =
IS_OBJECT_FILE (exec_aouthdr) ? 0 : N_TXTADDR (exec_aouthdr);
exec_data_start = IS_OBJECT_FILE (exec_aouthdr)
? exec_aouthdr.a_text : N_DATADDR (exec_aouthdr);
}
#endif FIXME
if (build_section_table (exec_bfd, &exec_sections, &exec_sections_end))
error ("Can't find the file sections in `%s': %s",
exec_bfd->filename, bfd_errmsg (bfd_error));
validate_files ();
push_target (&exec_ops);
/* Tell display code (if any) about the changed file name. */
if (exec_file_display_hook)
(*exec_file_display_hook) (filename);
}
else if (from_tty)
printf ("No exec file now.\n");
}
/* Set both the exec file and the symbol file, in one command.
What a novelty. Why did GDB go through four major releases before this
command was added? */
void
file_command (arg, from_tty)
char *arg;
int from_tty;
{
/* FIXME, if we lose on reading the symbol file, we should revert
the exec file, but that's rough. */
exec_file_command (arg, from_tty);
symbol_file_command (arg, from_tty);
}
/* Locate all mappable sections of a BFD file. */
void
add_to_section_table (abfd, asect, table_pp)
bfd *abfd;
sec_ptr asect;
struct section_table **table_pp;
{
flagword aflag;
aflag = bfd_get_section_flags (abfd, asect);
/* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */
if (!(aflag & SEC_LOAD))
return;
(*table_pp)->sec_ptr = asect;
(*table_pp)->addr = bfd_section_vma (abfd, asect);
(*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect);
(*table_pp)++;
}
int
build_section_table (some_bfd, start, end)
bfd *some_bfd;
struct section_table **start, **end;
{
unsigned count;
count = bfd_count_sections (some_bfd);
if (count == 0)
abort(); /* return 1? */
*start = (struct section_table *) xmalloc (count * sizeof (**start));
*end = *start;
bfd_map_over_sections (some_bfd, add_to_section_table, end);
if (*end > *start + count)
abort();
/* We could realloc the table, but it probably loses for most files. */
return 0;
}
/* Read or write the exec file.
Args are address within exec file, address within gdb address-space,
length, and a flag indicating whether to read or write.
Result is a length:
0: We cannot handle this address and length.
> 0: We have handled N bytes starting at this address.
(If N == length, we did it all.) We might be able
to handle more bytes beyond this length, but no
promises.
< 0: We cannot handle this address, but if somebody
else handles (-N) bytes, we can start from there.
The same routine is used to handle both core and exec files;
we just tail-call it with more arguments to select between them. */
int
xfer_memory (memaddr, myaddr, len, write, abfd, sections, sections_end)
CORE_ADDR memaddr;
char *myaddr;
int len;
int write;
bfd *abfd;
struct section_table *sections, *sections_end;
{
boolean res;
struct section_table *p;
CORE_ADDR nextsectaddr, memend;
boolean (*xfer_fn) ();
if (len <= 0)
abort();
memend = memaddr + len;
xfer_fn = write? bfd_set_section_contents: bfd_get_section_contents;
nextsectaddr = memend;
for (p = sections; p < sections_end; p++)
{
if (p->addr <= memaddr)
if (p->endaddr >= memend)
{
/* Entire transfer is within this section. */
res = xfer_fn (abfd, p->sec_ptr, myaddr, memaddr - p->addr, len);
return (res != false)? len: 0;
}
else if (p->endaddr <= memaddr)
{
/* This section ends before the transfer starts. */
continue;
}
else
{
/* This section overlaps the transfer. Just do half. */
len = p->endaddr - memaddr;
res = xfer_fn (abfd, p->sec_ptr, myaddr, memaddr - p->addr, len);
return (res != false)? len: 0;
}
else if (p->addr < nextsectaddr)
nextsectaddr = p->addr;
}
if (nextsectaddr >= memend)
return 0; /* We can't help */
else
return - (nextsectaddr - memaddr); /* Next boundary where we can help */
}
/* The function called by target_xfer_memory via our target_ops */
int
exec_xfer_memory (memaddr, myaddr, len, write)
CORE_ADDR memaddr;
char *myaddr;
int len;
int write;
{
return xfer_memory (memaddr, myaddr, len, write,
exec_bfd, exec_sections, exec_sections_end);
}
#ifdef FIXME
#ifdef REG_STACK_SEGMENT
/* MOVE TO BFD... */
/* Pyramids and AM29000s have an extra segment in the virtual address space
for the (control) stack of register-window frames. The AM29000 folk
call it the "register stack" rather than the "memory stack". */
else if (memaddr >= reg_stack_start && memaddr < reg_stack_end)
{
i = min (len, reg_stack_end - memaddr);
fileptr = memaddr - reg_stack_start + reg_stack_offset;
wanna_xfer = coredata;
}
#endif /* REG_STACK_SEGMENT */
#endif FIXME
static void
exec_files_info ()
{
struct section_table *p;
printf ("\tExecutable file `%s'.\n", bfd_get_filename(exec_bfd));
for (p = exec_sections; p < exec_sections_end; p++)
printf("\texecutable from 0x%08x to 0x%08x is %s\n",
p->addr, p->endaddr,
bfd_section_name (exec_bfd, p->sec_ptr));
}
struct target_ops exec_ops = {
"exec", "Local exec file",
exec_file_command, exec_close, /* open, close */
child_attach, 0, 0, 0, /* attach, detach, resume, wait, */
0, 0, /* fetch_registers, store_registers, */
0, 0, 0, /* prepare_to_store, conv_to, conv_from, */
exec_xfer_memory, exec_files_info,
0, 0, /* insert_breakpoint, remove_breakpoint, */
0, 0, 0, 0, 0, /* terminal stuff */
0, 0, 0, 0, 0, /* kill, load, add_syms, call fn, lookup sym */
child_create_inferior,
0, /* mourn_inferior */
file_stratum, 0, /* next */
0, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */
OPS_MAGIC, /* Always the last thing */
};
void
_initialize_exec()
{
add_com ("file", class_files, file_command,
"Use FILE as program to be debugged.\n\
It is read for its symbols, for getting the contents of pure memory,\n\
and it is the program executed when you use the `run' command.\n\
If FILE cannot be found as specified, your execution directory path\n\
($PATH) is searched for a command of that name.\n\
No arg means to have no executable file and no symbols.");
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_target (&exec_ops);
}

324
gdb/expprint.c Normal file
View file

@ -0,0 +1,324 @@
/* Print in infix form a struct expression.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "symtab.h"
#include "param.h"
#include "expression.h"
#include "value.h"
/* These codes indicate operator precedences, least tightly binding first. */
/* Adding 1 to a precedence value is done for binary operators,
on the operand which is more tightly bound, so that operators
of equal precedence within that operand will get parentheses. */
/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator;
they are used as the "surrounding precedence" to force
various kinds of things to be parenthesized. */
enum precedence
{ PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_OR, PREC_AND,
PREC_LOGIOR, PREC_LOGAND, PREC_LOGXOR, PREC_EQUAL, PREC_ORDER,
PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT,
PREC_HYPER, PREC_PREFIX, PREC_SUFFIX };
/* Table mapping opcodes into strings for printing operators
and precedences of the operators. */
struct op_print
{
char *string;
enum exp_opcode opcode;
/* Precedence of operator. These values are used only by comparisons. */
enum precedence precedence;
int right_assoc;
};
static struct op_print op_print_tab[] =
{
{",", BINOP_COMMA, PREC_COMMA, 0},
{"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
{"||", BINOP_OR, PREC_OR, 0},
{"&&", BINOP_AND, PREC_AND, 0},
{"|", BINOP_LOGIOR, PREC_LOGIOR, 0},
{"&", BINOP_LOGAND, PREC_LOGAND, 0},
{"^", BINOP_LOGXOR, PREC_LOGXOR, 0},
{"==", BINOP_EQUAL, PREC_EQUAL, 0},
{"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
{"<=", BINOP_LEQ, PREC_ORDER, 0},
{">=", BINOP_GEQ, PREC_ORDER, 0},
{">", BINOP_GTR, PREC_ORDER, 0},
{"<", BINOP_LESS, PREC_ORDER, 0},
{">>", BINOP_RSH, PREC_SHIFT, 0},
{"<<", BINOP_LSH, PREC_SHIFT, 0},
{"+", BINOP_ADD, PREC_ADD, 0},
{"-", BINOP_SUB, PREC_ADD, 0},
{"*", BINOP_MUL, PREC_MUL, 0},
{"/", BINOP_DIV, PREC_MUL, 0},
{"%", BINOP_REM, PREC_MUL, 0},
{"@", BINOP_REPEAT, PREC_REPEAT, 0},
{"-", UNOP_NEG, PREC_PREFIX, 0},
{"!", UNOP_ZEROP, PREC_PREFIX, 0},
{"~", UNOP_LOGNOT, PREC_PREFIX, 0},
{"*", UNOP_IND, PREC_PREFIX, 0},
{"&", UNOP_ADDR, PREC_PREFIX, 0},
{"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
{"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
{"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
/* C++ */
{"::", BINOP_SCOPE, PREC_PREFIX, 0},
};
static void print_subexp ();
void
print_expression (exp, stream)
struct expression *exp;
FILE *stream;
{
int pc = 0;
print_subexp (exp, &pc, stream, PREC_NULL);
}
/* Print the subexpression of EXP that starts in position POS, on STREAM.
PREC is the precedence of the surrounding operator;
if the precedence of the main operator of this subexpression is less,
parentheses are needed here. */
static void
print_subexp (exp, pos, stream, prec)
register struct expression *exp;
register int *pos;
FILE *stream;
enum precedence prec;
{
register unsigned tem;
register int pc;
unsigned nargs;
register char *op_str;
int assign_modify = 0;
enum exp_opcode opcode;
enum precedence myprec;
/* Set to 1 for a right-associative operator. */
int assoc;
pc = (*pos)++;
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,
exp->elts[pc + 2].longconst),
stream, 0, Val_no_prettyprint);
return;
case OP_DOUBLE:
(*pos) += 3;
value_print (value_from_double (exp->elts[pc + 1].type,
exp->elts[pc + 2].doubleconst),
stream, 0, Val_no_prettyprint);
return;
case OP_VAR_VALUE:
(*pos) += 2;
fprintf (stream, "%s", SYMBOL_NAME (exp->elts[pc + 1].symbol));
return;
case OP_LAST:
(*pos) += 2;
fprintf (stream, "$%d", (int) exp->elts[pc + 1].longconst);
return;
case OP_REGISTER:
(*pos) += 2;
fprintf (stream, "$%s", reg_names[exp->elts[pc + 1].longconst]);
return;
case OP_INTERNALVAR:
(*pos) += 2;
fprintf (stream, "$%s",
internalvar_name (exp->elts[pc + 1].internalvar));
return;
case OP_FUNCALL:
(*pos) += 2;
nargs = exp->elts[pc + 1].longconst;
print_subexp (exp, pos, stream, PREC_SUFFIX);
fprintf (stream, " (");
for (tem = 0; tem < nargs; tem++)
{
if (tem != 0)
fprintf (stream, ", ");
print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
}
fprintf (stream, ")");
return;
case OP_STRING:
nargs = strlen (&exp->elts[pc + 1].string);
(*pos) += 2 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element);
fprintf (stream, "\"");
for (tem = 0; tem < nargs; tem++)
printchar ((&exp->elts[pc + 1].string)[tem], stream, '"');
fprintf (stream, "\"");
return;
case TERNOP_COND:
if ((int) prec > (int) PREC_COMMA)
fprintf (stream, "(");
/* Print the subexpressions, forcing parentheses
around any binary operations within them.
This is more parentheses than are strictly necessary,
but it looks clearer. */
print_subexp (exp, pos, stream, PREC_HYPER);
fprintf (stream, " ? ");
print_subexp (exp, pos, stream, PREC_HYPER);
fprintf (stream, " : ");
print_subexp (exp, pos, stream, PREC_HYPER);
if ((int) prec > (int) PREC_COMMA)
fprintf (stream, ")");
return;
case STRUCTOP_STRUCT:
tem = strlen (&exp->elts[pc + 1].string);
(*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
print_subexp (exp, pos, stream, PREC_SUFFIX);
fprintf (stream, ".%s", &exp->elts[pc + 1].string);
return;
case STRUCTOP_PTR:
tem = strlen (&exp->elts[pc + 1].string);
(*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
print_subexp (exp, pos, stream, PREC_SUFFIX);
fprintf (stream, "->%s", &exp->elts[pc + 1].string);
return;
case BINOP_SUBSCRIPT:
print_subexp (exp, pos, stream, PREC_SUFFIX);
fprintf (stream, "[");
print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
fprintf (stream, "]");
return;
case UNOP_POSTINCREMENT:
print_subexp (exp, pos, stream, PREC_SUFFIX);
fprintf (stream, "++");
return;
case UNOP_POSTDECREMENT:
print_subexp (exp, pos, stream, PREC_SUFFIX);
fprintf (stream, "--");
return;
case UNOP_CAST:
(*pos) += 2;
if ((int) prec > (int) PREC_PREFIX)
fprintf (stream, "(");
fprintf (stream, "(");
type_print (exp->elts[pc + 1].type, "", stream, 0);
fprintf (stream, ") ");
print_subexp (exp, pos, stream, PREC_PREFIX);
if ((int) prec > (int) PREC_PREFIX)
fprintf (stream, ")");
return;
case UNOP_MEMVAL:
(*pos) += 2;
if ((int) prec > (int) PREC_PREFIX)
fprintf (stream, "(");
fprintf (stream, "{");
type_print (exp->elts[pc + 1].type, "", stream, 0);
fprintf (stream, "} ");
print_subexp (exp, pos, stream, PREC_PREFIX);
if ((int) prec > (int) PREC_PREFIX)
fprintf (stream, ")");
return;
case BINOP_ASSIGN_MODIFY:
opcode = exp->elts[pc + 1].opcode;
(*pos) += 2;
myprec = PREC_ASSIGN;
assoc = 1;
assign_modify = 1;
for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++)
if (op_print_tab[tem].opcode == opcode)
{
op_str = op_print_tab[tem].string;
break;
}
case OP_THIS:
++(*pos);
fprintf (stream, "this");
return;
default:
for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++)
if (op_print_tab[tem].opcode == opcode)
{
op_str = op_print_tab[tem].string;
myprec = op_print_tab[tem].precedence;
assoc = op_print_tab[tem].right_assoc;
break;
}
}
if ((int) myprec < (int) prec)
fprintf (stream, "(");
if ((int) opcode > (int) BINOP_END)
{
/* Unary prefix operator. */
fprintf (stream, "%s", op_str);
print_subexp (exp, pos, stream, PREC_PREFIX);
}
else
{
/* Binary operator. */
/* Print left operand.
If operator is right-associative,
increment precedence for this operand. */
print_subexp (exp, pos, stream, (int) myprec + assoc);
/* Print the operator itself. */
if (assign_modify)
fprintf (stream, " %s= ", op_str);
else if (op_str[0] == ',')
fprintf (stream, "%s ", op_str);
else
fprintf (stream, " %s ", op_str);
/* Print right operand.
If operator is left-associative,
increment precedence for this operand. */
print_subexp (exp, pos, stream, (int) myprec + !assoc);
}
if ((int) myprec < (int) prec)
fprintf (stream, ")");
}

200
gdb/expression.h Normal file
View file

@ -0,0 +1,200 @@
/* Definitions for expressions stored in reversed prefix form, for GDB.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Definitions for saved C expressions. */
/* An expression is represented as a vector of union exp_element's.
Each exp_element is an opcode, except that some opcodes cause
the following exp_element to be treated as a long or double constant
or as a variable. The opcodes are obeyed, using a stack for temporaries.
The value is left on the temporary stack at the end. */
/* When it is necessary to include a string,
it can occupy as many exp_elements as it needs.
We find the length of the string using strlen,
divide to find out how many exp_elements are used up,
and skip that many. Strings, like numbers, are indicated
by the preceding opcode. */
enum exp_opcode
{
/* BINOP_... operate on two values computed by following subexpressions,
replacing them by one result value. They take no immediate arguments. */
BINOP_ADD, /* + */
BINOP_SUB, /* - */
BINOP_MUL, /* * */
BINOP_DIV, /* / */
BINOP_REM, /* % */
BINOP_LSH, /* << */
BINOP_RSH, /* >> */
BINOP_AND, /* && */
BINOP_OR, /* || */
BINOP_LOGAND, /* & */
BINOP_LOGIOR, /* | */
BINOP_LOGXOR, /* ^ */
BINOP_EQUAL, /* == */
BINOP_NOTEQUAL, /* != */
BINOP_LESS, /* < */
BINOP_GTR, /* > */
BINOP_LEQ, /* <= */
BINOP_GEQ, /* >= */
BINOP_REPEAT, /* @ */
BINOP_ASSIGN, /* = */
BINOP_COMMA, /* , */
BINOP_SUBSCRIPT, /* x[y] */
BINOP_EXP, /* Exponentiation */
/* C++. */
BINOP_MIN, /* <? */
BINOP_MAX, /* >? */
BINOP_SCOPE, /* :: */
/* STRUCTOP_MEMBER is used for pointer-to-member constructs.
X . * Y translates into X STRUCTOP_MEMBER Y. */
STRUCTOP_MEMBER,
/* STRUCTOP_MPTR is used for pointer-to-member constructs
when X is a pointer instead of an aggregate. */
STRUCTOP_MPTR,
/* end of C++. */
BINOP_END,
BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on.
The following exp_element is another opcode,
a BINOP_, saying how to modify.
Then comes another BINOP_ASSIGN_MODIFY,
making three exp_elements in total. */
/* Operates on three values computed by following subexpressions. */
TERNOP_COND, /* ?: */
/* The OP_... series take immediate following arguments.
After the arguments come another OP_... (the same one)
so that the grouping can be recognized from the end. */
/* OP_LONG is followed by a type pointer in the next exp_element
and the long constant value in the following exp_element.
Then comes another OP_LONG.
Thus, the operation occupies four exp_elements. */
OP_LONG,
/* OP_DOUBLE is similar but takes a double constant instead of a long one. */
OP_DOUBLE,
/* OP_VAR_VALUE takes one struct symbol * in the following exp_element,
followed by another OP_VAR_VALUE, making three exp_elements. */
OP_VAR_VALUE,
/* OP_LAST is followed by an integer in the next exp_element.
The integer is zero for the last value printed,
or it is the absolute number of a history element.
With another OP_LAST at the end, this makes three exp_elements. */
OP_LAST,
/* OP_REGISTER is followed by an integer in the next exp_element.
This is the number of a register to fetch (as an int).
With another OP_REGISTER at the end, this makes three exp_elements. */
OP_REGISTER,
/* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element.
With another OP_INTERNALVAR at the end, this makes three exp_elements. */
OP_INTERNALVAR,
/* OP_FUNCALL is followed by an integer in the next exp_element.
The integer is the number of args to the function call.
That many plus one values from following subexpressions
are used, the first one being the function.
The integer is followed by a repeat of OP_FUNCALL,
making three exp_elements. */
OP_FUNCALL,
/* OP_STRING represents a string constant.
Its format is the same as that of a STRUCTOP, but the string
data is just made into a string constant when the operation
is executed. */
OP_STRING,
/* UNOP_CAST is followed by a type pointer in the next exp_element.
With another UNOP_CAST at the end, this makes three exp_elements.
It casts the value of the following subexpression. */
UNOP_CAST,
/* UNOP_MEMVAL is followed by a type pointer in the next exp_element
With another UNOP_MEMVAL at the end, this makes three exp_elements.
It casts the contents of the word addressed by the value of the
following subexpression. */
UNOP_MEMVAL,
/* UNOP_... operate on one value from a following subexpression
and replace it with a result. They take no immediate arguments. */
UNOP_NEG, /* Unary - */
UNOP_ZEROP, /* Unary ! */
UNOP_LOGNOT, /* Unary ~ */
UNOP_IND, /* Unary * */
UNOP_ADDR, /* Unary & */
UNOP_PREINCREMENT, /* ++ before an expression */
UNOP_POSTINCREMENT, /* ++ after an expression */
UNOP_PREDECREMENT, /* -- before an expression */
UNOP_POSTDECREMENT, /* -- after an expression */
UNOP_SIZEOF, /* Unary sizeof (followed by expression) */
/* STRUCTOP_... operate on a value from a following subexpression
by extracting a structure component specified by a string
that appears in the following exp_elements (as many as needed).
STRUCTOP_STRUCT is used for "." and STRUCTOP_PTR for "->".
They differ only in the error message given in case the value is
not suitable or the structure component specified is not found.
The length of the string follows in the next exp_element,
(after the string), followed by another STRUCTOP_... code. */
STRUCTOP_STRUCT,
STRUCTOP_PTR,
/* C++ */
/* OP_THIS is just a placeholder for the class instance variable.
It just comes in a tight (OP_THIS, OP_THIS) pair. */
OP_THIS,
/* OP_SCOPE surrounds a type name and a field name. The type
name is encoded as one element, but the field name stays as
a string, which, of course, is variable length. */
OP_SCOPE,
};
union exp_element
{
enum exp_opcode opcode;
struct symbol *symbol;
LONGEST longconst;
double doubleconst;
char string;
struct type *type;
struct internalvar *internalvar;
};
struct expression
{
int nelts;
union exp_element elts[1];
};
/* From expread.y. */
struct expression *parse_c_expression ();
struct expression *parse_c_1 ();
/* The innermost context required by the stack and register variables
we've encountered so far. To use this, set it to NULL, then call
parse_c_<whatever>, then look at it. */
extern struct block *innermost_block;
/* From expprint.c. */
void print_expression ();

684
gdb/findvar.c Normal file
View file

@ -0,0 +1,684 @@
/* Find a variable's value in memory, for GDB, the GNU debugger.
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "param.h"
#include "symtab.h"
#include "frame.h"
#include "value.h"
#include "gdbcore.h"
#include "inferior.h"
#include "target.h"
#if !defined (GET_SAVED_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;
if (frame == 0) /* No regs saved if want current frame */
return 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/or disappears 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. */
/* However, note that we don't want this to return anything if
nothing is saved (if there's a frame inside of this one). Also,
callers to this routine asking for the stack pointer want the
stack pointer saved for *this* frame; this is returned from the
next frame. */
if (REGISTER_IN_WINDOW_P(regnum))
{
frame1 = get_next_frame (frame);
if (!frame1) return 0; /* Registers of this frame are
active. */
/* Get the SP from the next frame in; it will be this
current frame. */
if (regnum != SP_REGNUM)
frame1 = frame;
fi = get_frame_info (frame1);
get_frame_saved_regs (fi, &saved_regs);
return saved_regs.regs[regnum]; /* ... which might be zero */
}
#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;
}
/* Find register number REGNUM relative to FRAME and put its
(raw) contents in *RAW_BUFFER. Set *OPTIMIZED if the variable
was optimized out (and thus can't be fetched). Set *LVAL to
lval_memory, lval_register, or not_lval, depending on whether the
value was fetched from memory, from a register, or in a strange
and non-modifiable way (e.g. a frame pointer which was calculated
rather than fetched). Set *ADDRP to the address, either in memory
on as a REGISTER_BYTE offset into the registers array.
Note that this implementation never sets *LVAL to not_lval. But
it can be replaced by defining GET_SAVED_REGISTER and supplying
your own.
The argument RAW_BUFFER must point to aligned memory. */
void
get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
char *raw_buffer;
int *optimized;
CORE_ADDR *addrp;
FRAME frame;
int regnum;
enum lval_type *lval;
{
CORE_ADDR addr;
/* Normal systems don't optimize out things with register numbers. */
if (optimized != NULL)
*optimized = 0;
addr = find_saved_register (frame, regnum);
if (addr != NULL)
{
if (lval != NULL)
*lval = lval_memory;
if (regnum == SP_REGNUM)
{
if (raw_buffer != NULL)
*(CORE_ADDR *)raw_buffer = addr;
if (addrp != NULL)
*addrp = 0;
return;
}
if (raw_buffer != NULL)
read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
}
else
{
if (lval != NULL)
*lval = lval_register;
addr = REGISTER_BYTE (regnum);
if (raw_buffer != NULL)
read_register_gen (regnum, raw_buffer);
}
if (addrp != NULL)
*addrp = addr;
}
#endif /* GET_SAVED_REGISTER. */
/* Copy the bytes of register REGNUM, relative to the current stack frame,
into our memory at MYADDR, in target byte order.
The number of bytes copied is REGISTER_RAW_SIZE (REGNUM).
Returns 1 if could not be read, 0 if could. */
int
read_relative_register_raw_bytes (regnum, myaddr)
int regnum;
char *myaddr;
{
int optim;
if (regnum == FP_REGNUM && selected_frame)
{
bcopy (&FRAME_FP(selected_frame), myaddr, sizeof (CORE_ADDR));
SWAP_TARGET_AND_HOST (myaddr, sizeof (CORE_ADDR)); /* in target order */
return 0;
}
get_saved_register (myaddr, &optim, (CORE_ADDR) NULL, selected_frame,
regnum, (enum lval_type *)NULL);
return optim;
}
/* 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;
{
CORE_ADDR addr;
int optim;
register value val;
char raw_buffer[MAX_REGISTER_RAW_SIZE];
char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
enum lval_type lval;
get_saved_register (raw_buffer, &optim, &addr,
selected_frame, regnum, &lval);
target_convert_to_virtual (regnum, raw_buffer, virtual_buffer);
val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
bcopy (virtual_buffer, VALUE_CONTENTS_RAW (val),
REGISTER_VIRTUAL_SIZE (regnum));
VALUE_LVAL (val) = lval;
VALUE_ADDRESS (val) = addr;
VALUE_REGNO (val) = regnum;
VALUE_OPTIMIZED_OUT (val) = optim;
return val;
}
/* Low level examining and depositing of registers.
The caller is responsible for making
sure that the inferior is stopped before calling the fetching routines,
or it will get garbage. (a change from GDB version 3, in which
the caller got the value from the last stop). */
/* Contents of the registers in target byte order.
We allocate some extra slop since we do a lot of bcopy's around `registers',
and failing-soft is better than failing hard. */
char registers[REGISTER_BYTES + /* SLOP */ 256];
/* Nonzero if that register has been fetched. */
char register_valid[NUM_REGS];
/* Indicate that registers may have changed, so invalidate the cache. */
void
registers_changed ()
{
int i;
for (i = 0; i < NUM_REGS; i++)
register_valid[i] = 0;
}
/* Indicate that all registers have been fetched, so mark them all valid. */
void
registers_fetched ()
{
int i;
for (i = 0; i < NUM_REGS; i++)
register_valid[i] = 1;
}
/* 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;
{
/* Fetch all registers. */
int i;
for (i = 0; i < NUM_REGS; i++)
if (!register_valid[i])
{
target_fetch_registers (-1);
break;
}
if (myaddr != NULL)
bcopy (&registers[regbyte], myaddr, len);
}
/* Read register REGNO into memory at MYADDR, which must be large enough
for REGISTER_RAW_BYTES (REGNO). If the register is known to be the
size of a CORE_ADDR or smaller, read_register can be used instead. */
void
read_register_gen (regno, myaddr)
int regno;
char *myaddr;
{
if (!register_valid[regno])
target_fetch_registers (regno);
bcopy (&registers[REGISTER_BYTE (regno)], myaddr, REGISTER_RAW_SIZE (regno));
}
/* 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;
{
/* Make sure the entire registers array is valid. */
read_register_bytes (0, (char *)NULL, REGISTER_BYTES);
bcopy (myaddr, &registers[regbyte], len);
target_store_registers (-1);
}
/* Return the contents of register REGNO, regarding it as an integer. */
CORE_ADDR
read_register (regno)
int regno;
{
int reg;
if (!register_valid[regno])
target_fetch_registers (regno);
/* FIXME, this loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
reg = *(int *) &registers[REGISTER_BYTE (regno)];
SWAP_TARGET_AND_HOST (&reg, sizeof (int));
return reg;
}
/* Registers we shouldn't try to store. */
#if !defined (CANNOT_STORE_REGISTER)
#define CANNOT_STORE_REGISTER(regno) 0
#endif
/* Store VALUE in the register number REGNO, regarded as an integer. */
void
write_register (regno, val)
int regno, val;
{
/* On the sparc, writing %g0 is a no-op, so we don't even want to change
the registers array if something writes to this register. */
if (CANNOT_STORE_REGISTER (regno))
return;
SWAP_TARGET_AND_HOST (&val, sizeof (int));
target_prepare_to_store ();
register_valid [regno] = 1;
/* FIXME, this loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
/* FIXME, this depends on REGISTER_BYTE (regno) being aligned for host */
*(int *) &registers[REGISTER_BYTE (regno)] = val;
target_store_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;
{
register_valid[regno] = 1;
bcopy (val, &registers[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno));
}
/* Given a struct symbol for a variable,
and a stack frame id, read the value of the variable
and return a (pointer to a) struct value containing the value.
If the variable cannot be found, return a zero pointer. */
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);
CORE_ADDR addr;
int val;
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:
val = SYMBOL_VALUE (var);
bcopy (&val, VALUE_CONTENTS_RAW (v), len);
SWAP_TARGET_AND_HOST (VALUE_CONTENTS_RAW (v), len);
VALUE_LVAL (v) = not_lval;
return v;
case LOC_LABEL:
addr = SYMBOL_VALUE_ADDRESS (var);
bcopy (&addr, VALUE_CONTENTS_RAW (v), len);
SWAP_TARGET_AND_HOST (VALUE_CONTENTS_RAW (v), len);
VALUE_LVAL (v) = not_lval;
return v;
case LOC_CONST_BYTES:
addr = SYMBOL_VALUE_ADDRESS (var);
bcopy (addr, VALUE_CONTENTS_RAW (v), len);
VALUE_LVAL (v) = not_lval;
return v;
case LOC_STATIC:
case LOC_EXTERNAL:
addr = SYMBOL_VALUE_ADDRESS (var);
break;
/* Nonzero if a struct which is located in a register or a LOC_ARG
really contains
the address of the struct, not the struct itself. GCC_P is nonzero
if the function was compiled with GCC. */
#if !defined (REG_STRUCT_HAS_ADDR)
#define REG_STRUCT_HAS_ADDR(gcc_p) 0
#endif
case LOC_ARG:
fi = get_frame_info (frame);
addr = FRAME_ARGS_ADDRESS (fi);
if (!addr) {
return 0;
}
addr += SYMBOL_VALUE (var);
break;
case LOC_REF_ARG:
fi = get_frame_info (frame);
addr = FRAME_ARGS_ADDRESS (fi);
if (!addr) {
return 0;
}
addr += SYMBOL_VALUE (var);
addr = read_memory_integer (addr, sizeof (CORE_ADDR));
break;
case LOC_LOCAL:
case LOC_LOCAL_ARG:
fi = get_frame_info (frame);
addr = SYMBOL_VALUE (var) + FRAME_LOCALS_ADDRESS (fi);
break;
case LOC_TYPEDEF:
error ("Cannot look up value of a typedef");
break;
case LOC_BLOCK:
VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
return v;
case LOC_REGISTER:
case LOC_REGPARM:
{
struct block *b = get_frame_block (frame);
v = value_from_register (type, SYMBOL_VALUE (var), frame);
if (REG_STRUCT_HAS_ADDR(b->gcc_compile_flag)
&& TYPE_CODE (type) == TYPE_CODE_STRUCT)
addr = *(CORE_ADDR *)VALUE_CONTENTS (v);
else
return v;
}
break;
default:
error ("Cannot look up value of a botched symbol.");
break;
}
VALUE_ADDRESS (v) = addr;
VALUE_LAZY (v) = 1;
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;
int optim;
value v = allocate_value (type);
int len = TYPE_LENGTH (type);
char *value_bytes = 0;
int value_bytes_copied = 0;
int num_storage_locs;
enum lval_type lval;
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;
CORE_ADDR first_addr;
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))
{
get_saved_register (value_bytes + value_bytes_copied,
&optim,
&addr,
frame,
local_regnum,
&lval);
if (lval == lval_register)
reg_stor++;
else
{
mem_stor++;
if (regnum == local_regnum)
first_addr = addr;
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) = first_addr;
}
else if (reg_stor)
{
VALUE_LVAL (v) = lval_register;
VALUE_ADDRESS (v) = first_addr;
}
else
fatal ("value_from_register: Value not stored anywhere!");
VALUE_OPTIMIZED_OUT (v) = optim;
/* Any structure stored in more than one register will always be
an integral 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_RAW (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. */
get_saved_register (raw_buffer, &optim, &addr, frame, regnum, &lval);
VALUE_OPTIMIZED_OUT (v) = optim;
VALUE_LVAL (v) = lval;
VALUE_ADDRESS (v) = addr;
/* Convert the raw contents to virtual contents.
(Just copy them if the formats are the same.) */
target_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_RAW (v), len);
v = value_cast (type, v);
}
else
bcopy (virtual_buffer, VALUE_CONTENTS_RAW (v), len);
}
else
{
/* Raw and virtual formats are the same for this register. */
#if TARGET_BYTE_ORDER == 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_RAW (v), len);
}
return v;
}
/* Given a struct symbol for a variable,
and a stack frame id,
return a (pointer to a) struct value containing the variable's address. */
value
locate_var_value (var, frame)
register struct symbol *var;
FRAME frame;
{
CORE_ADDR addr = 0;
struct type *type = SYMBOL_TYPE (var);
struct type *result_type;
value lazy_value;
/* Evaluate it first; if the result is a memory address, we're fine.
Lazy evaluation pays off here. */
lazy_value = read_var_value (var, frame);
if (lazy_value == 0)
error ("Address of \"%s\" is unknown.", SYMBOL_NAME (var));
if (VALUE_LAZY (lazy_value))
{
addr = VALUE_ADDRESS (lazy_value);
/* C++: The "address" of a reference should yield the address
* of the object pointed to. So force an extra de-reference. */
if (TYPE_CODE (type) == TYPE_CODE_REF)
{
char *buf = alloca (TYPE_LENGTH (type));
read_memory (addr, buf, TYPE_LENGTH (type));
addr = unpack_long (type, buf);
type = TYPE_TARGET_TYPE (type);
}
/* Address of an array is of the type of address of it's elements. */
result_type =
lookup_pointer_type (TYPE_CODE (type) == TYPE_CODE_ARRAY ?
TYPE_TARGET_TYPE (type) : type);
return value_cast (result_type,
value_from_long (builtin_type_long, (LONGEST) addr));
}
/* Not a memory address; check what the problem was. */
switch (VALUE_LVAL (lazy_value))
{
case lval_register:
case lval_reg_frame_relative:
error ("Address requested for identifier \"%s\" which is in a register.",
SYMBOL_NAME (var));
break;
default:
error ("Can't take address of \"%s\" which isn't an lvalue.",
SYMBOL_NAME (var));
break;
}
return 0; /* For lint -- never reached */
}

128
gdb/frame.h Normal file
View file

@ -0,0 +1,128 @@
/* Definitions for dealing with stack frames, for GDB, the GNU debugger.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (FRAME_H)
#define FRAME_H 1
#include "param.h"
/*
* 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_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.
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. */
struct frame_saved_regs
{
/* For each register, address of where it was saved on entry to the frame,
or zero if it was not saved on entry to this frame. */
CORE_ADDR regs[NUM_REGS];
};
/* The stack frame that the user has specified for commands to act on.
Note that one cannot assume this is the address of valid data. */
extern FRAME selected_frame;
extern struct frame_info *get_frame_info ();
extern struct frame_info *get_prev_frame_info ();
extern FRAME create_new_frame ();
extern void flush_cached_frames ();
extern void get_frame_saved_regs ();
extern void set_current_frame ();
extern FRAME get_prev_frame ();
extern FRAME get_current_frame ();
extern FRAME get_next_frame ();
extern struct block *get_frame_block ();
extern struct block *get_current_block ();
extern struct block *get_selected_block ();
extern struct symbol *get_frame_function ();
extern CORE_ADDR get_frame_pc ();
extern CORE_ADDR get_pc_function_start ();
struct block *block_for_pc ();
int frameless_look_for_prologue ();
void print_frame_args ();
/* In stack.c */
extern FRAME find_relative_frame ();
extern void print_selected_frame ();
extern void print_sel_frame ();
extern void select_frame ();
extern void record_selected_frame ();
#endif /* frame.h not already included. */

242
gdb/gdb-int.texinfo Executable file
View file

@ -0,0 +1,242 @@
\input texinfo
@setfilename gdb-internals
@ifinfo
This file documents the internals of the GNU debugger GDB.
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
Contributed by Cygnus Support. Written by John Gilmore.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@ignore
Permission is granted to process this file through Tex and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy or distribute modified versions of this
manual under the terms of the GPL (for which purpose this text may be
regarded as a program in the language TeX).
@end ifinfo
@setchapternewpage odd
@settitle GDB Internals
@titlepage
@title{Working in GDB}
@subtitle{A guide to the internals of the GNU debugger}
@author John Gilmore
@author Cygnus Support
@page
@tex
\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$
\xdef\manvers{\$Revision$} % For use in headers, footers too
{\parskip=0pt
\hfill Cygnus Support\par
\hfill \manvers\par
\hfill \TeX{}info \texinfoversion\par
}
@end tex
@vskip 0pt plus 1filll
Copyright @copyright{} 1990, 1991 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@end titlepage
@node Top, Cleanups, (dir), (dir)
@menu
* Cleanups:: Cleanups
* Wrapping:: Wrapping output lines
* Releases:: Configuring GDB for release
* README:: The README file
* New Architectures:: Defining a new host or target architecture
* Host versus Targt:: What features are in which files
@end menu
@node Cleanups, Wrapping, Top, Top
@chapter Cleanups
Cleanups are a structured way to deal with things that need to be done
later. When your code does something (like malloc some memory, or open
a file) that needs to be undone later (e.g. free the memory or close
the file), it can make a cleanup. The cleanup will be done at some
future point: when the command is finished, when an error occurs, or
when your code decides it's time to do cleanups.
You can also discard cleanups, that is, throw them away without doing
what they say. This is only done if you ask that it be done.
Syntax:
@table @code
@item old_chain = make_cleanup (function, arg);
This makes a cleanup which will cause FUNCTION to be called with ARG
(a char *) later. The result, OLD_CHAIN, is a handle that can be
passed to do_cleanups or discard_cleanups later. Unless you are
going to call do_cleanups or discard_cleanups yourself,
you can ignore the result from make_cleanup.
@item do_cleanups (old_chain);
Performs all cleanups done since make_cleanup returned OLD_CHAIN.
E.g.: make_cleanup (a, 0); old = make_cleanup (b, 0); do_cleanups (old);
will call b() but will not call a(). The cleanup that calls a() will remain
in the cleanup chain, and will be done later unless otherwise discarded.
@item discard_cleanups (old_chain);
Same as do_cleanups except that it just removes the cleanups from the
chain and does not call the specified functions.
@end table
Some functions, e.g. @code{fputs_filtered()} or @code{error()}, specify that they
``should not be called when cleanups are not in place''. This means
that any actions you need to reverse in the case of an error or
interruption must be on the cleanup chain before you call these functions,
since they might never return to your code (they @samp{longjmp} instead).
@node Wrapping, Releases, Cleanups, Top
@chapter Wrapping output lines
Output that goes through printf_filtered or fputs_filtered or
fputs_demangled needs only to have calls to wrap_here() added
in places that would be good breaking points. The utility routines
will take care of actually wrapping if the line width is exceeded.
The argument to wrap_here() is an indentation string which is printed
ONLY if the line breaks there. This argument is saved away and used
later. It must remain valid until the next call to wrap_here() or
until a newline has been printed through the *_filtered functions.
Don't pass in a local variable and then return!
It is usually best to call wrap_here() after printing a comma or space.
If you call it before printing a space, make sure that your indentation
properly accounts for the leading space that will print if the line wraps
there.
Any function or set of functions that produce filtered output must finish
by printing a newline, to flush the wrap buffer, before switching to
unfiltered ("printf") output. Symbol reading routines that print
warnings are a good example.
@node Releases, README, Wrapping, Top
@chapter Configuring GDB for release
GDB should be released after doing @samp{config.gdb none} in the top level
directory. This will leave a makefile there, but no tm- or xm- files.
The makefile is needed, for example, for @samp{make gdb.tar.Z}@dots{} If you
have tm- or xm-files in the main source directory, C's include rules
cause them to be used in preference to tm- and xm-files in the
subdirectories where the user will actually configure and build the
binaries.
@samp{config.gdb none} is also a good way to rebuild the top level Makefile
after changing Makefile.dist, alldeps.mak, etc.
@node README, New Architectures, Releases, Top
@chapter The README file
Check the README file, it often has useful information that does not
appear anywhere else in the directory.
@node New Architectures, Host versus Target, README, Top
@chapter Defining a new host or target architecture
When building support for a new host and/or target, this will help you
organize where to put the various parts. @var{ARCH} stands for the
architecture involved.
Object files needed when the host system is an @var{ARCH} are listed in
the file @file{xconfig/@var{ARCH}}, in the Makefile macro @samp{XDEPFILES
= }@dots{}. You can also define XXXXXX in there.
There are some ``generic'' versions of routines that can be used by
various host systems. If these routines work for the @var{ARCH} host,
you can just include the generic file's name (with .o, not .c) in
@code{XDEPFILES}. Otherwise, you will need to write routines that
perform the same functions as the generic file, put them into
@code{@var{ARCH}-xdep.c}, and put @code{@var{ARCH}-xdep.o} into
@code{XDEPFILES}. These generic host support files include:
@example
coredep.c, coredep.o
@end example
@table @code
@item fetch_core_registers()
Support for reading registers out of a core file. This routine calls
@code{register_addr(}), see below.
@item register_addr()
If your @code{xm-@var{ARCH}.h} file defines the macro @code{REGISTER_U_ADDR(reg)} to be the
offset within the @samp{user} struct of a register (represented as a GDB
register number), @file{coredep.c} will define the @code{register_addr()} function
and use the macro in it. If you do not define @code{REGISTER_U_ADDR}, but
you are using the standard @code{fetch_core_registers}, you
will need to define your own version of @code{register_addr}, put it into
your @code{@var{ARCH}-xdep.c} file, and be sure @code{@var{ARCH}-xdep.o} is in the @code{XDEPFILES} list.
If you have your own @code{fetch_core_registers}, you only need to define
@code{register_addr} if your @code{fetch_core_registers} calls it. Many custom
@code{fetch_core_registers} implementations simply locate the registers
themselves.
@end table
Files needed when the target system is an @var{ARCH} are listed in the file
@file{tconfig/@var{ARCH}}, in the @code{Makefile} macro @samp{TDEPFILES = }@dots{}. You can also
define XXXXXX in there.
Similar generic support files for target systems are:
@example
exec.c, exec.o:
@end example
This file defines functions for accessing files that are executable
on the target system. These functions open and examine an exec file,
extract data from one, write data to one, print information about one,
etc. Now that executable files are handled with BFD, every architecture
should be able to use the generic exec.c rather than its own custom code.
@node Host versus Target, , README, Top
@chapter What is considered ``host-dependent'' versus ``target-dependent''?
The xconfig/*, xm-*.h and *-xdep.c files are for host support. The
question is, what features or aspects of a debugging or cross-debugging
environment are considered to be ``host'' support.
Defines and include files needed to build on the host are host support.
Examples are tty support, system defined types, host byte order, host
float format.
Unix child process support is considered an aspect of the host. Since
when you fork on the host you are still on the host, the various macros
needed for finding the registers in the upage, running ptrace, and such
are all in the host-dependent files.
This is still somewhat of a grey area; I (John Gilmore) didn't do the
xm- and tm- split for gdb (it was done by Jim Kingdon) so I have had to
figure out the grounds on which it was split, and make my own choices
as I evolve it. I have moved many things out of the xdep files
actually, partly as a result of BFD and partly by removing duplicated
code.
@contents
@bye

63
gdb/gdbcmd.h Normal file
View file

@ -0,0 +1,63 @@
/* Header file for GDB-specific command-line stuff.
Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "command.h"
/* Chain containing all defined commands. */
extern struct cmd_list_element *cmdlist;
/* Chain containing all defined info subcommands. */
extern struct cmd_list_element *infolist;
/* Chain containing all defined enable subcommands. */
extern struct cmd_list_element *enablelist;
/* Chain containing all defined disable subcommands. */
extern struct cmd_list_element *disablelist;
/* Chain containing all defined delete subcommands. */
extern struct cmd_list_element *deletelist;
/* Chain containing all defined "enable breakpoint" subcommands. */
extern struct cmd_list_element *enablebreaklist;
/* Chain containing all defined set subcommands */
extern struct cmd_list_element *setlist;
/* Chain containing all defined show subcommands. */
extern struct cmd_list_element *showlist;
/* Chain containing all defined \"set history\". */
extern struct cmd_list_element *sethistlist;
/* Chain containing all defined \"show history\". */
extern struct cmd_list_element *showhistlist;
/* Chain containing all defined \"unset history\". */
extern struct cmd_list_element *unsethistlist;
void execute_command ();
char **noop_completer ();

82
gdb/gdbcore.h Normal file
View file

@ -0,0 +1,82 @@
/* Machine independent variables that describe the core file under GDB.
Copyright (C) 1986, 1987, 1989, 1990 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Interface routines for core, executable, etc. */
#include "bfd.h" /* Binary File Description */
/* 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 ();
/* Nonzero if there is a core file. */
int have_core_file_p ();
/* Read "memory data" from whatever target or inferior we have.
Returns zero if successful, errno value if not. EIO is used
for address out of bounds. If breakpoints are inserted, returns
shadow contents, not the breakpoints themselves. From breakpoint.c. */
int read_memory_nobpt ();
/* Report a memory error with error(). */
void memory_error ();
/* Like target_read_memory, but report an error if can't read. */
void read_memory ();
/* Read an integer from debugged memory, given address and number of bytes. */
long read_memory_integer ();
/* Hook for `exec_file_command' command to call. */
extern void (*exec_file_display_hook) ();
/* Binary File Diddlers for the exec and core files */
extern bfd *core_bfd;
extern bfd *exec_bfd;
void core_file_command ();
void exec_file_command ();
void validate_files ();
unsigned int register_addr ();
int xfer_core_file ();
void fetch_core_registers ();
void registers_fetched ();
#if !defined (KERNEL_U_ADDR)
extern CORE_ADDR kernel_u_addr;
#define KERNEL_U_ADDR kernel_u_addr
#endif
/* Struct section_table maps address ranges to file sections. It is
mostly used with BFD files, but can be used without (e.g. for handling
raw disks, or files not in formats handled by BFD). */
struct section_table {
CORE_ADDR addr; /* Lowest address in section */
CORE_ADDR endaddr; /* 1+highest address in section */
sec_ptr sec_ptr; /* BFD section pointer */
};
/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
Returns 0 if OK, 1 on error. */
int build_section_table ();

494
gdb/i386-tdep.c Normal file
View file

@ -0,0 +1,494 @@
/* Intel 386 stuff.
Copyright (C) 1988, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#include "gdbcore.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/user.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#ifndef N_SET_MAGIC
#ifdef COFF_FORMAT
#define N_SET_MAGIC(exec, val) ((exec).magic = (val))
#else
#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
#endif
#endif
#include <sys/file.h>
#include <sys/stat.h>
/* I don't know whether this is right for cross-debugging even if you
do somehow manage to get the right include file. */
#if defined (USE_MACHINE_REG_H)
#include <machine/reg.h>
#else
#include <sys/reg.h>
#endif
/* helper functions for m-i386.h */
/* stdio style buffering to minimize calls to ptrace */
static CORE_ADDR codestream_next_addr;
static CORE_ADDR codestream_addr;
static unsigned char codestream_buf[sizeof (int)];
static int codestream_off;
static int codestream_cnt;
#define codestream_tell() (codestream_addr + codestream_off)
#define codestream_peek() (codestream_cnt == 0 ? \
codestream_fill(1): codestream_buf[codestream_off])
#define codestream_get() (codestream_cnt-- == 0 ? \
codestream_fill(0) : codestream_buf[codestream_off++])
static unsigned char
codestream_fill (peek_flag)
{
codestream_addr = codestream_next_addr;
codestream_next_addr += sizeof (int);
codestream_off = 0;
codestream_cnt = sizeof (int);
read_memory (codestream_addr,
(unsigned char *)codestream_buf,
sizeof (int));
if (peek_flag)
return (codestream_peek());
else
return (codestream_get());
}
static void
codestream_seek (place)
{
codestream_next_addr = place & -sizeof (int);
codestream_cnt = 0;
codestream_fill (1);
while (codestream_tell() != place)
codestream_get ();
}
static void
codestream_read (buf, count)
unsigned char *buf;
{
unsigned char *p;
int i;
p = buf;
for (i = 0; i < count; i++)
*p++ = codestream_get ();
}
/* next instruction is a jump, move to target */
static
i386_follow_jump ()
{
int long_delta;
short short_delta;
char byte_delta;
int data16;
int pos;
pos = codestream_tell ();
data16 = 0;
if (codestream_peek () == 0x66)
{
codestream_get ();
data16 = 1;
}
switch (codestream_get ())
{
case 0xe9:
/* relative jump: if data16 == 0, disp32, else disp16 */
if (data16)
{
codestream_read ((unsigned char *)&short_delta, 2);
pos += short_delta + 3; /* include size of jmp inst */
}
else
{
codestream_read ((unsigned char *)&long_delta, 4);
pos += long_delta + 5;
}
break;
case 0xeb:
/* relative jump, disp8 (ignore data16) */
codestream_read ((unsigned char *)&byte_delta, 1);
pos += byte_delta + 2;
break;
}
codestream_seek (pos + data16);
}
/*
* find & return amound a local space allocated, and advance codestream to
* first register push (if any)
*
* if entry sequence doesn't make sense, return -1, and leave
* codestream pointer random
*/
static long
i386_get_frame_setup (pc)
{
unsigned char op;
codestream_seek (pc);
i386_follow_jump ();
op = codestream_get ();
if (op == 0x58) /* popl %eax */
{
/*
* this function must start with
*
* popl %eax 0x58
* xchgl %eax, (%esp) 0x87 0x04 0x24
* or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
*
* (the system 5 compiler puts out the second xchg
* inst, and the assembler doesn't try to optimize it,
* so the 'sib' form gets generated)
*
* this sequence is used to get the address of the return
* buffer for a function that returns a structure
*/
int pos;
unsigned char buf[4];
static unsigned char proto1[3] = { 0x87,0x04,0x24 };
static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 };
pos = codestream_tell ();
codestream_read (buf, 4);
if (bcmp (buf, proto1, 3) == 0)
pos += 3;
else if (bcmp (buf, proto2, 4) == 0)
pos += 4;
codestream_seek (pos);
op = codestream_get (); /* update next opcode */
}
if (op == 0x55) /* pushl %ebp */
{
/* check for movl %esp, %ebp - can be written two ways */
switch (codestream_get ())
{
case 0x8b:
if (codestream_get () != 0xec)
return (-1);
break;
case 0x89:
if (codestream_get () != 0xe5)
return (-1);
break;
default:
return (-1);
}
/* check for stack adjustment
*
* subl $XXX, %esp
*
* note: you can't subtract a 16 bit immediate
* from a 32 bit reg, so we don't have to worry
* about a data16 prefix
*/
op = codestream_peek ();
if (op == 0x83)
{
/* subl with 8 bit immed */
codestream_get ();
if (codestream_get () != 0xec)
/* Some instruction starting with 0x83 other than subl. */
{
codestream_seek (codestream_tell () - 2);
return 0;
}
/* subl with signed byte immediate
* (though it wouldn't make sense to be negative)
*/
return (codestream_get());
}
else if (op == 0x81)
{
/* subl with 32 bit immed */
int locals;
codestream_get();
if (codestream_get () != 0xec)
/* Some instruction starting with 0x81 other than subl. */
{
codestream_seek (codestream_tell () - 2);
return 0;
}
/* subl with 32 bit immediate */
codestream_read ((unsigned char *)&locals, 4);
return (locals);
}
else
{
return (0);
}
}
else if (op == 0xc8)
{
/* enter instruction: arg is 16 bit unsigned immed */
unsigned short slocals;
codestream_read ((unsigned char *)&slocals, 2);
codestream_get (); /* flush final byte of enter instruction */
return (slocals);
}
return (-1);
}
/* 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
*/
int
i386_frame_num_args (fi)
struct frame_info fi;
{
int retpc;
unsigned char op;
struct frame_info *pfi;
int frameless;
FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
if (frameless)
/* In the absence of a frame pointer, GDB doesn't get correct values
for nameless arguments. Return -1, so it doesn't print any
nameless arguments. */
return -1;
pfi = get_prev_frame_info ((fi));
if (pfi == 0)
{
/* Note: this can happen if we are looking at the frame for
main, because FRAME_CHAIN_VALID won't let us go into
start. If we have debugging symbols, that's not really
a big deal; it just means it will only show as many arguments
to main as are declared. */
return -1;
}
else
{
retpc = pfi->pc;
op = read_memory_integer (retpc, 1);
if (op == 0x59)
/* pop %ecx */
return 1;
else if (op == 0x83)
{
op = read_memory_integer (retpc+1, 1);
if (op == 0xc4)
/* addl $<signed imm 8 bits>, %esp */
return (read_memory_integer (retpc+2,1)&0xff)/4;
else
return 0;
}
else if (op == 0x81)
{ /* add with 32 bit immediate */
op = read_memory_integer (retpc+1, 1);
if (op == 0xc4)
/* addl $<imm 32>, %esp */
return read_memory_integer (retpc+2, 4) / 4;
else
return 0;
}
else
{
return 0;
}
}
}
/*
* parse the first few instructions of the function to see
* what registers were stored.
*
* We handle these cases:
*
* The startup sequence can be at the start of the function,
* or the function can start with a branch to startup code at the end.
*
* %ebp can be set up with either the 'enter' instruction, or
* 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
* but was once used in the sys5 compiler)
*
* Local space is allocated just below the saved %ebp by either the
* 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has
* a 16 bit unsigned argument for space to allocate, and the
* 'addl' instruction could have either a signed byte, or
* 32 bit immediate.
*
* Next, the registers used by this function are pushed. In
* the sys5 compiler they will always be in the order: %edi, %esi, %ebx
* (and sometimes a harmless bug causes it to also save but not restore %eax);
* however, the code below is willing to see the pushes in any order,
* and will handle up to 8 of them.
*
* If the setup sequence is at the end of the function, then the
* next instruction will be a branch back to the start.
*/
i386_frame_find_saved_regs (fip, fsrp)
struct frame_info *fip;
struct frame_saved_regs *fsrp;
{
long locals;
unsigned char *p;
unsigned char op;
CORE_ADDR dummy_bottom;
CORE_ADDR adr;
int i;
bzero (fsrp, sizeof *fsrp);
/* if frame is the end of a dummy, compute where the
* beginning would be
*/
dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
/* check if the PC is in the stack, in a dummy frame */
if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
{
/* all regs were saved by push_call_dummy () */
adr = fip->frame;
for (i = 0; i < NUM_REGS; i++)
{
adr -= REGISTER_RAW_SIZE (i);
fsrp->regs[i] = adr;
}
return;
}
locals = i386_get_frame_setup (get_pc_function_start (fip->pc));
if (locals >= 0)
{
adr = fip->frame - 4 - locals;
for (i = 0; i < 8; i++)
{
op = codestream_get ();
if (op < 0x50 || op > 0x57)
break;
fsrp->regs[op - 0x50] = adr;
adr -= 4;
}
}
fsrp->regs[PC_REGNUM] = fip->frame + 4;
fsrp->regs[FP_REGNUM] = fip->frame;
}
/* return pc of first real instruction */
i386_skip_prologue (pc)
{
unsigned char op;
int i;
if (i386_get_frame_setup (pc) < 0)
return (pc);
/* found valid frame setup - codestream now points to
* start of push instructions for saving registers
*/
/* skip over register saves */
for (i = 0; i < 8; i++)
{
op = codestream_peek ();
/* break if not pushl inst */
if (op < 0x50 || op > 0x57)
break;
codestream_get ();
}
i386_follow_jump ();
return (codestream_tell ());
}
i386_push_dummy_frame ()
{
CORE_ADDR sp = read_register (SP_REGNUM);
int regnum;
char regbuf[MAX_REGISTER_RAW_SIZE];
sp = push_word (sp, read_register (PC_REGNUM));
sp = push_word (sp, read_register (FP_REGNUM));
write_register (FP_REGNUM, sp);
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
read_register_gen (regnum, regbuf);
sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
}
write_register (SP_REGNUM, sp);
}
i386_pop_frame ()
{
FRAME frame = get_current_frame ();
CORE_ADDR fp;
int regnum;
struct frame_saved_regs fsr;
struct frame_info *fi;
char regbuf[MAX_REGISTER_RAW_SIZE];
fi = get_frame_info (frame);
fp = fi->frame;
get_frame_saved_regs (fi, &fsr);
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
CORE_ADDR adr;
adr = fsr.regs[regnum];
if (adr)
{
read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
write_register_bytes (REGISTER_BYTE (regnum), regbuf,
REGISTER_RAW_SIZE (regnum));
}
}
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 ()));
}

1088
gdb/infcmd.c Normal file

File diff suppressed because it is too large Load diff

201
gdb/inferior.h Normal file
View file

@ -0,0 +1,201 @@
/* Variables that describe the inferior process running under GDB:
Where it is, why it stopped, and how to step it.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* For bpstat. */
#include "breakpoint.h"
/* For FRAME_ADDR. */
#include "frame.h"
/*
* 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;
FRAME_ADDR stop_frame_address;
bpstat stop_bpstat;
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_soon_quietly;
FRAME_ADDR selected_frame_address;
int selected_level;
char stop_registers[REGISTER_BYTES];
int breakpoint_proceeded;
int restore_stack_info;
int proceed_to_finish;
};
void save_inferior_status (), restore_inferior_status ();
/* File name for default use for standard in/out in the inferior. */
extern char *inferior_io_terminal;
/* Pid of our debugged inferior, or 0 if no inferior now. */
extern int inferior_pid;
/* Character array containing an image of the inferior programs' registers. */
extern char registers[];
extern void clear_proceed_status ();
extern void start_inferior ();
extern void proceed ();
extern void kill_inferior ();
extern void kill_inferior_fast ();
extern void generic_mourn_inferior ();
extern void terminal_ours ();
extern void detach ();
extern void run_stack_dummy ();
extern CORE_ADDR read_pc ();
extern void write_pc ();
extern void wait_for_inferior ();
extern void init_wait_for_inferior ();
extern void close_exec_file ();
extern void reopen_exec_file ();
/* Last signal that the inferior received (why it stopped). */
extern int stop_signal;
/* Address at which inferior stopped. */
extern CORE_ADDR stop_pc;
/* Stack frame when program stopped. */
extern FRAME_ADDR stop_frame_address;
/* Chain containing status of breakpoint(s) that we have stopped at. */
extern bpstat stop_bpstat;
/* Flag indicating that a command has proceeded the inferior past the
current breakpoint. */
extern int breakpoint_proceeded;
/* Nonzero if stopped due to a step command. */
extern int stop_step;
/* Nonzero if stopped due to completion of a stack dummy routine. */
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. */
extern CORE_ADDR step_range_start; /* Inclusive */
extern CORE_ADDR step_range_end; /* Exclusive */
/* Stack frame address as of when stepping command was issued.
This is how we know when we step into a subroutine call,
and how to set the frame for the breakpoint used to step out. */
extern FRAME_ADDR step_frame_address;
/* 1 means step over all subroutine calls.
-1 means step over calls to undebuggable functions. */
extern int step_over_calls;
/* If stepping, nonzero means step count is > 1
so don't print frame next time inferior stops
if it stops due to stepping. */
extern int step_multi;
/* Nonzero if proceed is being used for a "finish" command or a similar
situation when stop_registers should be saved. */
extern int proceed_to_finish;
/* Save register contents here when about to pop a stack dummy frame,
if-and-only-if proceed_to_finish is set.
Thus this contains the return value from the called function (assuming
values are returned in a register). */
extern char stop_registers[REGISTER_BYTES];
/* Nonzero if pc has been changed by the debugger
since the inferior stopped. */
extern int pc_changed;
/* Nonzero if the child process in inferior_pid was attached rather
than forked. */
int attach_flag;
/* Possible values for CALL_DUMMY_LOCATION. */
#define ON_STACK 1
#define BEFORE_TEXT_END 2
#define AFTER_TEXT_END 3
#if !defined (CALL_DUMMY_LOCATION)
#if defined (CANNOT_EXECUTE_STACK)
#define CALL_DUMMY_LOCATION BEFORE_TEXT_END
#else /* Can execute stack. */
#define CALL_DUMMY_LOCATION ON_STACK
#endif /* Can execute stack. */
#endif /* No CALL_DUMMY_LOCATION. */
/* Are we in a call dummy? The code below which allows DECR_PC_AFTER_BREAK
below is for infrun.c, which may give the macro a pc without that
subtracted out. */
#if !defined (PC_IN_CALL_DUMMY)
#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
((pc) >= text_end - CALL_DUMMY_LENGTH \
&& (pc) < text_end + DECR_PC_AFTER_BREAK)
#else /* Not before text_end. */
#if CALL_DUMMY_LOCATION == AFTER_TEXT_END
#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
((pc) >= text_end \
&& (pc) < text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK)
#else /* On stack. */
#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
((sp) INNER_THAN (pc) && (pc) INNER_THAN (frame_address))
#endif /* On stack. */
#endif /* Not before text_end. */
#endif /* No PC_IN_CALL_DUMMY. */

478
gdb/inflow.c Normal file
View file

@ -0,0 +1,478 @@
/* Low level interface to ptrace, for GDB when running under Unix.
Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#include "command.h"
#include "signals.h"
#include "terminal.h"
#include "target.h"
#ifdef USG
#include <sys/types.h>
#endif
/* Some USG-esque systems (some of which are BSD-esque enough so that USG
is not defined) want this header, and it won't do any harm. */
#include <fcntl.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
extern struct target_ops child_ops;
/* 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;
#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
static struct tchars tc_inferior;
static struct tchars tc_ours;
#endif
#ifdef TIOCGLTC
static struct ltchars ltc_inferior;
static struct ltchars ltc_ours;
#endif
#ifdef TIOCLGET
static int lmode_inferior;
static int lmode_ours;
#endif
#ifdef TIOCGPGRP
static int pgrp_inferior;
static int pgrp_ours;
#else
static void (*sigint_ours) ();
static void (*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 ()
{
sg_inferior = sg_ours;
tflags_inferior = tflags_ours;
#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
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 (terminal_is_ours && inferior_thisrun_terminal == 0)
{
fcntl (0, F_SETFL, tflags_inferior);
fcntl (0, F_SETFL, tflags_inferior);
ioctl (0, TIOCSETN, &sg_inferior);
#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
ioctl (0, TIOCSETC, &tc_inferior);
#endif
#ifdef TIOCGLTC
ioctl (0, TIOCSLTC, &ltc_inferior);
#endif
#ifdef TIOCLGET
ioctl (0, TIOCLSET, &lmode_inferior);
#endif
#ifdef TIOCGPGRP
ioctl (0, TIOCSPGRP, &pgrp_inferior);
#else
sigint_ours = (void (*) ()) signal (SIGINT, SIG_IGN);
sigquit_ours = (void (*) ()) 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 ()
{
terminal_ours_1 (1);
}
/* Put our terminal settings into effect.
First record the inferior's terminal settings
so they can be restored properly later. */
void
terminal_ours ()
{
terminal_ours_1 (0);
}
static void
terminal_ours_1 (output_only)
int output_only;
{
#ifdef TIOCGPGRP
/* Ignore this signal since it will happen when we try to set the pgrp. */
void (*osigttou) ();
#endif /* TIOCGPGRP */
/* The check for inferior_thisrun_terminal had been commented out
when the call to ioctl (TIOCNOTTY) was commented out.
Checking inferior_thisrun_terminal is necessary so that
if GDB is running in the background, it won't block trying
to do the ioctl()'s below. */
if (inferior_thisrun_terminal != 0)
return;
if (!terminal_is_ours)
{
terminal_is_ours = 1;
#ifdef TIOCGPGRP
osigttou = (void (*) ()) 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);
#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
ioctl (0, TIOCGETC, &tc_inferior);
#endif
#ifdef TIOCGLTC
ioctl (0, TIOCGLTC, &ltc_inferior);
#endif
#ifdef TIOCLGET
ioctl (0, TIOCLGET, &lmode_inferior);
#endif
}
#ifdef HAVE_TERMIO
sg_ours.c_lflag |= ICANON;
if (output_only && !(sg_inferior.c_lflag & ICANON))
sg_ours.c_lflag &= ~ICANON;
#else /* not HAVE_TERMIO */
sg_ours.sg_flags &= ~RAW & ~CBREAK;
if (output_only)
sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags;
#endif /* not HAVE_TERMIO */
fcntl (0, F_SETFL, tflags_ours);
fcntl (0, F_SETFL, tflags_ours);
ioctl (0, TIOCSETN, &sg_ours);
#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
ioctl (0, TIOCSETC, &tc_ours);
#endif
#ifdef TIOCGLTC
ioctl (0, TIOCSLTC, &ltc_ours);
#endif
#ifdef TIOCLGET
ioctl (0, TIOCLSET, &lmode_ours);
#endif
#ifdef HAVE_TERMIO
sg_ours.c_lflag |= ICANON;
#else /* not HAVE_TERMIO */
sg_ours.sg_flags &= ~RAW & ~CBREAK;
#endif /* not HAVE_TERMIO */
}
/* ARGSUSED */
void
term_info (arg, from_tty)
char *arg;
int from_tty;
{
target_terminal_info (arg, from_tty);
}
void
child_terminal_info (args, from_tty)
char *args;
int from_tty;
{
register int i;
printf_filtered ("Inferior's terminal status (currently saved by GDB):\n");
#ifdef HAVE_TERMIO
printf_filtered ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n",
tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag);
printf_filtered ("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_filtered ("c_cc: ");
for (i = 0; (i < NCC); i += 1)
printf_filtered ("0x%x ", sg_inferior.c_cc[i]);
printf_filtered ("\n");
#else /* not HAVE_TERMIO */
printf_filtered ("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 */
#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
printf_filtered ("tchars: ");
for (i = 0; i < (int)sizeof (struct tchars); i++)
printf_filtered ("0x%x ", ((char *)&tc_inferior)[i]);
printf_filtered ("\n");
#endif
#ifdef TIOCGLTC
printf_filtered ("ltchars: ");
for (i = 0; i < (int)sizeof (struct ltchars); i++)
printf_filtered ("0x%x ", ((char *)&ltc_inferior)[i]);
printf_filtered ("\n");
#endif
#ifdef TIOCLGET
printf_filtered ("lmode: 0x%x\n", lmode_inferior);
#endif
}
/* NEW_TTY is called in new child processes under Unix, which will
become debugger target processes.
If the TTYNAME argument is non-null, we switch to that tty for further
input and output. In either case, we remember the setup. */
void
new_tty (ttyname)
char *ttyname;
{
register int tty;
/* Save the name for later, for determining whether we and the child
are sharing a tty. */
inferior_thisrun_terminal = ttyname;
if (ttyname == 0)
return;
#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)
{
print_sys_errmsg (ttyname, errno);
_exit(1);
}
/* Avoid use of dup2; doesn't exist on all systems. */
if (tty != 0)
{ close (0); dup (tty); }
if (tty != 1)
{ close (1); dup (tty); }
if (tty != 2)
{ close (2); dup (tty); }
if (tty > 2)
close(tty);
}
/* Kill the inferior process. Make us have no inferior. */
/* ARGSUSED */
static void
kill_command (arg, from_tty)
char *arg;
int from_tty;
{
if (inferior_pid == 0)
error ("The program is not being run.");
if (!query ("Kill the inferior process? "))
error ("Not confirmed.");
target_kill (arg, from_tty);
}
/* The inferior process has died. Long live the inferior! */
void
generic_mourn_inferior ()
{
inferior_pid = 0;
attach_flag = 0;
mark_breakpoints_out ();
registers_changed ();
#ifdef CLEAR_DEFERRED_STORES
/* Delete any pending stores to the inferior... */
CLEAR_DEFERRED_STORES;
#endif
select_frame ((FRAME) 0, -1);
reopen_exec_file ();
if (target_has_stack)
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
read_pc ()));
else
set_current_frame (0);
/* It is confusing to the user for ignore counts to stick around
from previous runs of the inferior. So clear them. */
breakpoint_clear_ignore_counts ();
}
void
child_mourn_inferior ()
{
unpush_target (&child_ops);
generic_mourn_inferior ();
}
#if 0
/* This function is just for testing, and on some systems (Sony NewsOS
3.2) <sys/user.h> also includes <sys/time.h> which leads to errors
(since on this system at least sys/time.h is not protected against
multiple inclusion). */
/* ARGSUSED */
static void
try_writing_regs_command (arg, from_tty)
char *arg;
int from_tty;
{
register int i;
register int value;
if (inferior_pid == 0)
error ("There is no inferior process now.");
/* A Sun 3/50 or 3/60 (at least) running SunOS 4.0.3 will have a
kernel panic if we try to write past the end of the user area.
Presumably Sun will fix this bug (it has been reported), but it
is tacky to crash the system, so at least on SunOS4 we need to
stop writing when we hit the end of the user area. */
for (i = 0; i < sizeof (struct user); 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);
}
}
#endif
void
_initialize_inflow ()
{
add_info ("terminal", term_info,
"Print inferior's saved terminal status.");
#if 0
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.");
#endif
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);
#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
ioctl (0, TIOCGETC, &tc_ours);
#endif
#ifdef TIOCGLTC
ioctl (0, TIOCGLTC, &ltc_ours);
#endif
#ifdef TIOCLGET
ioctl (0, TIOCLGET, &lmode_ours);
#endif
#ifdef TIOCGPGRP
ioctl (0, TIOCGPGRP, &pgrp_ours);
#endif /* TIOCGPGRP */
terminal_is_ours = 1;
}

397
gdb/infptrace.c Normal file
View file

@ -0,0 +1,397 @@
/* Low level Unix child interface to ptrace, for GDB when running under Unix.
Copyright (C) 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/ptrace.h>
#if !defined (PT_KILL)
#define PT_KILL 8
#define PT_STEP 9
#define PT_CONTINUE 7
#define PT_READ_U 3
#define PT_WRITE_U 6
#define PT_READ_I 1
#define PT_WRITE_I 4
/* The Following Change is for a Sun */
#define PT_WRITE_D 4
#endif /* No PT_KILL. */
#ifndef PT_ATTACH
#define PT_ATTACH PTRACE_ATTACH
#endif
#ifndef PT_DETACH
#define PT_DETACH PTRACE_DETACH
#endif
#include "gdbcore.h"
#include <sys/user.h> /* After a.out.h */
#include <sys/file.h>
#include <sys/stat.h>
/* 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, addr, data)
int request, pid, *addr, data;
{
return ptrace (request, pid, addr, data);
}
#ifdef DEBUG_PTRACE
/* For the rest of the file, use an extra level of indirection */
/* This lets us breakpoint usefully on call_ptrace. */
#define ptrace call_ptrace
#endif
/* This is used when GDB is exiting. It gives less chance of error.*/
void
kill_inferior_fast ()
{
if (inferior_pid == 0)
return;
ptrace (PT_KILL, inferior_pid, 0, 0);
wait ((int *)0);
}
void
kill_inferior (args, from_tty)
char *args;
int from_tty;
{
kill_inferior_fast ();
target_mourn_inferior ();
}
/* Resume execution of the inferior process.
If STEP is nonzero, single-step it.
If SIGNAL is nonzero, give it that signal. */
void
child_resume (step, signal)
int step;
int signal;
{
errno = 0;
/* An address of (int *)1 tells it to continue from where it was.
(If GDB wanted it to start some other way, we have already written
a new PC value to the child.) */
if (step)
{
#if defined (NO_SINGLE_STEP)
single_step (signal);
#else /* Have single step. */
ptrace (PT_STEP, inferior_pid, (int *)1, signal);
#endif /* Have single step. */
}
else
ptrace (PT_CONTINUE, inferior_pid, (int *)1, signal);
if (errno)
perror_with_name ("ptrace");
}
#ifdef ATTACH_DETACH
/* Nonzero if we are debugging an attached process rather than
an inferior. */
extern int attach_flag;
/* Start debugging the process whose number is PID. */
int
attach (pid)
int pid;
{
errno = 0;
ptrace (PT_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 (PT_DETACH, inferior_pid, 1, signal);
if (errno)
perror_with_name ("ptrace");
attach_flag = 0;
}
#endif /* ATTACH_DETACH */
#if !defined (FETCH_INFERIOR_REGISTERS)
/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0
to get the offset in the core file of the register values. */
#if defined (KERNEL_U_ADDR_BSD)
/* Get kernel_u_addr using BSD-style nlist(). */
CORE_ADDR kernel_u_addr;
void
_initialize_kernel_u_addr ()
{
struct nlist names[2];
names[0].n_un.n_name = "_u";
names[1].n_un.n_name = NULL;
if (nlist ("/vmunix", names) == 0)
kernel_u_addr = names[0].n_value;
else
fatal ("Unable to get kernel u area address.");
}
#endif /* KERNEL_U_ADDR_BSD. */
#if defined (KERNEL_U_ADDR_HPUX)
/* Get kernel_u_addr using HPUX-style nlist(). */
CORE_ADDR kernel_u_addr;
struct hpnlist {
char * n_name;
long n_value;
unsigned char n_type;
unsigned char n_length;
short n_almod;
short n_unused;
};
static struct hpnlist nl[] = {{ "_u", -1, }, { (char *) 0, }};
/* read the value of the u area from the hp-ux kernel */
void _initialize_kernel_u_addr ()
{
struct user u;
nlist ("/hp-ux", &nl);
kernel_u_addr = nl[0].n_value;
}
#endif /* KERNEL_U_ADDR_HPUX. */
#if !defined (offsetof)
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
#endif
/* U_REGS_OFFSET is the offset of the registers within the u area. */
#if !defined (U_REGS_OFFSET)
#define U_REGS_OFFSET \
ptrace (PT_READ_U, inferior_pid, \
(int *)(offsetof (struct user, u_ar0)), 0) - KERNEL_U_ADDR
#endif
/* Fetch one register. */
static void
fetch_register (regno)
int regno;
{
register unsigned int regaddr;
char buf[MAX_REGISTER_RAW_SIZE];
register int i;
/* Offset of registers within the u area. */
unsigned int offset = U_REGS_OFFSET;
regaddr = register_addr (regno, offset);
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
{
*(int *) &buf[i] = ptrace (PT_READ_U, inferior_pid, (int *)regaddr, 0);
regaddr += sizeof (int);
}
supply_register (regno, buf);
}
/* Fetch all registers, or just one, from the child process.
We should check for errors, but we don't. FIXME. */
int
fetch_inferior_registers (regno)
int regno;
{
if (regno == -1)
for (regno = 0; regno < NUM_REGS; regno++)
fetch_register (regno);
else
fetch_register (regno);
return 0;
}
/* Registers we shouldn't try to store. */
#if !defined (CANNOT_STORE_REGISTER)
#define CANNOT_STORE_REGISTER(regno) 0
#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). */
int
store_inferior_registers (regno)
int regno;
{
register unsigned int regaddr;
char buf[80];
extern char registers[];
register int i;
int result = 0;
unsigned int offset = U_REGS_OFFSET;
if (regno >= 0)
{
regaddr = register_addr (regno, offset);
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
{
errno = 0;
ptrace (PT_WRITE_U, inferior_pid, (int *)regaddr,
*(int *) &registers[REGISTER_BYTE (regno) + i]);
if (errno != 0)
{
sprintf (buf, "writing register number %d(%d)", regno, i);
perror_with_name (buf);
result = -1;
}
regaddr += sizeof(int);
}
}
else
{
for (regno = 0; regno < NUM_REGS; regno++)
{
if (CANNOT_STORE_REGISTER (regno))
continue;
regaddr = register_addr (regno, offset);
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
{
errno = 0;
ptrace (PT_WRITE_U, inferior_pid, (int *)regaddr,
*(int *) &registers[REGISTER_BYTE (regno) + i]);
if (errno != 0)
{
sprintf (buf, "writing register number %d(%d)", regno, i);
perror_with_name (buf);
result = -1;
}
regaddr += sizeof(int);
}
}
}
return result;
}
#endif /* !defined (FETCH_INFERIOR_REGISTERS). */
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
in the NEW_SUN_PTRACE case.
It ought to be straightforward. But it appears that writing did
not write the data that I specified. I cannot understand where
it got the data that it actually did write. */
/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
to debugger memory starting at MYADDR. Copy to inferior if
WRITE is nonzero.
Returns the length copied, which is either the LEN argument or zero.
This xfer function does not do partial moves, since child_ops
doesn't allow memory operations to cross below us in the target stack
anyway. */
int
child_xfer_memory (memaddr, myaddr, len, write)
CORE_ADDR memaddr;
char *myaddr;
int len;
int write;
{
register int i;
/* Round starting address down to longword boundary. */
register CORE_ADDR addr = memaddr & - sizeof (int);
/* Round ending address up; get number of longwords that makes. */
register int count
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
/* Allocate buffer of that many longwords. */
register int *buffer = (int *) alloca (count * sizeof (int));
if (write)
{
/* Fill start and end extra bytes of buffer with existing memory data. */
if (addr != memaddr || len < (int)sizeof (int)) {
/* Need part of initial word -- fetch it. */
buffer[0] = ptrace (PT_READ_I, inferior_pid, (int *)addr, 0);
}
if (count > 1) /* FIXME, avoid if even boundary */
{
buffer[count - 1]
= ptrace (PT_READ_I, inferior_pid,
(int *)(addr + (count - 1) * sizeof (int)), 0);
}
/* Copy data to be written over corresponding part of buffer */
bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
/* Write the entire buffer. */
for (i = 0; i < count; i++, addr += sizeof (int))
{
errno = 0;
ptrace (PT_WRITE_D, inferior_pid, (int *)addr, buffer[i]);
if (errno)
{
/* Using the appropriate one (I or D) is necessary for
Gould NP1, at least. */
errno = 0;
ptrace (PT_WRITE_I, inferior_pid, (int *)addr, buffer[i]);
}
if (errno)
return 0;
}
}
else
{
/* Read all the longwords */
for (i = 0; i < count; i++, addr += sizeof (int))
{
errno = 0;
buffer[i] = ptrace (PT_READ_I, inferior_pid, (int *)addr, 0);
if (errno)
return 0;
QUIT;
}
/* Copy appropriate bytes out of the buffer. */
bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
}
return len;
}

1690
gdb/infrun.c Normal file

File diff suppressed because it is too large Load diff

182
gdb/inftarg.c Normal file
View file

@ -0,0 +1,182 @@
/* Subroutines for handling an "inferior" (child) process as a target
for debugging, in GDB.
Copyright 1990, 1991 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "param.h"
#include "frame.h" /* required by inferior.h */
#include "inferior.h"
#include "target.h"
#include "wait.h"
#include "gdbcore.h"
#include "ieee-float.h" /* Required by REGISTER_CONVERT_TO_XXX */
extern int fetch_inferior_registers();
extern int store_inferior_registers();
extern int child_xfer_memory();
extern int memory_insert_breakpoint(), memory_remove_breakpoint();
extern void terminal_init_inferior(), terminal_ours(), terminal_inferior();
extern void terminal_ours_for_output(), child_terminal_info();
extern void kill_inferior(), add_syms_addr_command();
extern struct value *call_function_by_hand();
extern void child_resume();
extern void child_create_inferior();
extern void child_mourn_inferior();
extern void child_attach ();
/* Forward declaration */
extern struct target_ops child_ops;
/* Wait for child to do something. Return pid of child, or -1 in case
of error; store status through argument pointer STATUS. */
int
child_wait (status)
int *status;
{
int pid;
do {
pid = wait (status);
if (pid == -1) /* No more children to wait for */
{
fprintf (stderr, "Child process unexpectedly missing.\n");
*status = 42; /* Claim it exited with signal 42 */
return -1;
}
} while (pid != inferior_pid); /* Some other child died or stopped */
return pid;
}
/*
* child_detach()
* takes a program previously attached to and detaches it.
* The program resumes execution and will no longer stop
* on signals, etc. We better not have left any breakpoints
* in the program or it'll die when it hits one. For this
* to work, it may be necessary for the process to have been
* previously attached. It *might* work if the program was
* started via the normal ptrace (PTRACE_TRACEME).
*/
static void
child_detach (args, from_tty)
char *args;
int from_tty;
{
int siggnal = 0;
#ifdef ATTACH_DETACH
if (from_tty)
{
char *exec_file = get_exec_file (0);
if (exec_file == 0)
exec_file = "";
printf ("Detaching program: %s pid %d\n",
exec_file, inferior_pid);
fflush (stdout);
}
if (args)
siggnal = atoi (args);
detach (siggnal);
inferior_pid = 0;
unpush_target (&child_ops); /* Pop out of handling an inferior */
#else
error ("This version of Unix does not support detaching a process.");
#endif
}
/* Get ready to modify the registers array. On machines which store
individual registers, this doesn't need to do anything. On machines
which store all the registers in one fell swoop, this makes sure
that registers contains all the registers from the program being
debugged. */
void
child_prepare_to_store ()
{
#ifdef CHILD_PREPARE_TO_STORE
CHILD_PREPARE_TO_STORE ();
#endif
}
/* Convert data from raw format for register REGNUM
to virtual format for register REGNUM. */
void
host_convert_to_virtual (regnum, from, to)
int regnum;
char *from;
char *to;
{
REGISTER_CONVERT_TO_VIRTUAL (regnum, from, to);
}
/* Convert data from virtual format for register REGNUM
to raw format for register REGNUM. */
void
host_convert_from_virtual (regnum, from, to)
int regnum;
char *from;
char *to;
{
REGISTER_CONVERT_TO_RAW (regnum, from, to);
}
/* Print status information about what we're accessing. */
static void
child_files_info ()
{
printf ("\tUsing the running image of %s process %d.\n",
attach_flag? "attached": "child", inferior_pid);
}
struct target_ops child_ops = {
"child", "Unix child process",
0, 0, /* open, close */
child_attach, child_detach,
child_resume,
child_wait,
fetch_inferior_registers, store_inferior_registers,
child_prepare_to_store,
host_convert_to_virtual, host_convert_from_virtual,
child_xfer_memory, child_files_info,
memory_insert_breakpoint, memory_remove_breakpoint,
terminal_init_inferior, terminal_inferior,
terminal_ours_for_output, terminal_ours, child_terminal_info,
kill_inferior, 0, add_syms_addr_command, /* load */
call_function_by_hand,
0, /* lookup_symbol */
child_create_inferior, child_mourn_inferior,
process_stratum, 0, /* next */
1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */
OPS_MAGIC, /* Always the last thing */
};
void
_initialize_inftarg ()
{
add_target (&child_ops);
}

26
gdb/m68k-tdep.c Normal file
View file

@ -0,0 +1,26 @@
/* Target dependent code for the Motorola 68000 series.
Copyright (C) 1990 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "ieee-float.h"
const struct ext_format ext_format_68881 [] = {
/* tot sbyte smask expbyte manbyte */
{ 12, 0, 0x80, 0,1, 4,8 }, /* mc68881 */
};

2127
gdb/main.c Normal file

File diff suppressed because it is too large Load diff

178
gdb/mem-break.c Normal file
View file

@ -0,0 +1,178 @@
/* Simulate breakpoints by patching locations in the target system.
Copyright (C) 1990 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "param.h"
#ifdef BREAKPOINT
/* This file is only useful if BREAKPOINT is set. If not, we punt. */
#include <stdio.h>
#include "breakpoint.h"
#include "inferior.h"
#include "target.h"
/* This is the sequence of bytes we insert for a breakpoint. On some
machines, breakpoints are handled by the target environment and we
don't have to worry about them here. */
static char break_insn[] = BREAKPOINT;
/* This is only to check that BREAKPOINT fits in BREAKPOINT_MAX bytes. */
static char check_break_insn_size[BREAKPOINT_MAX] = BREAKPOINT;
/* Insert a breakpoint on machines that don't have any better breakpoint
support. We read the contents of the target location and stash it,
then overwrite it with a breakpoint instruction. ADDR is the target
location in the target machine. CONTENTS_CACHE is a pointer to
memory allocated for saving the target contents. It is guaranteed
by the caller to be long enough to save sizeof BREAKPOINT bytes.
FIXME: This size is target_arch dependent and should be available in
the target_arch transfer vector, if we ever have one... */
int
memory_insert_breakpoint (addr, contents_cache)
CORE_ADDR addr;
char *contents_cache;
{
int val;
val = target_read_memory (addr, contents_cache, sizeof break_insn);
if (val == 0)
val = target_write_memory (addr, break_insn, sizeof break_insn);
return val;
}
int
memory_remove_breakpoint (addr, contents_cache)
CORE_ADDR addr;
char *contents_cache;
{
return target_write_memory (addr, contents_cache, sizeof break_insn);
}
#if 0
/* This should move back into breakpoint.c, sad to say. Encapsulate
sizeof (BREAKPOINT) by export it as an int from mem-break.c. */
/* Like target_read_memory() but if breakpoints are inserted, return
the shadow contents instead of the breakpoints themselves. */
int
read_memory_nobpt (memaddr, myaddr, len)
CORE_ADDR memaddr;
char *myaddr;
unsigned len;
{
int status;
struct breakpoint *b;
ALL_BREAKPOINTS (b)
{
if (b->address == NULL || !b->inserted)
continue;
else if (b->address + sizeof (break_insn) <= memaddr)
/* The breakpoint is entirely before the chunk of memory
we are reading. */
continue;
else if (b->address >= memaddr + len)
/* The breakpoint is entirely after the chunk of memory we
are reading. */
continue;
else
{
/* Copy the breakpoint from the shadow contents, and recurse
for the things before and after. */
/* Addresses and length of the part of the breakpoint that
we need to copy. */
CORE_ADDR membpt = b->address;
unsigned int bptlen = sizeof (break_insn);
/* Offset within shadow_contents. */
int bptoffset = 0;
if (membpt < memaddr)
{
/* Only copy the second part of the breakpoint. */
bptlen -= memaddr - membpt;
bptoffset = memaddr - membpt;
membpt = memaddr;
}
if (membpt + bptlen > memaddr + len)
{
/* Only copy the first part of the breakpoint. */
bptlen -= (membpt + bptlen) - (memaddr + len);
}
bcopy (b->shadow_contents + bptoffset,
myaddr + membpt - memaddr, bptlen);
if (membpt > memaddr)
{
/* Copy the section of memory before the breakpoint. */
status = read_memory_nobpt (memaddr, myaddr, membpt - memaddr);
if (status != 0)
return status;
}
if (membpt + bptlen < memaddr + len)
{
/* Copy the section of memory after the breakpoint. */
status = read_memory_nobpt
(membpt + bptlen,
myaddr + membpt + bptlen - memaddr,
memaddr + len - (membpt + bptlen));
if (status != 0)
return status;
}
return 0;
}
}
/* Nothing overlaps. Just call read_memory_noerr. */
return target_read_memory (memaddr, myaddr, len);
}
#endif /* 0 */
#else /* BREAKPOINT */
char nogo[] = "Breakpoints not implemented for this target.";
int
memory_insert_breakpoint (addr, contents_cache)
CORE_ADDR addr;
char *contents_cache;
{
error (nogo);
return 0; /* lint */
}
int
memory_remove_breakpoint (addr, contents_cache)
CORE_ADDR addr;
char *contents_cache;
{
error (nogo);
return 0; /* lint */
}
#endif /* BREAKPOINT */

679
gdb/mips-tdep.c Normal file
View file

@ -0,0 +1,679 @@
/* Work with core dump and executable files, for GDB on MIPS.
This code would be in core.c if it weren't machine-dependent. */
/* Low level interface to ptrace, for GDB when running under Unix.
Copyright (C) 1988, 1989, 1990 Free Software Foundation, Inc.
Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* FIXME: Can a MIPS porter/tester determine which of these include
files we still need? -- gnu@cygnus.com */
#include <stdio.h>
#include <mips/inst.h>
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#include "symtab.h"
#include "value.h"
#include "gdbcmd.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ioctl.h>
#include "gdbcore.h"
#ifndef MIPSMAGIC
#ifdef MIPSEL
#define MIPSMAGIC MIPSELMAGIC
#else
#define MIPSMAGIC MIPSEBMAGIC
#endif
#endif
#define VM_MIN_ADDRESS (unsigned)0x400000
#include <sys/user.h> /* After a.out.h */
#include <sys/file.h>
#include <sys/stat.h>
#define PROC_LOW_ADDR(proc) ((proc)->adr) /* least address */
#define PROC_HIGH_ADDR(proc) ((proc)->pad2) /* upper address bound */
#define PROC_FRAME_OFFSET(proc) ((proc)->framesize)
#define PROC_FRAME_REG(proc) ((proc)->framereg)
#define PROC_REG_MASK(proc) ((proc)->regmask)
#define PROC_FREG_MASK(proc) ((proc)->fregmask)
#define PROC_REG_OFFSET(proc) ((proc)->regoffset)
#define PROC_FREG_OFFSET(proc) ((proc)->fregoffset)
#define PROC_PC_REG(proc) ((proc)->pcreg)
#define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->isym)
#define _PROC_MAGIC_ 0x0F0F0F0F
#define PROC_DESC_IS_DUMMY(proc) ((proc)->isym == _PROC_MAGIC_)
#define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->isym = _PROC_MAGIC_)
struct linked_proc_info
{
struct mips_extra_func_info info;
struct linked_proc_info *next;
} * linked_proc_desc_table = NULL;
#define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next, regno)
int
read_next_frame_reg(fi, regno)
FRAME fi;
int regno;
{
#define SIGFRAME_BASE sizeof(struct sigcontext)
#define SIGFRAME_PC_OFF (-SIGFRAME_BASE+ 2*sizeof(int))
#define SIGFRAME_SP_OFF (-SIGFRAME_BASE+32*sizeof(int))
#define SIGFRAME_RA_OFF (-SIGFRAME_BASE+34*sizeof(int))
for (; fi; fi = fi->next)
if (in_sigtramp(fi->pc, 0)) {
/* No idea if this code works. --PB. */
int offset;
if (regno == PC_REGNUM) offset = SIGFRAME_PC_OFF;
else if (regno == RA_REGNUM) offset = SIGFRAME_RA_OFF;
else if (regno == SP_REGNUM) offset = SIGFRAME_SP_OFF;
else return 0;
return read_memory_integer(fi->frame + offset, 4);
}
else if (regno == SP_REGNUM) return fi->frame;
else if (fi->saved_regs->regs[regno])
return read_memory_integer(fi->saved_regs->regs[regno], 4);
return read_register(regno);
}
int
mips_frame_saved_pc(frame)
FRAME frame;
{
mips_extra_func_info_t proc_desc = (mips_extra_func_info_t)frame->proc_desc;
int pcreg = proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM;
if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
return read_memory_integer(frame->frame - 4, 4);
#if 0
/* If in the procedure prologue, RA_REGNUM might not have been saved yet.
* Assume non-leaf functions start with:
* addiu $sp,$sp,-frame_size
* sw $ra,ra_offset($sp)
* This if the pc is pointing at either of these instructions,
* then $ra hasn't been trashed.
* If the pc has advanced beyond these two instructions,
* then $ra has been saved.
* critical, and much more complex. Handling $ra is enough to get
* a stack trace, but some register values with be wrong.
*/
if (frame->proc_desc && frame->pc < PROC_LOW_ADDR(proc_desc) + 8)
return read_register(pcreg);
#endif
return read_next_frame_reg(frame, pcreg);
}
static struct mips_extra_func_info temp_proc_desc;
static struct frame_saved_regs temp_saved_regs;
CORE_ADDR heuristic_proc_start(pc)
CORE_ADDR pc;
{
CORE_ADDR start_pc = pc;
CORE_ADDR fence = start_pc - 10000;
if (fence < VM_MIN_ADDRESS) fence = VM_MIN_ADDRESS;
/* search back for previous return */
for (start_pc -= 4; ; start_pc -= 4)
if (start_pc < fence) return 0;
else if (ABOUT_TO_RETURN(start_pc))
break;
start_pc += 8; /* skip return, and its delay slot */
#if 0
/* skip nops (usually 1) 0 - is this */
while (start_pc < pc && read_memory_integer (start_pc, 4) == 0)
start_pc += 4;
#endif
return start_pc;
}
mips_extra_func_info_t
heuristic_proc_desc(start_pc, limit_pc, next_frame)
CORE_ADDR start_pc, limit_pc;
FRAME next_frame;
{
CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM);
CORE_ADDR cur_pc;
int frame_size;
int has_frame_reg = 0;
int reg30; /* Value of $r30. Used by gcc for frame-pointer */
unsigned long reg_mask = 0;
if (start_pc == 0) return NULL;
bzero(&temp_proc_desc, sizeof(temp_proc_desc));
bzero(&temp_saved_regs, sizeof(struct frame_saved_regs));
if (start_pc + 200 < limit_pc) limit_pc = start_pc + 200;
restart:
frame_size = 0;
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) {
unsigned long word;
int status;
status = read_memory_nobpt (cur_pc, &word, 4);
if (status) memory_error (status, cur_pc);
if ((word & 0xFFFF0000) == 0x27bd0000) /* addiu $sp,$sp,-i */
frame_size += (-word) & 0xFFFF;
else if ((word & 0xFFFF0000) == 0x23bd0000) /* addu $sp,$sp,-i */
frame_size += (-word) & 0xFFFF;
else if ((word & 0xFFE00000) == 0xafa00000) { /* sw reg,offset($sp) */
int reg = (word & 0x001F0000) >> 16;
reg_mask |= 1 << reg;
temp_saved_regs.regs[reg] = sp + (short)word;
}
else if ((word & 0xFFFF0000) == 0x27be0000) { /* addiu $30,$sp,size */
if ((unsigned short)word != frame_size)
reg30 = sp + (unsigned short)word;
else if (!has_frame_reg) {
int alloca_adjust;
has_frame_reg = 1;
reg30 = read_next_frame_reg(next_frame, 30);
alloca_adjust = reg30 - (sp + (unsigned short)word);
if (alloca_adjust > 0) {
/* FP > SP + frame_size. This may be because
/* of an alloca or somethings similar.
* Fix sp to "pre-alloca" value, and try again.
*/
sp += alloca_adjust;
goto restart;
}
}
}
else if ((word & 0xFFE00000) == 0xafc00000) { /* sw reg,offset($30) */
int reg = (word & 0x001F0000) >> 16;
reg_mask |= 1 << reg;
temp_saved_regs.regs[reg] = reg30 + (short)word;
}
}
if (has_frame_reg) {
PROC_FRAME_REG(&temp_proc_desc) = 30;
PROC_FRAME_OFFSET(&temp_proc_desc) = 0;
}
else {
PROC_FRAME_REG(&temp_proc_desc) = SP_REGNUM;
PROC_FRAME_OFFSET(&temp_proc_desc) = frame_size;
}
PROC_REG_MASK(&temp_proc_desc) = reg_mask;
PROC_PC_REG(&temp_proc_desc) = RA_REGNUM;
return &temp_proc_desc;
}
mips_extra_func_info_t
find_proc_desc(pc, next_frame)
CORE_ADDR pc;
FRAME next_frame;
{
mips_extra_func_info_t proc_desc;
extern struct block *block_for_pc();
struct block *b = block_for_pc(pc);
struct symbol *sym =
b ? lookup_symbol(".gdbinfo.", b, LABEL_NAMESPACE, 0, NULL) : NULL;
if (sym != NULL)
{
/* IF this is the topmost frame AND
* (this proc does not have debugging information OR
* the PC is in the procedure prologue)
* THEN create a "hueristic" proc_desc (by analyzing
* the actual code) to replace the "official" proc_desc.
*/
proc_desc = (struct mips_extra_func_info *)sym->value.value;
if (next_frame == NULL) {
struct symtab_and_line val;
struct symbol *proc_symbol =
PROC_DESC_IS_DUMMY(proc_desc) ? 0 : PROC_SYMBOL(proc_desc);
if (proc_symbol) {
val = find_pc_line (BLOCK_START
(SYMBOL_BLOCK_VALUE(proc_symbol)),
0);
val.pc = val.end ? val.end : pc;
}
if (!proc_symbol || pc < val.pc) {
mips_extra_func_info_t found_heuristic =
heuristic_proc_desc(PROC_LOW_ADDR(proc_desc),
pc, next_frame);
if (found_heuristic) proc_desc = found_heuristic;
}
}
}
else
{
register struct linked_proc_info *link;
for (link = linked_proc_desc_table; link; link = link->next)
if (PROC_LOW_ADDR(&link->info) <= pc
&& PROC_HIGH_ADDR(&link->info) > pc)
return &link->info;
proc_desc =
heuristic_proc_desc(heuristic_proc_start(pc), pc, next_frame);
}
return proc_desc;
}
mips_extra_func_info_t cached_proc_desc;
FRAME_ADDR mips_frame_chain(frame)
FRAME frame;
{
extern CORE_ADDR startup_file_start; /* From blockframe.c */
mips_extra_func_info_t proc_desc;
CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
if (startup_file_start)
{ /* has at least the __start symbol */
if (saved_pc == 0 || !outside_startup_file (saved_pc)) return 0;
}
else
{ /* This hack depends on the internals of __start. */
/* We also assume the breakpoints are *not* inserted */
if (read_memory_integer (saved_pc + 8, 4) & 0xFC00003F == 0xD)
return 0; /* break */
}
proc_desc = find_proc_desc(saved_pc, frame);
if (!proc_desc) return 0;
cached_proc_desc = proc_desc;
return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
+ PROC_FRAME_OFFSET(proc_desc);
}
void
init_extra_frame_info(fci)
struct frame_info *fci;
{
extern struct obstack frame_cache_obstack;
/* Use proc_desc calculated in frame_chain */
mips_extra_func_info_t proc_desc = fci->next ? cached_proc_desc :
find_proc_desc(fci->pc, fci->next);
fci->saved_regs = (struct frame_saved_regs*)
obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
bzero(fci->saved_regs, sizeof(struct frame_saved_regs));
fci->proc_desc =
proc_desc == &temp_proc_desc ? (char*)NULL : (char*)proc_desc;
if (proc_desc)
{
int ireg;
CORE_ADDR reg_position;
unsigned long mask;
/* r0 bit means kernel trap */
int kernel_trap = PROC_REG_MASK(proc_desc) & 1;
/* Fixup frame-pointer - only needed for top frame */
/* This may not be quite right, if procedure has a real frame register */
if (fci->pc == PROC_LOW_ADDR(proc_desc))
fci->frame = read_register (SP_REGNUM);
else
fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc))
+ PROC_FRAME_OFFSET(proc_desc);
if (proc_desc == &temp_proc_desc)
*fci->saved_regs = temp_saved_regs;
else
{
/* find which general-purpose registers were saved */
reg_position = fci->frame + PROC_REG_OFFSET(proc_desc);
mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc);
for (ireg= 31; mask; --ireg, mask <<= 1)
if (mask & 0x80000000)
{
fci->saved_regs->regs[ireg] = reg_position;
reg_position -= 4;
}
/* find which floating-point registers were saved */
reg_position = fci->frame + PROC_FREG_OFFSET(proc_desc);
/* The freg_offset points to where the first *double* register is saved.
* So skip to the high-order word. */
reg_position += 4;
mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc);
for (ireg = 31; mask; --ireg, mask <<= 1)
if (mask & 0x80000000)
{
fci->saved_regs->regs[32+ireg] = reg_position;
reg_position -= 4;
}
}
/* hack: if argument regs are saved, guess these contain args */
if ((PROC_REG_MASK(proc_desc) & 0xF0) == 0) fci->num_args = -1;
else if ((PROC_REG_MASK(proc_desc) & 0x80) == 0) fci->num_args = 4;
else if ((PROC_REG_MASK(proc_desc) & 0x40) == 0) fci->num_args = 3;
else if ((PROC_REG_MASK(proc_desc) & 0x20) == 0) fci->num_args = 2;
else if ((PROC_REG_MASK(proc_desc) & 0x10) == 0) fci->num_args = 1;
fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM];
}
if (fci->next == 0)
supply_register(FP_REGNUM, &fci->frame);
}
CORE_ADDR mips_push_arguments(nargs, args, sp, struct_return, struct_addr)
int nargs;
value *args;
CORE_ADDR sp;
int struct_return;
CORE_ADDR struct_addr;
{
CORE_ADDR buf;
register i;
int accumulate_size = struct_return ? 4 : 0;
struct mips_arg { char *contents; int len; int offset; };
struct mips_arg *mips_args =
(struct mips_arg*)alloca(nargs * sizeof(struct mips_arg));
register struct mips_arg *m_arg;
for (i = 0, m_arg = mips_args; i < nargs; i++, m_arg++) {
extern value value_arg_coerce();
value arg = value_arg_coerce (args[i]);
m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg));
/* This entire mips-specific routine is because doubles must be aligned
* on 8-byte boundaries. It still isn't quite right, because MIPS decided
* to align 'struct {int a, b}' on 4-byte boundaries (even though this
* breaks their varargs implementation...). A correct solution
* requires an simulation of gcc's 'alignof' (and use of 'alignof'
* in stdarg.h/varargs.h).
*/
if (m_arg->len > 4) accumulate_size = (accumulate_size + 7) & -8;
m_arg->offset = accumulate_size;
accumulate_size = (accumulate_size + m_arg->len + 3) & -4;
m_arg->contents = VALUE_CONTENTS(arg);
}
accumulate_size = (accumulate_size + 7) & (-8);
if (accumulate_size < 16) accumulate_size = 16;
sp -= accumulate_size;
for (i = nargs; m_arg--, --i >= 0; )
write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len);
if (struct_return) {
buf = struct_addr;
write_memory(sp, &buf, sizeof(CORE_ADDR));
}
return sp;
}
/* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31. */
#define MASK(i,j) ((1 << (j)+1)-1 ^ (1 << (i))-1)
void
mips_push_dummy_frame()
{
int ireg;
struct linked_proc_info *link = (struct linked_proc_info*)
xmalloc(sizeof(struct linked_proc_info));
mips_extra_func_info_t proc_desc = &link->info;
CORE_ADDR sp = read_register (SP_REGNUM);
CORE_ADDR save_address;
REGISTER_TYPE buffer;
link->next = linked_proc_desc_table;
linked_proc_desc_table = link;
#define PUSH_FP_REGNUM 16 /* must be a register preserved across calls */
#define GEN_REG_SAVE_MASK MASK(1,16)|MASK(24,28)|(1<<31)
#define GEN_REG_SAVE_COUNT 22
#define FLOAT_REG_SAVE_MASK MASK(0,19)
#define FLOAT_REG_SAVE_COUNT 20
#define SPECIAL_REG_SAVE_COUNT 4
/*
* The registers we must save are all those not preserved across
* procedure calls. Dest_Reg (see tm-mips.h) must also be saved.
* In addition, we must save the PC, and PUSH_FP_REGNUM.
* (Ideally, we should also save MDLO/-HI and FP Control/Status reg.)
*
* Dummy frame layout:
* (high memory)
* Saved PC
* Saved MMHI, MMLO, FPC_CSR
* Saved R31
* Saved R28
* ...
* Saved R1
* Saved D18 (i.e. F19, F18)
* ...
* Saved D0 (i.e. F1, F0)
* CALL_DUMMY (subroutine stub; see m-mips.h)
* Parameter build area (not yet implemented)
* (low memory)
*/
PROC_REG_MASK(proc_desc) = GEN_REG_SAVE_MASK;
PROC_FREG_MASK(proc_desc) = FLOAT_REG_SAVE_MASK;
PROC_REG_OFFSET(proc_desc) = /* offset of (Saved R31) from FP */
-sizeof(long) - 4 * SPECIAL_REG_SAVE_COUNT;
PROC_FREG_OFFSET(proc_desc) = /* offset of (Saved D18) from FP */
-sizeof(double) - 4 * (SPECIAL_REG_SAVE_COUNT + GEN_REG_SAVE_COUNT);
/* save general registers */
save_address = sp + PROC_REG_OFFSET(proc_desc);
for (ireg = 32; --ireg >= 0; )
if (PROC_REG_MASK(proc_desc) & (1 << ireg))
{
buffer = read_register (ireg);
write_memory (save_address, &buffer, sizeof(REGISTER_TYPE));
save_address -= 4;
}
/* save floating-points registers */
save_address = sp + PROC_FREG_OFFSET(proc_desc);
for (ireg = 32; --ireg >= 0; )
if (PROC_FREG_MASK(proc_desc) & (1 << ireg))
{
buffer = read_register (ireg);
write_memory (save_address, &buffer, 4);
save_address -= 4;
}
write_register (PUSH_FP_REGNUM, sp);
PROC_FRAME_REG(proc_desc) = PUSH_FP_REGNUM;
PROC_FRAME_OFFSET(proc_desc) = 0;
buffer = read_register (PC_REGNUM);
write_memory (sp - 4, &buffer, sizeof(REGISTER_TYPE));
buffer = read_register (HI_REGNUM);
write_memory (sp - 8, &buffer, sizeof(REGISTER_TYPE));
buffer = read_register (LO_REGNUM);
write_memory (sp - 12, &buffer, sizeof(REGISTER_TYPE));
buffer = read_register (FCRCS_REGNUM);
write_memory (sp - 16, &buffer, sizeof(REGISTER_TYPE));
sp -= 4 * (GEN_REG_SAVE_COUNT+FLOAT_REG_SAVE_COUNT+SPECIAL_REG_SAVE_COUNT);
write_register (SP_REGNUM, sp);
PROC_LOW_ADDR(proc_desc) = sp - CALL_DUMMY_SIZE + CALL_DUMMY_START_OFFSET;
PROC_HIGH_ADDR(proc_desc) = sp;
SET_PROC_DESC_IS_DUMMY(proc_desc);
PROC_PC_REG(proc_desc) = RA_REGNUM;
}
void
mips_pop_frame()
{ register int regnum;
FRAME frame = get_current_frame ();
CORE_ADDR new_sp = frame->frame;
mips_extra_func_info_t proc_desc = (mips_extra_func_info_t)frame->proc_desc;
if (PROC_DESC_IS_DUMMY(proc_desc))
{
struct linked_proc_info **ptr = &linked_proc_desc_table;;
for (; &ptr[0]->info != proc_desc; ptr = &ptr[0]->next )
if (ptr[0] == NULL) abort();
*ptr = ptr[0]->next;
free (ptr[0]);
write_register (HI_REGNUM, read_memory_integer(new_sp - 8, 4));
write_register (LO_REGNUM, read_memory_integer(new_sp - 12, 4));
write_register (FCRCS_REGNUM, read_memory_integer(new_sp - 16, 4));
}
write_register (PC_REGNUM, FRAME_SAVED_PC(frame));
if (frame->proc_desc) {
for (regnum = 32; --regnum >= 0; )
if (PROC_REG_MASK(proc_desc) & (1 << regnum))
write_register (regnum,
read_memory_integer (frame->saved_regs->regs[regnum], 4));
for (regnum = 64; --regnum >= 32; )
if (PROC_FREG_MASK(proc_desc) & (1 << regnum))
write_register (regnum,
read_memory_integer (frame->saved_regs->regs[regnum], 4));
}
write_register (SP_REGNUM, new_sp);
flush_cached_frames ();
set_current_frame (create_new_frame (new_sp, read_pc ()));
}
static mips_print_register(regnum, all)
int regnum, all;
{
unsigned char raw_buffer[8];
REGISTER_TYPE val;
read_relative_register_raw_bytes (regnum, raw_buffer);
if (!(regnum & 1) && regnum >= FP0_REGNUM && regnum < FP0_REGNUM+32) {
read_relative_register_raw_bytes (regnum+1, raw_buffer+4);
printf_filtered ("(d%d: ", regnum&31);
val_print (builtin_type_double, raw_buffer, 0,
stdout, 0, 1, 0, Val_pretty_default);
printf_filtered ("); ", regnum&31);
}
fputs_filtered (reg_names[regnum], stdout);
#ifndef NUMERIC_REG_NAMES
if (regnum < 32)
printf_filtered ("(r%d): ", regnum);
else
#endif
printf_filtered (": ");
/* If virtual format is floating, print it that way. */
if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
&& ! INVALID_FLOAT (raw_buffer, REGISTER_VIRTUAL_SIZE(regnum))) {
val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0,
stdout, 0, 1, 0, Val_pretty_default);
}
/* Else print as integer in hex. */
else
{
long val;
bcopy (raw_buffer, &val, sizeof (long));
if (val == 0)
printf_filtered ("0");
else if (all)
printf_filtered ("0x%x", val);
else
printf_filtered ("0x%x=%d", val, val);
}
}
mips_do_registers_info(regnum)
int regnum;
{
if (regnum != -1) {
mips_print_register (regnum, 0);
printf_filtered ("\n");
}
else {
for (regnum = 0; regnum < NUM_REGS; ) {
mips_print_register (regnum, 1);
regnum++;
if ((regnum & 3) == 0 || regnum == NUM_REGS)
printf_filtered (";\n");
else
printf_filtered ("; ");
}
}
}
/* Return number of args passed to a frame. described by FIP.
Can return -1, meaning no way to tell. */
mips_frame_num_args(fip)
FRAME fip;
{
#if 0
struct chain_info_t *p;
p = mips_find_cached_frame(FRAME_FP(fip));
if (p->valid)
return p->the_info.numargs;
#endif
return -1;
}
/* Bad floats: Returns 0 if P points to a valid IEEE floating point number,
1 if P points to a denormalized number or a NaN. LEN says whether this is
a single-precision or double-precision float */
#define SINGLE_EXP_BITS 8
#define DOUBLE_EXP_BITS 11
int
isa_NAN(p, len)
int *p, len;
{
int exponent;
if (len == 4)
{
exponent = *p;
exponent = exponent << 1 >> (32 - SINGLE_EXP_BITS - 1);
return ((exponent == -1) || (! exponent && *p));
}
else if (len == 8)
{
exponent = *(p+1);
exponent = exponent << 1 >> (32 - DOUBLE_EXP_BITS - 1);
return ((exponent == -1) || (! exponent && *p * *(p+1)));
}
else return 1;
}
/* To skip prologues, I use this predicate. Returns either PC
itself if the code at PC does not look like a function prologue,
PC+4 if it does (our caller does not need anything more fancy). */
CORE_ADDR mips_skip_prologue(pc)
CORE_ADDR pc;
{
struct symbol *f;
struct block *b;
unsigned long inst;
/* For -g modules and most functions anyways the
first instruction adjusts the stack. */
inst = read_memory_integer(pc, 4);
if ((inst & 0xffff0000) == 0x27bd0000)
return pc + 4;
/* Well, it looks like a frameless. Let's make sure.
Note that we are not called on the current PC,
but on the function`s start PC, and I have definitely
seen optimized code that adjusts the SP quite later */
b = block_for_pc(pc);
if (!b) return pc;
f = lookup_symbol(".gdbinfo.", b, LABEL_NAMESPACE, 0, NULL);
if (!f) return pc;
/* Ideally, I would like to use the adjusted info
from mips_frame_info(), but for all practical
purposes it will not matter (and it would require
a different definition of SKIP_PROLOGUE())
Actually, it would not hurt to skip the storing
of arguments on the stack as well. */
if (((struct mips_extra_func_info *)f->value.value)->framesize)
return pc + 4;
return pc;
}

2879
gdb/mipsread.c Normal file

File diff suppressed because it is too large Load diff

1960
gdb/printcmd.c Normal file

File diff suppressed because it is too large Load diff

893
gdb/remote-sa.m68k.shar Executable file
View file

@ -0,0 +1,893 @@
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Glenn Engel <glenne@labgre> on Mon Jun 12 15:19:20 1989
#
# This archive contains:
# remcom.c
#
LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH
echo x - remcom.c
cat >remcom.c <<'@EOF'
/****************************************************************************
THIS SOFTWARE IS NOT COPYRIGHTED
HP offers the following for use in the public domain. HP makes no
warranty with regard to the software or it's performance and the
user accepts the software "AS IS" with all faults.
HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
****************************************************************************/
/****************************************************************************
* $Header$
*
* $Module name: remcom.c $
* $Revision$
* $Date$
* $Contributor: Lake Stevens Instrument Division$
*
* $Description: low level support for gdb debugger. $
*
* $Considerations: only works on target hardware $
*
* $Written by: Glenn Engel $
* $ModuleState: Experimental $
*
* $NOTES: See Below $
*
* To enable debugger support, two things need to happen. One, a
* call to set_debug_traps() is necessary in order to allow any breakpoints
* or error conditions to be properly intercepted and reported to gdb.
* Two, a breakpoint needs to be generated to begin communication. This
* is most easily accomplished by a call to breakpoint(). Breakpoint()
* simulates a breakpoint by executing a trap #1.
*
* Some explanation is probably necessary to explain how exceptions are
* handled. When an exception is encountered the 68000 pushes the current
* program counter and status register onto the supervisor stack and then
* transfers execution to a location specified in it's vector table.
* The handlers for the exception vectors are hardwired to jmp to an address
* given by the relation: (exception - 256) * 6. These are decending
* addresses starting from -6, -12, -18, ... By allowing 6 bytes for
* each entry, a jsr, jmp, bsr, ... can be used to enter the exception
* handler. Using a jsr to handle an exception has an added benefit of
* allowing a single handler to service several exceptions and use the
* return address as the key differentiation. The vector number can be
* computed from the return address by [ exception = (addr + 1530) / 6 ].
* The sole purpose of the routine _catchException is to compute the
* exception number and push it on the stack in place of the return address.
* The external function exceptionHandler() is
* used to attach a specific handler to a specific 68k exception.
* For 68020 machines, the ability to have a return address around just
* so the vector can be determined is not necessary because the '020 pushes an
* extra word onto the stack containing the vector offset
*
* Because gdb will sometimes write to the stack area to execute function
* calls, this program cannot rely on using the supervisor stack so it
* uses it's own stack area reserved in the int array remcomStack.
*
*************
*
* The following gdb commands are supported:
*
* command function Return value
*
* g return the value of the CPU registers hex data or ENN
* G set the value of the CPU registers OK or ENN
*
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
*
* c Resume at current address SNN ( signal NN)
* cAA..AA Continue at address AA..AA SNN
*
* s Step one instruction SNN
* sAA..AA Step one instruction from AA..AA SNN
*
* k kill
*
* ? What was the last sigval ? SNN (signal NN)
*
* All commands and responses are sent with a packet which includes a
* checksum. A packet consists of
*
* $<packet info>#<checksum>.
*
* where
* <packet info> :: <characters representing the command or response>
* <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
*
* When a packet is received, it is first acknowledged with either '+' or '-'.
* '+' indicates a successful transfer. '-' indicates a failed transfer.
*
* Example:
*
* Host: Reply:
* $m0,10#2a +$00010203040506070809101112131415#42
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
/************************************************************************
*
* external low-level support routines
*/
typedef void (*ExceptionHook)(int); /* pointer to function with int parm */
typedef void (*Function)(); /* pointer to a function */
extern putDebugChar(); /* write a single character */
extern getDebugChar(); /* read and return a single char */
extern Function exceptionHandler(); /* assign an exception handler */
extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */
/************************************************************************/
/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
/* at least NUMREGBYTES*2 are needed for register packets */
#define BUFMAX 400
static char initialized; /* boolean flag. != 0 means we've been initialized */
int remote_debug = 0;
/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
char hexchars[]="0123456789abcdef";
/* there are 180 bytes of registers on a 68020 w/68881 */
/* many of the fpa registers are 12 byte (96 bit) registers */
#define NUMREGBYTES 180
enum regnames {D0,D1,D2,D3,D4,D5,D6,D7,
A0,A1,A2,A3,A4,A5,A6,A7,
PS,PC,
FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7,
FPCONTROL,FPSTATUS,FPIADDR
};
typedef struct FrameStruct
{
struct FrameStruct *previous;
int exceptionPC; /* pc value when this frame created */
int exceptionVector; /* cpu vector causing exception */
short frameSize; /* size of cpu frame in words */
short sr; /* for 68000, this not always sr */
int pc;
short format;
int fsaveHeader;
int morejunk[0]; /* exception frame, fp save... */
} Frame;
#define FRAMESIZE 500
static Frame *lastFrame;
static int frameStack[FRAMESIZE];
/*
* these should not be static cuz they can be used outside this module
*/
int registers[NUMREGBYTES/4];
int superStack;
static int remcomStack[400];
static int* stackPtr = &remcomStack[399];
/*
* In many cases, the system will want to continue exception processing
* when a continue command is given.
* oldExceptionHook is a function to invoke in this case.
*/
static ExceptionHook oldExceptionHook;
/* the size of the exception stack on the 68020 varies with the type of
* exception. The following table is the number of WORDS used
* for each exception format.
*/
static short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,4,4,4,4 };
/************* jump buffer used for setjmp/longjmp **************************/
jmp_buf env;
/*************************** ASSEMBLY CODE MACROS *************************/
/* */
#ifdef __HAVE_68881__
/* do an fsave, then remember the address to begin a restore from */
#define SAVE_FP_REGS() asm(" fsave a0@-"); \
asm(" fmovemx fp0-fp7,_registers+72"); \
asm(" fmoveml fpcr/fpsr/fpi,_registers+168");
#define RESTORE_FP_REGS() asm(" fmoveml _registers+168,fpcr/fpsr/fpi"); \
asm(" fmovemx _registers+72,fp0-fp7"); \
asm(" frestore a0@+");
#else
#define SAVE_FP_REGS()
#define RESTORE_FP_REGS()
#endif /* __HAVE_68881__ */
asm("
.text
.globl _return_to_super
_return_to_super:
movel _registers+60,sp /* get new stack pointer */
movel _lastFrame,a0 /* get last frame info */
bra return_to_any
.globl _return_to_user
_return_to_user:
movel _registers+60,a0 /* get usp */
movel a0,usp /* set usp */
movel _superStack,sp /* get original stack pointer */
return_to_any:
movel _lastFrame,a0 /* get last frame info */
movel a0@+,_lastFrame /* link in previous frame */
addql #8,a0 /* skip over pc, vector#*/
movew a0@+,d0 /* get # of words in cpu frame */
addw d0,a0 /* point to end of data */
addw d0,a0 /* point to end of data */
movel a0,a1
#
# copy the stack frame
subql #1,d0
copyUserLoop:
movew a1@-,sp@-
dbf d0,copyUserLoop
");
RESTORE_FP_REGS()
asm(" moveml _registers,d0-d7/a0-a6");
asm(" rte"); /* pop and go! */
#define DISABLE_INTERRUPTS() asm(" oriw #0x0700,sr");
#define BREAKPOINT() asm(" trap #1");
/* this function is called immediately when a level 7 interrupt occurs */
/* if the previous interrupt level was 7 then we're already servicing */
/* this interrupt and an rte is in order to return to the debugger. */
/* For the 68000, the offset for sr is 6 due to the jsr return address */
asm("
.text
.globl __debug_level7
__debug_level7:
movew d0,sp@-");
#ifdef mc68020
asm(" movew sp@(2),d0");
#else
asm(" movew sp@(6),d0");
#endif
asm(" andiw #0x700,d0
cmpiw #0x700,d0
beq _already7
movew sp@+,d0
bra __catchException
_already7:
movew sp@+,d0");
#ifndef mc68020
asm(" lea sp@(4),sp"); /* pull off 68000 return address */
#endif
asm(" rte");
extern void _catchException();
#ifdef mc68020
/* This function is called when a 68020 exception occurs. It saves
* all the cpu and fpcp regs in the _registers array, creates a frame on a
* linked list of frames which has the cpu and fpcp stack frames needed
* to properly restore the context of these processors, and invokes
* an exception handler (remcom_handler).
*
* stack on entry: stack on exit:
* N bytes of junk exception # MSWord
* Exception Format Word exception # MSWord
* Program counter LSWord
* Program counter MSWord
* Status Register
*
*
*/
asm("
.text
.globl __catchException
__catchException:");
DISABLE_INTERRUPTS();
asm("
moveml d0-d7/a0-a6,_registers /* save registers */
movel _lastFrame,a0 /* last frame pointer */
");
SAVE_FP_REGS();
asm("
lea _registers,a5 /* get address of registers */
movew sp@,d1 /* get status register */
movew d1,a5@(66) /* save sr */
movel sp@(2),a4 /* save pc in a4 for later use */
movel a4,a5@(68) /* save pc in _regisers[] */
#
# figure out how many bytes in the stack frame
movew sp@(6),d0 /* get '020 exception format */
movew d0,d2 /* make a copy of format word */
andiw #0xf000,d0 /* mask off format type */
rolw #5,d0 /* rotate into the low byte *2 */
lea _exceptionSize,a1
addw d0,a1 /* index into the table */
movew a1@,d0 /* get number of words in frame */
movew d0,d3 /* save it */
subw d0,a0 /* adjust save pointer */
subw d0,a0 /* adjust save pointer(bytes) */
movel a0,a1 /* copy save pointer */
subql #1,d0 /* predecrement loop counter */
#
# copy the frame
saveFrameLoop:
movew sp@+,a1@+
dbf d0,saveFrameLoop
#
# now that the stack has been clenaed,
# save the a7 in use at time of exception
movel sp,_superStack /* save supervisor sp */
andiw #0x2000,d1 /* were we in supervisor mode ? */
beq userMode
movel a7,a5@(60) /* save a7 */
bra a7saveDone
userMode:
movel usp,a1
movel a1,a5@(60) /* save user stack pointer */
a7saveDone:
#
# save size of frame
movew d3,a0@-
#
# compute exception number
andl #0xfff,d2 /* mask off vector offset */
lsrw #2,d2 /* divide by 4 to get vect num */
movel d2,a0@- /* save it */
#
# save pc causing exception
movel a4,a0@-
#
# save old frame link and set the new value
movel _lastFrame,a1 /* last frame pointer */
movel a1,a0@- /* save pointer to prev frame */
movel a0,_lastFrame
movel d2,sp@- /* push exception num */
movel _exceptionHook,a0 /* get address of handler */
jbsr a0@ /* and call it */
jmp __returnFromException /* now, return */
");
#else /* mc68000 */
/* This function is called when an exception occurs. It translates the
* return address found on the stack into an exception vector # which
* is then handled by either handle_exception or a system handler.
* _catchException provides a front end for both.
*
* stack on entry: stack on exit:
* Program counter MSWord exception # MSWord
* Program counter LSWord exception # MSWord
* Status Register
* Return Address MSWord
* Return Address LSWord
*/
asm("
.text
.globl __catchException
__catchException:");
DISABLE_INTERRUPTS();
asm("
moveml d0-d7/a0-a6,_registers /* save registers */
movel _lastFrame,a0 /* last frame pointer */
");
SAVE_FP_REGS();
asm("
lea _registers,a5 /* get address of registers */
movel sp@+,d2 /* pop return address */
addl #1530,d2 /* convert return addr to */
divs #6,d2 /* exception number */
extl d2
moveql #3,d3 /* assume a three word frame */
cmpiw #3,d2 /* bus error or address error ? */
bgt normal /* if >3 then normal error */
movel sp@+,a0@- /* copy error info to frame buff*/
movel sp@+,a0@- /* these are never used */
moveql #7,d3 /* this is a 7 word frame */
normal:
movew sp@+,d1 /* pop status register */
movel sp@+,a4 /* pop program counter */
movew d1,a5@(66) /* save sr */
movel a4,a5@(68) /* save pc in _regisers[] */
movel a4,a0@- /* copy pc to frame buffer */
movew d1,a0@- /* copy sr to frame buffer */
movel sp,_superStack /* save supervisor sp */
andiw #0x2000,d1 /* were we in supervisor mode ? */
beq userMode
movel a7,a5@(60) /* save a7 */
bra saveDone
userMode:
movel usp,a1 /* save user stack pointer */
movel a1,a5@(60) /* save user stack pointer */
saveDone:
movew d3,a0@- /* push frame size in words */
movel d2,a0@- /* push vector number */
movel a4,a0@- /* push exception pc */
#
# save old frame link and set the new value
movel _lastFrame,a1 /* last frame pointer */
movel a1,a0@- /* save pointer to prev frame */
movel a0,_lastFrame
movel d2,sp@- /* push exception num */
movel _exceptionHook,a0 /* get address of handler */
jbsr a0@ /* and call it */
jmp __returnFromException /* now, return */
");
#endif
/*
* remcomHandler is a front end for handle_exception. It moves the
* stack pointer into an area reserved for debugger use in case the
* breakpoint happened in supervisor mode.
*/
asm("_remcomHandler:");
asm(" addl #4,sp"); /* pop off return address */
asm(" movel sp@+,d0"); /* get the exception number */
asm(" movel _stackPtr,sp"); /* move to remcom stack area */
asm(" movel d0,sp@-"); /* push exception onto stack */
asm(" jbsr _handle_exception"); /* this never returns */
asm(" rts"); /* return */
void _returnFromException( Frame *frame )
{
/* if no existing frame, dummy one up */
if (! frame)
{
frame = lastFrame -1;
frame->frameSize = 4;
frame->format = 0;
frame->fsaveHeader = 0;
frame->previous = lastFrame;
}
#ifndef mc68020
/* a 68000 cannot use the internal info pushed onto a bus error
* or address error frame when doing an RTE so don't put this info
* onto the stack or the stack will creep every time this happens.
*/
frame->frameSize=3;
#endif
/* throw away any frames in the list after this frame */
lastFrame = frame;
frame->sr = registers[(int) PS];
frame->pc = registers[(int) PC];
if (registers[(int) PS] & 0x2000)
{
/* return to supervisor mode... */
return_to_super();
}
else
{ /* return to user mode */
return_to_user();
}
}
int hex(ch)
char ch;
{
if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
if ((ch >= '0') && (ch <= '9')) return (ch-'0');
return (0);
}
/* scan for the sequence $<data>#<checksum> */
void getpacket(buffer)
char * buffer;
{
unsigned char checksum;
unsigned char xmitcsum;
int i;
int count;
char ch;
do {
/* wait around for the start character, ignore all other characters */
while ((ch = getDebugChar()) != '$');
checksum = 0;
count = 0;
/* now, read until a # or end of buffer is found */
while (count < BUFMAX) {
ch = getDebugChar();
if (ch == '#') break;
checksum = checksum + ch;
buffer[count] = ch;
count = count + 1;
}
buffer[count] = 0;
if (ch == '#') {
xmitcsum = hex(getDebugChar()) << 4;
xmitcsum += hex(getDebugChar());
if ((remote_debug ) && (checksum != xmitcsum)) {
fprintf(stderr,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
checksum,xmitcsum,buffer);
}
if (checksum != xmitcsum) putDebugChar('-'); /* failed checksum */
else {
putDebugChar('+'); /* successful transfer */
/* if a sequence char is present, reply the sequence ID */
if (buffer[2] == ':') {
putDebugChar( buffer[0] );
putDebugChar( buffer[1] );
/* remove sequence chars from buffer */
count = strlen(buffer);
for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
}
}
}
} while (checksum != xmitcsum);
}
/* send the packet in buffer. The host get's one chance to read it.
This routine does not wait for a positive acknowledge. */
void putpacket(buffer)
char * buffer;
{
unsigned char checksum;
int count;
char ch;
/* $<packet info>#<checksum>. */
do {
putDebugChar('$');
checksum = 0;
count = 0;
while (ch=buffer[count]) {
if (! putDebugChar(ch)) return;
checksum += ch;
count += 1;
}
putDebugChar('#');
putDebugChar(hexchars[checksum >> 4]);
putDebugChar(hexchars[checksum % 16]);
} while (1 == 0); /* (getDebugChar() != '+'); */
}
static char inbuffer[BUFMAX];
static char outbuffer[BUFMAX];
static short error;
void debug_error(format, parm)
char * format;
char * parm;
{
if (remote_debug) fprintf(stderr,format,parm);
}
/* convert the memory pointed to by mem into hex, placing result in buf */
/* return a pointer to the last char put in buf (null) */
char* mem2hex(mem, buf, count)
char* mem;
char* buf;
int count;
{
int i;
unsigned char ch;
for (i=0;i<count;i++) {
ch = *mem++;
*buf++ = hexchars[ch >> 4];
*buf++ = hexchars[ch % 16];
}
*buf = 0;
return(buf);
}
/* convert the hex array pointed to by buf into binary to be placed in mem */
/* return a pointer to the character AFTER the last byte written */
char* hex2mem(buf, mem, count)
char* buf;
char* mem;
int count;
{
int i;
unsigned char ch;
for (i=0;i<count;i++) {
ch = hex(*buf++) << 4;
ch = ch + hex(*buf++);
*mem++ = ch;
}
return(mem);
}
/* a bus error has occurred, perform a longjmp
to return execution and allow handling of the error */
void handle_buserror()
{
longjmp(env,1);
}
/* this function takes the 68000 exception number and attempts to
translate this number into a unix compatible signal value */
int computeSignal( exceptionVector )
int exceptionVector;
{
int sigval;
switch (exceptionVector) {
case 2 : sigval = 10; break; /* bus error */
case 3 : sigval = 10; break; /* address error */
case 4 : sigval = 4; break; /* illegal instruction */
case 5 : sigval = 8; break; /* zero divide */
case 6 : sigval = 16; break; /* chk instruction */
case 7 : sigval = 16; break; /* trapv instruction */
case 8 : sigval = 11; break; /* privilege violation */
case 9 : sigval = 5; break; /* trace trap */
case 10: sigval = 4; break; /* line 1010 emulator */
case 11: sigval = 4; break; /* line 1111 emulator */
case 31: sigval = 2; break; /* interrupt */
case 33: sigval = 5; break; /* breakpoint */
case 40: sigval = 8; break; /* floating point err */
case 48: sigval = 8; break; /* floating point err */
case 49: sigval = 8; break; /* floating point err */
case 50: sigval = 8; break; /* zero divide */
case 51: sigval = 8; break; /* underflow */
case 52: sigval = 8; break; /* operand error */
case 53: sigval = 8; break; /* overflow */
case 54: sigval = 8; break; /* NAN */
default:
sigval = 7; /* "software generated"*/
}
return (sigval);
}
/*
* This function does all command procesing for interfacing to gdb.
*/
void handle_exception(int exceptionVector)
{
int sigval;
int addr, length;
char * ptr;
int newPC;
Frame *frame;
if (remote_debug) printf("vector=%d, sr=0x%x, pc=0x%x\n",
exceptionVector,
registers[ PS ],
registers[ PC ]);
/* reply to host that an exception has occurred */
sigval = computeSignal( exceptionVector );
sprintf(outbuffer,"S%02x",sigval);
putpacket(outbuffer);
while (1==1) {
error = 0;
outbuffer[0] = 0;
getpacket(inbuffer);
switch (inbuffer[0]) {
case '?' : sprintf(outbuffer,"S%02x",sigval);
break;
case 'd' : remote_debug = !(remote_debug); /* toggle debug flag */
break;
case 'g' : /* return the value of the CPU registers */
mem2hex((char*) registers, outbuffer, NUMREGBYTES);
break;
case 'G' : /* set the value of the CPU registers - return OK */
hex2mem(&inbuffer[1], (char*) registers, NUMREGBYTES);
strcpy(outbuffer,"OK");
break;
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
case 'm' :
if (setjmp(env) == 0) {
exceptionHandler(2,handle_buserror);
if (2 == sscanf(&inbuffer[1],"%x,%x",&addr,&length)) {
mem2hex((char*) addr, outbuffer, length);
}
else {
strcpy(outbuffer,"E01");
debug_error("malformed read memory command: %s",inbuffer);
}
}
else {
exceptionHandler(2,_catchException);
strcpy(outbuffer,"E03");
debug_error("bus error");
}
/* restore handler for bus error */
exceptionHandler(2,_catchException);
break;
/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
case 'M' :
if (setjmp(env) == 0) {
exceptionHandler(2,handle_buserror);
if (2 == sscanf(&inbuffer[1],"%x,%x:",&addr,&length)) {
ptr = strchr(inbuffer,':');
ptr += 1; /* point 1 past the colon */
hex2mem(ptr, (char*) addr, length);
strcpy(outbuffer,"OK");
}
else {
strcpy(outbuffer,"E02");
debug_error("malformed write memory command: %s",inbuffer);
}
}
else {
exceptionHandler(2,_catchException);
strcpy(outbuffer,"E03");
debug_error("bus error");
}
break;
/* cAA..AA Continue at address AA..AA(optional) */
/* sAA..AA Step one instruction from AA..AA(optional) */
case 'c' :
case 's' :
/* try to read optional parameter, addr unchanged if no parm */
if (1 == sscanf(&inbuffer[1],"%x",&registers[ PC ]));
newPC = registers[ PC];
/* clear the trace bit */
registers[ PS ] &= 0x7fff;
/* set the trace bit if we're stepping */
if (inbuffer[0] == 's') registers[ PS ] |= 0x8000;
/*
* look for newPC in the linked list of exception frames.
* if it is found, use the old frame it. otherwise,
* fake up a dummy frame in returnFromException().
*/
if (remote_debug) printf("new pc = 0x%x\n",newPC);
frame = lastFrame;
while (frame)
{
if (remote_debug)
printf("frame at 0x%x has pc=0x%x, except#=%d\n",
frame,frame->exceptionPC,
frame->exceptionVector);
if (frame->exceptionPC == newPC) break; /* bingo! a match */
/*
* for a breakpoint instruction, the saved pc may
* be off by two due to re-executing the instruction
* replaced by the trap instruction. Check for this.
*/
if ((frame->exceptionVector == 33) &&
(frame->exceptionPC == (newPC+2))) break;
frame = frame->previous;
}
/*
* If we found a match for the PC AND we are not returning
* as a result of a breakpoint (33),
* trace exception (9), nmi (31), jmp to
* the old exception handler as if this code never ran.
*/
if (frame)
{
if ((frame->exceptionVector != 9) &&
(frame->exceptionVector != 31) &&
(frame->exceptionVector != 33))
{
/*
* invoke the previous handler.
*/
if (oldExceptionHook)
(*oldExceptionHook) (frame->exceptionVector);
newPC = registers[ PC ]; /* pc may have changed */
if (newPC != frame->exceptionPC)
{
if (remote_debug)
printf("frame at 0x%x has pc=0x%x, except#=%d\n",
frame,frame->exceptionPC,
frame->exceptionVector);
/* dispose of this frame, we're skipping it (longjump?)*/
lastFrame = frame->previous;
frame = (Frame *) 0;
}
}
}
_returnFromException( frame );
break;
/* kill the program */
case 'k' : /* do nothing */
break;
} /* switch */
/* reply to the request */
putpacket(outbuffer);
}
}
/* this function is used to set up exception handlers for tracing and
breakpoints */
void set_debug_traps()
{
extern void _debug_level7();
extern void remcomHandler();
int exception;
for (exception = 2; exception <= 23; exception++)
exceptionHandler(exception,_catchException);
/* level 7 interrupt */
exceptionHandler(31,_debug_level7);
/* breakpoint exception (trap #1) */
exceptionHandler(33,_catchException);
/* floating point error (trap #8) */
exceptionHandler(40,_catchException);
/* 48 to 54 are floating point coprocessor errors */
for (exception = 48; exception <= 54; exception++)
exceptionHandler(exception,_catchException);
if (oldExceptionHook != remcomHandler)
{
oldExceptionHook = exceptionHook;
exceptionHook = remcomHandler;
}
initialized = 1;
lastFrame = (Frame *) &frameStack[FRAMESIZE-1];
lastFrame->previous = (Frame *) 0;
}
/* This function will generate a breakpoint exception. It is used at the
beginning of a program to sync up with a debugger and can be used
otherwise as a quick means to stop program execution and "break" into
the debugger. */
void breakpoint()
{
if (initialized) BREAKPOINT();
}
@EOF
chmod 444 remcom.c
exit 0

829
gdb/remote.c Normal file
View file

@ -0,0 +1,829 @@
/* Memory-access and commands for inferior process, for GDB.
Copyright (C) 1988-1991 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* 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.
last signal ? Reply the current reason for stopping.
This is the same reply as is generated
for step or cont : SAA where AA is the
signal number.
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 <stdio.h>
#include <string.h>
#include <fcntl.h>
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
#include "wait.h"
#include "terminal.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <signal.h>
extern int memory_insert_breakpoint ();
extern int memory_remove_breakpoint ();
extern void add_syms_addr_command ();
extern struct value *call_function_by_hand();
extern void start_remote ();
extern struct target_ops remote_ops; /* Forward decl */
static int kiodebug;
static int timeout = 5;
#if 0
int icache;
#endif
/* Descriptor for I/O to remote machine. Initialize it to -1 so that
remote_open knows that we don't have a file open when the program
starts. */
int remote_desc = -1;
#define PBUFSIZ 400
/* Maximum number of bytes to read/write at once. The value here
is chosen to fill up a packet (the headers account for the 32). */
#define MAXBUFBYTES ((PBUFSIZ-32)/2)
static void remote_send ();
static void putpkt ();
static void getpkt ();
#if 0
static void dcache_flush ();
#endif
/* Called when SIGALRM signal sent due to alarm() timeout. */
#ifndef HAVE_TERMIO
void
remote_timer ()
{
if (kiodebug)
printf ("remote_timer called\n");
alarm (timeout);
}
#endif
/* Initialize remote connection */
void
remote_start()
{
}
/* Clean up connection to a remote debugger. */
void
remote_close (quitting)
int quitting;
{
if (remote_desc >= 0)
close (remote_desc);
remote_desc = -1;
}
/* 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;
if (name == 0)
error (
"To open a remote debug connection, you need to specify what serial\n\
device is attached to the remote system (e.g. /dev/ttya).");
remote_close (0);
#if 0
dcache_init ();
#endif
remote_desc = open (name, O_RDWR);
if (remote_desc < 0)
perror_with_name (name);
ioctl (remote_desc, TIOCGETP, &sg);
#ifdef HAVE_TERMIO
sg.c_cc[VMIN] = 0; /* read with timeout. */
sg.c_cc[VTIME] = timeout * 10;
sg.c_lflag &= ~(ICANON | ECHO);
#else
sg.sg_flags = RAW;
#endif
ioctl (remote_desc, TIOCSETP, &sg);
if (from_tty)
printf ("Remote debugging using %s\n", name);
push_target (&remote_ops); /* Switch to using remote target now */
start_remote (); /* Initialize gdb process mechanisms */
#ifndef HAVE_TERMIO
#ifndef NO_SIGINTERRUPT
/* Cause SIGALRM's to make reads fail. */
if (siginterrupt (SIGALRM, 1) != 0)
perror ("remote_open: error in siginterrupt");
#endif
/* Set up read timeout timer. */
if ((void (*)) signal (SIGALRM, remote_timer) == (void (*)) -1)
perror ("remote_open: error in signal");
#endif
putpkt ("?"); /* initiate a query from remote machine */
}
/* remote_detach()
takes a program previously attached to and detaches it.
We better not have left any breakpoints
in the program or it'll die when it hits one.
Close the open connection to the remote debugger.
Use this when you want to detach and do something else
with your gdb. */
static void
remote_detach (args, from_tty)
char *args;
int from_tty;
{
if (args)
error ("Argument given to \"detach\" when remotely debugging.");
pop_target ();
if (from_tty)
printf ("Ending remote debugging.\n");
}
/* 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");
return -1;
}
/* 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. */
void
remote_resume (step, siggnal)
int step, siggnal;
{
char buf[PBUFSIZ];
if (siggnal)
error ("Can't send signals to a remote system.");
#if 0
dcache_flush ();
#endif
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;
{
unsigned 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. */
int
remote_fetch_registers (regno)
int regno;
{
char buf[PBUFSIZ];
int i;
char *p;
char regs[REGISTER_BYTES];
sprintf (buf, "g");
remote_send (buf);
/* Reply describes registers byte by byte, each byte encoded as two
hex characters. Suck them all up, then supply them to the
register cacheing/storage mechanism. */
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;
}
for (i = 0; i < NUM_REGS; i++)
supply_register (i, &regs[REGISTER_BYTE(i)]);
return 0;
}
/* Prepare to store registers. Since we send them all, we have to
read out the ones we don't want to change first. */
void
remote_prepare_to_store ()
{
remote_fetch_registers (-1);
}
/* Store the remote registers from the contents of the block REGISTERS.
FIXME, eventually just store one register if that's all that is needed. */
int
remote_store_registers (regno)
int regno;
{
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 ((registers[i] >> 4) & 0xf);
*p++ = tohex (registers[i] & 0xf);
}
*p = '\0';
remote_send (buf);
return 0;
}
#if 0
/* 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);
}
#endif /* 0 */
/* 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);
}
*p = '\0';
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;
}
}
/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
to or from debugger address MYADDR. Write to inferior if WRITE is
nonzero. Returns length of data written or read; 0 for error. */
int
remote_xfer_inferior_memory(memaddr, myaddr, len, write)
CORE_ADDR memaddr;
char *myaddr;
int len;
int write;
{
int origlen = len;
int xfersize;
while (len > 0)
{
if (len > MAXBUFBYTES)
xfersize = MAXBUFBYTES;
else
xfersize = len;
if (write)
remote_write_bytes(memaddr, myaddr, xfersize);
else
remote_read_bytes (memaddr, myaddr, xfersize);
memaddr += xfersize;
myaddr += xfersize;
len -= xfersize;
}
return origlen; /* no error possible */
}
void
remote_files_info ()
{
printf ("remote files info missing here. FIXME.\n");
}
/*
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
*/
static int
readchar ()
{
char buf;
buf = '\0';
#ifdef HAVE_TERMIO
/* termio does the timeout for us. */
read (remote_desc, &buf, 1);
#else
alarm (timeout);
read (remote_desc, &buf, 1);
alarm (0);
#endif
return buf & 0x7f;
}
/* 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;
{
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;
unsigned char csum = 0;
char buf2[500];
int cnt = strlen (buf);
char ch;
char *p;
/* 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 {
if (kiodebug)
{
*p = '\0';
printf ("Sending packet: %s (%s)\n", buf2, buf);
}
write (remote_desc, buf2, p - buf2);
/* read until either a timeout occurs (\0) or '+' is read */
do {
ch = readchar ();
} while ((ch != '+') && (ch != '\0'));
} while (ch != '+');
}
/* 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;
int c;
unsigned char c1, c2;
/* allow immediate quit while reading from device, it could be hung */
immediate_quit++;
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 & 0xff) == (c1 << 4) + c2)
break;
printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
(c1 << 4) + c2, csum & 0xff, buf);
write (remote_desc, "-", 1);
}
immediate_quit--;
write (remote_desc, "+", 1);
if (kiodebug)
fprintf (stderr,"Packet received :%s\n", buf);
}
/* The data cache leads to incorrect results because it doesn't know about
volatile variables, thus making it impossible to debug functions which
use hardware registers. Therefore it is #if 0'd out. Effect on
performance is some, for backtraces of functions with a few
arguments each. For functions with many arguments, the stack
frames don't fit in the cache blocks, which makes the cache less
helpful. Disabling the cache is a big performance win for fetching
large structures, because the cache code fetched data in 16-byte
chunks. */
#if 0
/* 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);
}
#endif /* 0 */
/* Define the target subroutine names */
struct target_ops remote_ops = {
"remote", "Remote serial target in gdb-specific protocol",
remote_open, remote_close,
0, remote_detach, remote_resume, remote_wait, /* attach */
remote_fetch_registers, remote_store_registers,
remote_prepare_to_store, 0, 0, /* conv_from, conv_to */
remote_xfer_inferior_memory, remote_files_info,
0, 0, /* insert_breakpoint, remove_breakpoint, */
0, 0, 0, 0, 0, /* Terminal crud */
0, /* kill */
0, add_syms_addr_command, /* load */
call_function_by_hand,
0, /* lookup_symbol */
0, 0, /* create_inferior FIXME, mourn_inferior FIXME */
process_stratum, 0, /* next */
1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */
OPS_MAGIC, /* Always the last thing */
};
void
_initialize_remote ()
{
add_target (&remote_ops);
}

245
gdb/solib.c Normal file
View file

@ -0,0 +1,245 @@
/* Copyright (C) 1990 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
** symbol definitions
*/
#include <sys/types.h>
#include <string.h>
#include <link.h>
#include "defs.h"
#include "param.h"
#include "symtab.h"
#include "gdbcore.h"
#include "command.h"
/*
** local data declarations
*/
#define MAX_PATH_SIZE 256
struct so_list {
struct link_map inferior_lm; /* inferior link map */
struct link_map *inferior_lm_add;
long ld_text;
char inferior_so_name[MAX_PATH_SIZE]; /* Shared Object Library Name */
struct so_list *next; /* Next Structure */
int symbols_loaded;
};
static struct so_list *so_list_head = 0;
/*=======================================================================*/
/* find_solib
**
**Description:
**
** This module contains the routine which finds the names of any loaded
** "images" in the current process. The argument in must be NULL on the
** first call, and then the returned value must be passed in on
** subsequent calls. This provides the capability to "step" down the
** list of loaded objects. On the last object, a NULL value is returned.
** The arg and return value are "struct link_map" pointers, as defined
** in <link.h>.
**
** NOTE: This only works under SunOS4.0.
*/
struct so_list *find_solib(so_list_ptr)
struct so_list *so_list_ptr; /* so_list_head position ptr */
{
struct so_list *so_list_next = 0;
CORE_ADDR inferior_dynamic_ptr = 0;
struct link_map *inferior_lm = 0;
struct link_dynamic inferior_dynamic_cpy;
struct link_dynamic_2 inferior_ld_2_cpy;
struct so_list *new;
int i;
if (!so_list_ptr) {
if (!(so_list_next = so_list_head)) {
for (i = 0; i < misc_function_count; i++) {
if (!strcmp (misc_function_vector[i].name, "_DYNAMIC")) {
inferior_dynamic_ptr = misc_function_vector[i].address;
break;
}
}
if (inferior_dynamic_ptr) {
read_memory(inferior_dynamic_ptr, &inferior_dynamic_cpy, sizeof(struct link_dynamic));
if (inferior_dynamic_cpy.ld_version == 3) {
read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2,
&inferior_ld_2_cpy,
sizeof(struct link_dynamic_2));
inferior_lm = inferior_ld_2_cpy.ld_loaded;
}
}
}
} else {
/*
** Advance to next local abbreviated load_map structure
*/
if (!(inferior_lm = so_list_ptr->inferior_lm.lm_next)) {
/*
** See if any were added
*/
read_memory((CORE_ADDR)so_list_ptr->inferior_lm_add,
&so_list_ptr->inferior_lm,
sizeof(struct link_map));
inferior_lm = so_list_ptr->inferior_lm.lm_next;
}
so_list_next = so_list_ptr->next;
}
if ((!so_list_next) && inferior_lm) {
/*
** Get Next LM Structure from inferior image and build
** an local abbreviated load_map structure
*/
new = (struct so_list *) xmalloc(sizeof(struct so_list));
new->inferior_lm_add = inferior_lm;
read_memory((CORE_ADDR)inferior_lm,
&new->inferior_lm,
sizeof(struct link_map));
read_memory((CORE_ADDR)new->inferior_lm.lm_name,
new->inferior_so_name,
MAX_PATH_SIZE - 1);
new->inferior_so_name[MAX_PATH_SIZE - 1] = 0;
/* Zero everything after the first terminating null */
strncpy(new->inferior_so_name, new->inferior_so_name, MAX_PATH_SIZE);
read_memory((CORE_ADDR)new->inferior_lm.lm_ld,
&inferior_dynamic_cpy,
sizeof(struct link_dynamic));
read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2,
&inferior_ld_2_cpy,
sizeof(struct link_dynamic_2));
new->ld_text = inferior_ld_2_cpy.ld_text;
new->next = 0;
new->symbols_loaded = 0;
if (so_list_ptr)
so_list_ptr->next = new;
else
so_list_head = new;
so_list_next = new;
}
return(so_list_next);
}
/*=======================================================================*/
static void solib_add(arg_string, from_tty)
char *arg_string;
int from_tty;
{
register struct so_list *so = 0; /* link map state variable */
char *val;
int sz;
if (arg_string == 0)
re_comp (".");
else if (val = (char *) re_comp (arg_string)) {
error ("Invalid regexp: %s", val);
}
printf_filtered ("All shared libraries");
if (arg_string)
printf_filtered (" matching regular expresion \"%s\"", arg_string);
printf_filtered (":\n");
dont_repeat();
while (so = find_solib(so)) {
if (re_exec(so->inferior_so_name)) {
if (so->symbols_loaded) {
printf("Symbols already loaded for %s\n", so->inferior_so_name);
} else {
/* File Name String Freed by processing */
sz = strlen(so->inferior_so_name) + 1;
val = (char *) xmalloc(sz);
bcopy(so->inferior_so_name, val, sz);
symbol_file_add (val, from_tty,
(unsigned int)so->inferior_lm.lm_addr, 0);
so->symbols_loaded = 1;
}
}
}
}
/*=======================================================================*/
static void solib_info()
{
register struct so_list *so = 0; /* link map state variable */
while (so = find_solib(so)) {
if (so == so_list_head) {
printf(" Address Range Symbols Shared Object Library\n");
}
printf(" 0x%08x - 0x%08x %s %s\n",
so->inferior_lm.lm_addr,
so->inferior_lm.lm_addr + so->ld_text - 1,
(so->symbols_loaded ? "Yes" : "No "),
so->inferior_so_name);
}
if (!so_list_head) {
printf("No shared libraries loaded at this time.\n");
}
}
/*
** Called by Insert Breakpoint to see if Address is Shared Library Address
*/
int
solib_address(address)
CORE_ADDR address;
{
register struct so_list *so = 0; /* link map state variable */
while (so = find_solib(so)) {
if ((address >= (CORE_ADDR) so->inferior_lm.lm_addr) &&
(address < (CORE_ADDR) so->inferior_lm.lm_addr + so->ld_text))
return 1;
}
return 0;
}
/*
** Called by free_all_symtabs
*/
void
clear_solib()
{
struct so_list *next;
while (so_list_head) {
next = so_list_head->next;
free(so_list_head);
so_list_head = next;
}
}
void
_initialize_solib()
{
add_com("sharedlibrary", class_files, solib_add,
"Load shared object library symbols for files matching REGEXP.");
add_info("sharedlibrary", solib_info,
"Status of loaded shared object libraries");
}

1186
gdb/source.c Normal file

File diff suppressed because it is too large Load diff

586
gdb/sparc-tdep.c Normal file
View file

@ -0,0 +1,586 @@
/* Machine-dependent code which would otherwise be in inflow.c and core.c,
for GDB, the GNU debugger.
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
This code is for the sparc cpu.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#include "obstack.h"
#include "signame.h"
#include "target.h"
#include "ieee-float.h"
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <machine/reg.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/core.h>
#include "gdbcore.h"
/* From infrun.c */
extern int stop_after_trap;
typedef enum
{
Error, not_branch, bicc, bicca, ba, baa, ticc, ta,
} branch_type;
/* Simulate single-step ptrace call for sun4. Code written by Gary
Beihl (beihl@mcc.com). */
/* npc4 and next_pc describe the situation at the time that the
step-breakpoint was set, not necessary the current value of NPC_REGNUM. */
static CORE_ADDR next_pc, npc4, target;
static int brknpc4, brktrg;
typedef char binsn_quantum[BREAKPOINT_MAX];
static binsn_quantum break_mem[3];
/* Non-zero if we just simulated a single-step ptrace call. This is
needed because we cannot remove the breakpoints in the inferior
process until after the `wait' in `wait_for_inferior'. Used for
sun4. */
int one_stepped;
void
single_step (signal)
int signal;
{
branch_type br, isannulled();
CORE_ADDR pc;
long pc_instruction;
if (!one_stepped)
{
/* Always set breakpoint for NPC. */
next_pc = read_register (NPC_REGNUM);
npc4 = next_pc + 4; /* branch not taken */
target_insert_breakpoint (next_pc, break_mem[0]);
/* printf ("set break at %x\n",next_pc); */
pc = read_register (PC_REGNUM);
pc_instruction = read_memory_integer (pc, sizeof(pc_instruction));
br = isannulled (pc_instruction, pc, &target);
brknpc4 = brktrg = 0;
if (br == bicca)
{
/* Conditional annulled branch will either end up at
npc (if taken) or at npc+4 (if not taken).
Trap npc+4. */
brknpc4 = 1;
target_insert_breakpoint (npc4, break_mem[1]);
}
else if (br == baa && target != next_pc)
{
/* Unconditional annulled branch will always end up at
the target. */
brktrg = 1;
target_insert_breakpoint (target, break_mem[2]);
}
/* Let it go */
ptrace (7, inferior_pid, 1, signal);
one_stepped = 1;
return;
}
else
{
/* Remove breakpoints */
target_remove_breakpoint (next_pc, break_mem[0]);
if (brknpc4)
target_remove_breakpoint (npc4, break_mem[1]);
if (brktrg)
target_remove_breakpoint (target, break_mem[2]);
one_stepped = 0;
}
}
/*
* Find the pc saved in frame FRAME.
*/
CORE_ADDR
frame_saved_pc (frame)
FRAME frame;
{
CORE_ADDR prev_pc;
/* If it's at the bottom, the return value's stored in i7/rp */
if (get_current_frame () == frame)
prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]);
else
/* Wouldn't this always work? This would allow this routine to
be completely a macro. */
prev_pc = GET_RWINDOW_REG (frame->bottom, rw_in[7]);
return PC_ADJUST (prev_pc);
}
/*
* Since an individual frame in the frame cache is defined by two
* arguments (a frame pointer and a stack pointer), we need two
* arguments to get info for an arbitrary stack frame. This routine
* takes two arguments and makes the cached frames look as if these
* two arguments defined a frame on the cache. This allows the rest
* of info frame to extract the important arguments without
* difficulty.
*/
FRAME
setup_arbitrary_frame (frame, stack)
FRAME_ADDR frame, stack;
{
FRAME fid = create_new_frame (frame, 0);
if (!fid)
fatal ("internal: create_new_frame returned invalid frame id");
fid->bottom = stack;
return fid;
}
/* This code was written by Gary Beihl (beihl@mcc.com).
It was modified by Michael Tiemann (tiemann@corto.inria.fr). */
/*
* This routine appears to be passed a size by which to increase the
* stack. It then executes a save instruction in the inferior to
* increase the stack by this amount. Only the register window system
* should be affected by this; the program counter & etc. will not be.
*
* This instructions used for this purpose are:
*
* sethi %hi(0x0),g1 *
* add g1,0x1ee0,g1 *
* save sp,g1,sp
* sethi %hi(0x0),g1 *
* add g1,0x1ee0,g1 *
* t g0,0x1,o0
* sethi %hi(0x0),g0 (nop)
*
* I presume that these set g1 to be the negative of the size, do a
* save (putting the stack pointer at sp - size) and restore the
* original contents of g1. A * indicates that the actual value of
* the instruction is modified below.
*/
static int save_insn_opcodes[] = {
0x03000000, 0x82007ee0, 0x9de38001, 0x03000000,
0x82007ee0, 0x91d02001, 0x01000000 };
/* Neither do_save_insn or do_restore_insn save stack configuration
(current_frame, etc),
since the stack is in an indeterminate state through the call to
each of them. That responsibility of the routine which calls them. */
static void
do_save_insn (size)
int size;
{
int g1 = read_register (G1_REGNUM);
CORE_ADDR sp = read_register (SP_REGNUM);
CORE_ADDR pc = read_register (PC_REGNUM);
CORE_ADDR npc = read_register (NPC_REGNUM);
CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes);
struct inferior_status inf_status;
save_inferior_status (&inf_status, 0); /* Don't restore stack info */
/*
* See above.
*/
save_insn_opcodes[0] = 0x03000000 | ((-size >> 10) & 0x3fffff);
save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff);
save_insn_opcodes[3] = 0x03000000 | ((g1 >> 10) & 0x3fffff);
save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff);
write_memory (fake_pc, (char *)save_insn_opcodes, sizeof (save_insn_opcodes));
clear_proceed_status ();
stop_after_trap = 1;
proceed (fake_pc, 0, 0);
write_register (PC_REGNUM, pc);
write_register (NPC_REGNUM, npc);
restore_inferior_status (&inf_status);
}
/*
* This routine takes a program counter value. It restores the
* register window system to the frame above the current one.
* THIS ROUTINE CLOBBERS PC AND NPC IN THE TARGET!
*/
/* The following insns translate to:
restore %g0,%g0,%g0
t %g0,1
sethi %hi(0),%g0 */
static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 };
static void
do_restore_insn ()
{
CORE_ADDR sp = read_register (SP_REGNUM);
CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes);
struct inferior_status inf_status;
save_inferior_status (&inf_status, 0); /* Don't restore stack info */
write_memory (fake_pc, (char *)restore_insn_opcodes,
sizeof (restore_insn_opcodes));
clear_proceed_status ();
stop_after_trap = 1;
proceed (fake_pc, 0, 0);
restore_inferior_status (&inf_status);
}
/* This routine should be more specific in it's actions; making sure
that it uses the same register in the initial prologue section.
Also, FIXME-SOON, it should recognize leaf functions as ones without
a SAVE in the prologue, and pass that info back to the caller so the
PC and arguments can be properly located. */
CORE_ADDR
skip_prologue (pc)
CORE_ADDR pc;
{
union
{
unsigned long int code;
struct
{
unsigned int op:2;
unsigned int rd:5;
unsigned int op2:3;
unsigned int imm22:22;
} sethi;
struct
{
unsigned int op:2;
unsigned int rd:5;
unsigned int op3:6;
unsigned int rs1:5;
unsigned int i:1;
unsigned int simm13:13;
} add;
int i;
} x;
int dest = -1;
x.i = read_memory_integer (pc, 4);
/* Recognize the `sethi' insn and record its destination. */
if (x.sethi.op == 0 && x.sethi.op2 == 4)
{
dest = x.sethi.rd;
pc += 4;
x.i = read_memory_integer (pc, 4);
}
/* Recognize an add immediate value to register to either %g1 or
the destination register recorded above. Actually, this might
well recognize several different arithmetic operations. */
if (x.add.op == 2 && x.add.i && (x.add.rd == 1 || x.add.rd == dest))
{
pc += 4;
x.i = read_memory_integer (pc, 4);
}
/* This recognizes any SAVE insn. But why do the XOR and then
the compare? That's identical to comparing against 60 (as long
as there isn't any sign extension). */
if (x.add.op == 2 && (x.add.op3 ^ 32) == 28)
{
pc += 4;
x.i = read_memory_integer (pc, 4);
}
/* Now we need to recognize stores into the frame from the input
registers. This recognizes all non alternate stores of input
register, into a location offset from the frame pointer. */
while (x.add.op == 3
&& (x.add.op3 & 0x3c) == 4 /* Store, non-alternate. */
&& (x.add.rd & 0x18) == 0x18 /* Input register. */
&& x.add.i /* Immediate mode. */
&& x.add.rs1 == 30 /* Off of frame pointer. */
/* Into reserved stack space. */
&& x.add.simm13 >= 0x44
&& x.add.simm13 < 0x5b)
{
pc += 4;
x.i = read_memory_integer (pc, 4);
}
return pc;
}
/* Check instruction at ADDR to see if it is an annulled branch.
All other instructions will go to NPC or will trap.
Set *TARGET if we find a canidate branch; set to zero if not. */
branch_type
isannulled (instruction, addr, target)
long instruction;
CORE_ADDR addr, *target;
{
branch_type val = not_branch;
long int offset; /* Must be signed for sign-extend. */
union
{
unsigned long int code;
struct
{
unsigned int op:2;
unsigned int a:1;
unsigned int cond:4;
unsigned int op2:3;
unsigned int disp22:22;
} b;
} insn;
*target = 0;
insn.code = instruction;
if (insn.b.op == 0
&& (insn.b.op2 == 2 || insn.b.op2 == 6 || insn.b.op2 == 7))
{
if (insn.b.cond == 8)
val = insn.b.a ? baa : ba;
else
val = insn.b.a ? bicca : bicc;
offset = 4 * ((int) (insn.b.disp22 << 10) >> 10);
*target = addr + offset;
}
return val;
}
/* sparc_frame_find_saved_regs ()
Stores, 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.
The "pc" is not stored in a frame on the SPARC. (What is stored
is a return address minus 8.) sparc_pop_frame knows how to
deal with that. Other routines might or might not.
See tm-sparc.h (PUSH_FRAME and friends) for CRITICAL information
about how this works. */
void
sparc_frame_find_saved_regs (fi, saved_regs_addr)
struct frame_info *fi;
struct frame_saved_regs *saved_regs_addr;
{
register int regnum;
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 (saved_regs_addr, sizeof (*saved_regs_addr));
/* Old test.
if (fi->pc >= frame - CALL_DUMMY_LENGTH - 0x140
&& fi->pc <= frame) */
if (fi->pc >= (fi->bottom ? fi->bottom :
read_register (SP_REGNUM))
&& fi->pc <= FRAME_FP(fi))
{
/* Dummy frame. All but the window regs are in there somewhere. */
for (regnum = G1_REGNUM; regnum < G1_REGNUM+7; regnum++)
saved_regs_addr->regs[regnum] =
frame + (regnum - G0_REGNUM) * 4 - 0xa0;
for (regnum = I0_REGNUM; regnum < I0_REGNUM+8; regnum++)
saved_regs_addr->regs[regnum] =
frame + (regnum - I0_REGNUM) * 4 - 0xc0;
for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++)
saved_regs_addr->regs[regnum] =
frame + (regnum - FP0_REGNUM) * 4 - 0x80;
for (regnum = Y_REGNUM; regnum < NUM_REGS; regnum++)
saved_regs_addr->regs[regnum] =
frame + (regnum - Y_REGNUM) * 4 - 0xe0;
frame = fi->bottom ?
fi->bottom : read_register (SP_REGNUM);
}
else
{
/* Normal frame. Just Local and In registers */
frame = fi->bottom ?
fi->bottom : read_register (SP_REGNUM);
for (regnum = L0_REGNUM; regnum < L0_REGNUM+16; regnum++)
saved_regs_addr->regs[regnum] = frame + (regnum-L0_REGNUM) * 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 = O0_REGNUM; regnum < O0_REGNUM+8; regnum++)
saved_regs_addr->regs[regnum] = next_next_frame + regnum * 4;
}
/* Otherwise, whatever we would get from ptrace(GETREGS) is accurate */
saved_regs_addr->regs[SP_REGNUM] = FRAME_FP (fi);
}
/* Push an empty stack frame, and record in it the current PC, regs, etc.
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 randoms, of the new frame, are being saved. The locals and outs
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 (now on the stack, since a context switch happended imm after).
The return pointer register %i7 does not have
the pc saved into it (return from this frame will be accomplished
by a POP_FRAME). In fact, we must leave it unclobbered, since we
must preserve it in the calling routine except across call instructions. */
/* Definitely see tm-sparc.h for more doc of the frame format here. */
void
sparc_push_dummy_frame ()
{
CORE_ADDR fp;
char register_temp[REGISTER_BYTES];
do_save_insn (0x140); /* FIXME where does this value come from? */
fp = read_register (FP_REGNUM);
read_register_bytes (REGISTER_BYTE (FP0_REGNUM), register_temp, 32 * 4);
write_memory (fp - 0x80, register_temp, 32 * 4);
read_register_bytes (REGISTER_BYTE (G0_REGNUM), register_temp, 8 * 4);
write_memory (fp - 0xa0, register_temp, 8 * 4);
read_register_bytes (REGISTER_BYTE (I0_REGNUM), register_temp, 8 * 4);
write_memory (fp - 0xc0, register_temp, 8 * 4);
/* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */
read_register_bytes (REGISTER_BYTE (Y_REGNUM), register_temp, 8 * 4);
write_memory (fp - 0xe0, register_temp, 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 called frame*. What this means is that the i
regs of fsr must be restored into the o regs of the (calling) frame that
we pop into. We don't care about the output regs of the calling frame,
since unless it's a dummy frame, it won't have any output regs in it.
We never have to bother with %l (local) regs, since the called routine's
locals get tossed, and the calling routine's locals are already saved
on its stack. */
/* Definitely see tm-sparc.h for more doc of the frame format here. */
void
sparc_pop_frame ()
{
register FRAME frame = get_current_frame ();
register CORE_ADDR pc;
struct frame_saved_regs fsr;
struct frame_info *fi;
char raw_buffer[REGISTER_BYTES];
fi = get_frame_info (frame);
get_frame_saved_regs (fi, &fsr);
do_restore_insn ();
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[G1_REGNUM])
{
read_memory (fsr.regs[G1_REGNUM], raw_buffer, 7 * 4);
write_register_bytes (REGISTER_BYTE (G1_REGNUM), raw_buffer, 7 * 4);
}
if (fsr.regs[I0_REGNUM])
{
read_memory (fsr.regs[I0_REGNUM], raw_buffer, 8 * 4);
write_register_bytes (REGISTER_BYTE (O0_REGNUM), 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[PC_REGNUM])
{
/* Explicitly specified PC (and maybe NPC) -- just restore them. */
write_register (PC_REGNUM, read_memory_integer (fsr.regs[PC_REGNUM], 4));
if (fsr.regs[NPC_REGNUM])
write_register (NPC_REGNUM,
read_memory_integer (fsr.regs[NPC_REGNUM], 4));
}
else if (fsr.regs[I7_REGNUM])
{
/* Return address in %i7 -- adjust it, then restore PC and NPC from it */
pc = PC_ADJUST (read_memory_integer (fsr.regs[I7_REGNUM], 4));
write_register (PC_REGNUM, pc);
write_register (NPC_REGNUM, pc + 4);
}
flush_cached_frames ();
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
read_pc ()));
}
/* Structure of SPARC extended floating point numbers.
This information is not currently used by GDB, since no current SPARC
implementations support extended float. */
const struct ext_format ext_format_sparc[] = {
/* tot sbyte smask expbyte manbyte */
{ 16, 0, 0x80, 0,1, 4,8 }, /* sparc */
};

1139
gdb/stack.c Normal file

File diff suppressed because it is too large Load diff

746
gdb/symfile.c Normal file
View file

@ -0,0 +1,746 @@
/* Generic symbol file reading for the GNU debugger, GDB.
Copyright 1990, 1991 Free Software Foundation, Inc.
Contributed by Cygnus Support, using pieces from other GDB modules.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "defs.h"
#include "symtab.h"
#include "param.h"
#include "gdbcore.h"
#include "frame.h"
#include "target.h"
#include "value.h"
#include "symfile.h"
#include "gdbcmd.h"
#include "breakpoint.h"
#include <obstack.h>
#include <assert.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
extern int info_verbose;
extern int close ();
extern void qsort ();
extern char *getenv ();
/* Functions this file defines */
static bfd *symfile_open();
static struct sym_fns *symfile_init();
/* List of all available sym_fns. */
struct sym_fns *symtab_fns = NULL;
/* Saves the sym_fns of the current symbol table, so we can call
the right sym_discard function when we free it. */
static struct sym_fns *symfile_fns;
/* Allocate an obstack to hold objects that should be freed
when we load a new symbol table.
This includes the symbols made by dbxread
and the types that are not permanent. */
struct obstack obstack1;
struct obstack *symbol_obstack = &obstack1;
/* This obstack will be used for partial_symbol objects. It can
probably actually be the same as the symbol_obstack above, but I'd
like to keep them seperate for now. If I want to later, I'll
replace one with the other. */
struct obstack obstack2;
struct obstack *psymbol_obstack = &obstack2;
/* File name symbols were loaded from. */
char *symfile = 0;
/* The modification date of the file when they were loaded. */
int symfile_mtime = 0;
/* Structures with which to manage partial symbol allocation. */
struct psymbol_allocation_list global_psymbols = {0}, static_psymbols = {0};
/* Structure to manage complaints about symbol file contents. */
struct complaint complaint_root[1] = {
{(char *)0, 0, complaint_root},
};
/* In the following sort, we always make sure that
register debug symbol declarations always come before regular
debug symbol declarations (as might happen when parameters are
then put into registers by the compiler). */
static int
compare_symbols (s1, s2)
struct symbol **s1, **s2;
{
register int namediff;
/* Compare the initial characters. */
namediff = SYMBOL_NAME (*s1)[0] - SYMBOL_NAME (*s2)[0];
if (namediff != 0) return namediff;
/* If they match, compare the rest of the names. */
namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
if (namediff != 0) return namediff;
/* For symbols of the same name, registers should come first. */
return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
- (SYMBOL_CLASS (*s1) == LOC_REGISTER));
}
/* Call sort_block_syms to sort alphabetically the symbols of one block. */
void
sort_block_syms (b)
register struct block *b;
{
qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
sizeof (struct symbol *), compare_symbols);
}
/* Call sort_symtab_syms to sort alphabetically
the symbols of each block of one symtab. */
void
sort_symtab_syms (s)
register struct symtab *s;
{
register struct blockvector *bv = BLOCKVECTOR (s);
int nbl = BLOCKVECTOR_NBLOCKS (bv);
int i;
register struct block *b;
for (i = 0; i < nbl; i++)
{
b = BLOCKVECTOR_BLOCK (bv, i);
if (BLOCK_SHOULD_SORT (b))
sort_block_syms (b);
}
}
void
sort_all_symtab_syms ()
{
register struct symtab *s;
for (s = symtab_list; s; s = s->next)
{
sort_symtab_syms (s);
}
}
/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
(and add a null character at the end in the copy).
Returns the address of the copy. */
char *
obsavestring (ptr, size)
char *ptr;
int size;
{
register char *p = (char *) obstack_alloc (symbol_obstack, size + 1);
/* Open-coded bcopy--saves function call time.
These strings are usually short. */
{
register char *p1 = ptr;
register char *p2 = p;
char *end = ptr + size;
while (p1 != end)
*p2++ = *p1++;
}
p[size] = 0;
return p;
}
/* Concatenate strings S1, S2 and S3; return the new string.
Space is found in the symbol_obstack. */
char *
obconcat (s1, s2, s3)
char *s1, *s2, *s3;
{
register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
register char *val = (char *) obstack_alloc (symbol_obstack, len);
strcpy (val, s1);
strcat (val, s2);
strcat (val, s3);
return val;
}
/* Accumulate the misc functions in bunches of 127.
At the end, copy them all into one newly allocated structure. */
#define MISC_BUNCH_SIZE 127
struct misc_bunch
{
struct misc_bunch *next;
struct misc_function contents[MISC_BUNCH_SIZE];
};
/* Bunch currently being filled up.
The next field points to chain of filled bunches. */
static struct misc_bunch *misc_bunch;
/* Number of slots filled in current bunch. */
static int misc_bunch_index;
/* Total number of misc functions recorded so far. */
static int misc_count;
void
init_misc_bunches ()
{
misc_count = 0;
misc_bunch = 0;
misc_bunch_index = MISC_BUNCH_SIZE;
}
void
prim_record_misc_function (name, address, misc_type)
char *name;
CORE_ADDR address;
enum misc_function_type misc_type;
{
register struct misc_bunch *new;
if (misc_bunch_index == MISC_BUNCH_SIZE)
{
new = (struct misc_bunch *) xmalloc (sizeof (struct misc_bunch));
misc_bunch_index = 0;
new->next = misc_bunch;
misc_bunch = new;
}
misc_bunch->contents[misc_bunch_index].name = name;
misc_bunch->contents[misc_bunch_index].address = address;
misc_bunch->contents[misc_bunch_index].type = misc_type;
misc_bunch->contents[misc_bunch_index].misc_info = 0;
misc_bunch_index++;
misc_count++;
}
static int
compare_misc_functions (fn1, fn2)
struct misc_function *fn1, *fn2;
{
/* Return a signed result based on unsigned comparisons
so that we sort into unsigned numeric order. */
if (fn1->address < fn2->address)
return -1;
if (fn1->address > fn2->address)
return 1;
return 0;
}
/* ARGSUSED */
void
discard_misc_bunches (foo)
int foo;
{
register struct misc_bunch *next;
while (misc_bunch)
{
next = misc_bunch->next;
free (misc_bunch);
misc_bunch = next;
}
}
/* INCLINK nonzero means bunches are from an incrementally-linked file.
Add them to the existing bunches.
Otherwise INCLINK is zero, and we start from scratch. */
void
condense_misc_bunches (inclink)
int inclink;
{
register int i, j;
register struct misc_bunch *bunch;
if (inclink)
{
misc_function_vector
= (struct misc_function *)
xrealloc (misc_function_vector, (misc_count + misc_function_count)
* sizeof (struct misc_function));
j = misc_function_count;
}
else
{
misc_function_vector
= (struct misc_function *)
xmalloc (misc_count * sizeof (struct misc_function));
j = 0;
}
bunch = misc_bunch;
while (bunch)
{
for (i = 0; i < misc_bunch_index; i++, j++)
{
misc_function_vector[j] = bunch->contents[i];
#ifdef NAMES_HAVE_UNDERSCORE
if (misc_function_vector[j].name[0] == '_')
misc_function_vector[j].name++;
#endif
}
bunch = bunch->next;
misc_bunch_index = MISC_BUNCH_SIZE;
}
if (misc_function_count + misc_count != j) /* DEBUG */
printf_filtered ("Function counts are off! %d + %d != %d\n",
misc_function_count, misc_count, j);
misc_function_count = j;
/* Sort the misc functions by address. */
qsort (misc_function_vector, misc_function_count,
sizeof (struct misc_function),
compare_misc_functions);
}
/* Get the symbol table that corresponds to a partial_symtab.
This is fast after the first time you do it. In fact, there
is an even faster macro PSYMTAB_TO_SYMTAB that does the fast
case inline. */
struct symtab *
psymtab_to_symtab (pst)
register struct partial_symtab *pst;
{
register struct symtab *result;
/* If it's been looked up before, return it. */
if (pst->symtab)
return pst->symtab;
/* If it has not yet been read in, read it. */
if (!pst->readin)
{
(*pst->read_symtab) (pst);
}
/* Search through list for correct name. */
for (result = symtab_list; result; result = result->next)
if (!strcmp (result->filename, pst->filename))
{
pst->symtab = result; /* Remember where it was. */
return result;
}
return 0;
}
/* Process a symbol file, as either the main file or as a dynamically
loaded file.
NAME is the file name (which will be tilde-expanded and made absolute
herein). FROM_TTY says how verbose to be. MAINLINE specifies whether
this is the main symbol file, or whether it's an extra symbol file
such as dynamically loaded code. If !mainline, ADDR is the address
where the text segment was loaded. */
void
symbol_file_add (name, from_tty, addr, mainline)
char *name;
int from_tty;
CORE_ADDR addr;
int mainline;
{
bfd *sym_bfd;
asection *text_sect;
struct sym_fns *sf;
char *realname;
sym_bfd = symfile_open (name);
entry_point = bfd_get_start_address (sym_bfd);
if (mainline)
symfile_mtime = bfd_get_mtime (sym_bfd);
/* There is a distinction between having no symbol table
(we refuse to read the file, leaving the old set of symbols around)
and having no debugging symbols in your symbol table (we read
the file and end up with a mostly empty symbol table). */
if (!(bfd_get_file_flags (sym_bfd) & HAS_SYMS))
{
error ("%s has no symbol-table", name);
}
if ((symtab_list || partial_symtab_list)
&& mainline
&& from_tty
&& !query ("Load new symbol table from \"%s\"? ", name))
error ("Not confirmed.");
if (from_tty)
{
printf ("Reading symbol data from %s...", name);
fflush (stdout);
}
sf = symfile_init (sym_bfd);
realname = bfd_get_filename (sym_bfd);
realname = savestring (realname, strlen (realname));
/* FIXME, this probably creates a storage leak... */
if (mainline)
{
/* Since no error yet, throw away the old symbol table. */
if (symfile)
free (symfile);
symfile = 0;
free_all_symtabs ();
free_all_psymtabs ();
(*sf->sym_new_init) ();
/* For mainline, caller didn't know the specified address of the
text section. We fix that here. */
text_sect = bfd_get_section_by_name (sym_bfd, ".text");
addr = bfd_section_vma (sym_bfd, text_sect);
}
clear_complaints(); /* Allow complaints to appear for this new file. */
(*sf->sym_read) (sf, addr, mainline);
/* Don't allow char * to have a typename (else would get caddr_t.) */
/* Ditto void *. FIXME should do this for all the builtin types. */
TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
TYPE_NAME (lookup_pointer_type (builtin_type_void)) = 0;
if (mainline)
{
/* OK, make it the "real" symbol file. */
symfile = realname;
symfile_fns = sf;
}
if (from_tty)
{
printf ("done.\n");
fflush (stdout);
}
}
/* This is the symbol-file command. Read the file, analyze its symbols,
and add a struct symtab to symtab_list. */
void
symbol_file_command (name, from_tty)
char *name;
int from_tty;
{
dont_repeat ();
if (name == 0)
{
if ((symtab_list || partial_symtab_list)
&& from_tty
&& !query ("Discard symbol table from `%s'? ", symfile))
error ("Not confirmed.");
if (symfile)
free (symfile);
symfile = 0;
free_all_symtabs ();
free_all_psymtabs ();
/* FIXME, this does not account for the main file and subsequent
files (shared libs, dynloads, etc) having different formats.
It only calls the cleanup routine for the main file's format. */
(*symfile_fns->sym_new_init) ();
free (symfile_fns);
symfile_fns = 0;
return;
}
symbol_file_add (name, from_tty, (CORE_ADDR)0, 1);
}
/* Open NAME and hand it off to BFD for preliminary analysis. Result
is a BFD *, which includes a new copy of NAME dynamically allocated
(which will be freed by the cleanup chain). In case of trouble,
error() is called. */
static bfd *
symfile_open (name)
char *name;
{
bfd *sym_bfd;
int desc;
char *absolute_name;
name = tilde_expand (name);
make_cleanup (free, name);
desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name);
if (desc < 0)
perror_with_name (name);
else
{
make_cleanup (free, absolute_name);
name = absolute_name;
}
sym_bfd = bfd_fdopenr (name, NULL, desc);
if (!sym_bfd)
{
close (desc);
error ("Could not open `%s' to read symbols: %s",
name, bfd_errmsg (bfd_error));
}
make_cleanup (bfd_close, sym_bfd);
if (!bfd_check_format (sym_bfd, bfd_object))
error ("\"%s\": can't read symbols: %s.",
name, bfd_errmsg (bfd_error));
return sym_bfd;
}
/* Link a new symtab_fns into the global symtab_fns list.
Called by various _initialize routines. */
void
add_symtab_fns (sf)
struct sym_fns *sf;
{
sf->next = symtab_fns;
symtab_fns = sf;
}
/* Initialize to read symbols from the symbol file sym_bfd. It either
returns or calls error(). The result is a malloc'd struct sym_fns
that contains cached information about the symbol file. */
static struct sym_fns *
symfile_init (sym_bfd)
bfd *sym_bfd;
{
struct sym_fns *sf, *sf2;
for (sf = symtab_fns; sf != NULL; sf = sf->next)
{
if (!strncmp (bfd_get_target (sym_bfd), sf->sym_name, sf->sym_namelen))
{
sf2 = (struct sym_fns *)xmalloc (sizeof (*sf2));
/* FIXME, who frees this? */
*sf2 = *sf;
sf2->sym_bfd = sym_bfd;
sf2->sym_private = 0; /* Not alloc'd yet */
(*sf2->sym_init) (sf2);
return sf2;
}
}
error ("I'm sorry, Dave, I can't do that. Symbol format unknown.");
}
/* This function runs the load command of our current target. */
void
load_command (arg, from_tty)
char *arg;
int from_tty;
{
target_load (arg, from_tty);
}
/* This function runs the add_syms command of our current target. */
void
add_syms_command (args, from_tty)
char *args;
int from_tty;
{
target_add_syms (args, from_tty);
}
/* This function allows the addition of incrementally linked object files. */
void
add_syms_addr_command (arg_string, from_tty)
char* arg_string;
int from_tty;
{
char *name;
CORE_ADDR text_addr;
if (arg_string == 0)
error ("add-syms takes a file name and an address");
arg_string = tilde_expand (arg_string);
make_cleanup (free, arg_string);
for( ; *arg_string == ' '; arg_string++ );
name = arg_string;
for( ; *arg_string && *arg_string != ' ' ; arg_string++ );
*arg_string++ = (char) 0;
if (name[0] == 0)
error ("add-syms takes a file name and an address");
text_addr = parse_and_eval_address (arg_string);
dont_repeat ();
if (!query ("add symbol table from file \"%s\" at text_addr = 0x%x\n",
name, text_addr))
error ("Not confirmed.");
symbol_file_add (name, 0, text_addr, 0);
}
/* Re-read symbols if the symbol-file has changed. */
void
reread_symbols ()
{
struct stat symstat;
/* With the addition of shared libraries, this should be modified,
the load time should be saved in the partial symbol tables, since
different tables may come from different source files. FIXME.
This routine should then walk down each partial symbol table
and see if the symbol table that it originates from has been changed
*/
if (stat (symfile, &symstat) < 0)
/* Can't read symbol-file. Assume it is up to date. */
return;
if (symstat.st_mtime > symfile_mtime)
{
printf_filtered ("Symbol file has changed; re-reading symbols.\n");
symbol_file_command (symfile, 0);
breakpoint_re_set ();
}
}
/* This function is really horrible, but to avoid it, there would need
to be more filling in of forward references. */
int
fill_in_vptr_fieldno (type)
struct type *type;
{
check_stub_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);
}
/* Functions to handle complaints during symbol reading. */
/* How many complaints about a particular thing should be printed before
we stop whining about it? */
static unsigned stop_whining = 1;
/* Print a complaint about the input symbols, and link the complaint block
into a chain for later handling. Result is 1 if the complaint was
printed, 0 if it was suppressed. */
int
complain (complaint, val)
struct complaint *complaint;
char *val;
{
complaint->counter++;
if (complaint->next == 0) {
complaint->next = complaint_root->next;
complaint_root->next = complaint;
}
if (complaint->counter > stop_whining)
return 0;
wrap_here ("");
if (!info_verbose) {
puts_filtered ("During symbol reading...");
}
printf_filtered (complaint->message, val);
puts_filtered ("...");
wrap_here("");
if (!info_verbose)
puts_filtered ("\n");
return 1;
}
/* Clear out all complaint counters that have ever been incremented. */
void
clear_complaints ()
{
struct complaint *p;
for (p = complaint_root->next; p != complaint_root; p = p->next)
p->counter = 0;
}
void
_initialize_symfile ()
{
add_com ("symbol-file", class_files, symbol_file_command,
"Load symbol table from executable file FILE.\n\
The `file' command can also load symbol tables, as well as setting the file\n\
to execute.");
add_com ("add-syms", class_files, add_syms_command,
"Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\
The second argument provides the starting address of the file's text.");
add_com ("load", class_files, load_command,
"Dynamically load FILE into the running program, and record its symbols\n\
for access from GDB.");
add_show_from_set
(add_set_cmd ("complaints", class_support, var_uinteger,
(char *)&stop_whining,
"Set max number of complaints about incorrect symbols.",
&setlist),
&showlist);
obstack_init (symbol_obstack);
obstack_init (psymbol_obstack);
}

170
gdb/symfile.h Normal file
View file

@ -0,0 +1,170 @@
/* Definitions for reading symbol files into GDB.
Copyright (C) 1990 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This file requires that you first include "bfd.h". */
/* Data structures and function definitions for dealing with
symbol table reading from files. */
/* Structure to keep track of symbol reading functions for various
object file types. */
struct sym_fns {
/* sym_name
is the name, or name prefix, of the BFD "target type" that this
set of functions handles. E.g. "a.out" or "sunOs" or "coff". */
char *sym_name;
/* sym_namelen
counts how many bytes of sym_name should be checked against the
BFD target type of the file being read. If an exact match is
desired, specify the number of characters in sym_name plus 1 for the
NUL. If a prefix match is desired, specify the number of characters in
sym_name. */
int sym_namelen;
/* sym_new_init
initializes anything that is global to the entire
symbol table. It is called e.g. during symbol_file_command, when
we begin debugging an entirely new program. */
void (*sym_new_init) ();
/* sym_init (sf)
reads any initial information from a symbol file, and
initializes the struct sym_fns SF in preparation for sym_read().
It is called every time we read a symbol file for any reason. */
void (*sym_init) ();
/* sym_read (sf, addr, mainline)
reads a symbol file into a psymtab (or possibly a symtab).
SF is the struct sym_fns that sym_init initialized. ADDR
is the offset between the file's specified start address and
its true address in memory. MAINLINE is 1 if this is the
main symbol table being read, and 0 if a secondary
symbol file (e.g. shared library or dynamically loaded file)
is being read. */
void (*sym_read) ();
/* sym_discard (sf)
discards any cached information from SF or elsewhere, that
was saved as part of reading a single symbol file. */
void (*sym_discard) ();
/* sym_bfd
is the accessor for the symbol file being read. */
bfd *sym_bfd;
/* sym_private
is where information can be shared among sym_init, sym_read and
sym_discard. It is typically a pointer to malloc'd memory. */
char *sym_private; /* Should be void * */
/* next
finds the next struct sym_fns. They are allocated and initialized
in whatever module implements the functions pointed to; an
initializer calls add_symtab_fns to add them to the global chain. */
struct sym_fns *next;
};
/* Functions */
extern void free_named_symtab ();
extern int fill_in_vptr_fieldno ();
extern void add_symtab_fns ();
/* Functions for dealing with the misc "function" vector, really a misc
address<->symbol mapping vector for things we don't have debug symbols
for. */
extern void init_misc_bunches ();
extern void prim_record_misc_function ();
extern void discard_misc_bunches ();
extern void condense_misc_bunches ();
/* Sorting your symbols for fast lookup or alphabetical printing. */
extern void sort_block_syms ();
extern void sort_symtab_syms ();
extern void sort_all_symtab_syms ();
extern void sort_block_syms ();
/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
(and add a null character at the end in the copy).
Returns the address of the copy. */
extern char *obsavestring ();
/* Concatenate strings S1, S2 and S3; return the new string.
Space is found in the symbol_obstack. */
extern char *obconcat ();
/* Variables */
/* File name symbols were loaded from. */
extern char *symfile;
/* The modification date of the file when they were loaded. */
extern int symfile_mtime;
/* The BFD for this file -- only good while we're actively reading
symbols into a psymtab or a symtab. */
static bfd *symfile_bfd;
/* Vectors of all partial symbols read in from file. */
extern struct psymbol_allocation_list {
struct partial_symbol *list, *next;
int size;
} global_psymbols, static_psymbols;
/* Support for complaining about things in the symbol file that aren't
catastrophic.
Each such thing gets a counter. The first time we have the problem,
during a symbol read, we report it. At the end of symbol reading,
if verbose, we report how many of each problem we had. */
struct complaint {
char *message;
unsigned counter;
struct complaint *next;
};
/* Root of the chain of complaints that have at some point been issued.
This is used to reset the counters, and/or report the total counts. */
extern struct complaint complaint_root[1];
/* Functions that handle complaints. (in symfile.c) */
int complain();
void clear_complaints();

442
gdb/symmisc.c Normal file
View file

@ -0,0 +1,442 @@
/* Do various things to symbol tables (other than lookup)), for GDB.
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "param.h"
#include "symtab.h"
#include "breakpoint.h"
#include "command.h"
#include <stdio.h>
#include <obstack.h>
static void free_symtab ();
/* Free all the symtabs that are currently installed,
and all storage associated with them.
Leaves us in a consistent state with no symtabs installed. */
void
free_all_symtabs ()
{
register struct symtab *s, *snext;
/* All values will be invalid because their types will be! */
clear_value_history ();
clear_displays ();
clear_internalvars ();
#if defined (CLEAR_SOLIB)
CLEAR_SOLIB ();
#endif
set_default_breakpoint (0, 0, 0, 0);
current_source_symtab = 0;
for (s = symtab_list; s; s = snext)
{
snext = s->next;
free_symtab (s);
}
symtab_list = 0;
obstack_free (symbol_obstack, 0);
obstack_init (symbol_obstack);
if (misc_function_vector)
free (misc_function_vector);
misc_function_count = 0;
misc_function_vector = 0;
clear_pc_function_cache();
}
/* Free a struct block <- B and all the symbols defined in that block. */
static void
free_symtab_block (b)
struct block *b;
{
register int i, n;
n = BLOCK_NSYMS (b);
for (i = 0; i < n; i++)
{
free (SYMBOL_NAME (BLOCK_SYM (b, i)));
free (BLOCK_SYM (b, i));
}
free (b);
}
/* Free all the storage associated with the struct symtab <- S.
Note that some symtabs have contents malloc'ed structure by structure,
while some have contents that all live inside one big block of memory,
and some share the contents of another symbol table and so you should
not free the contents on their behalf (except sometimes the linetable,
which maybe per symtab even when the rest is not).
It is s->free_code that says which alternative to use. */
static void
free_symtab (s)
register struct symtab *s;
{
register int i, n;
register struct blockvector *bv;
register struct typevector *tv;
switch (s->free_code)
{
case free_nothing:
/* All the contents are part of a big block of memory
and some other symtab is in charge of freeing that block.
Therefore, do nothing. */
break;
case free_contents:
/* Here all the contents were malloc'ed structure by structure
and must be freed that way. */
/* First free the blocks (and their symbols. */
bv = BLOCKVECTOR (s);
n = BLOCKVECTOR_NBLOCKS (bv);
for (i = 0; i < n; i++)
free_symtab_block (BLOCKVECTOR_BLOCK (bv, i));
/* Free the blockvector itself. */
free (bv);
/* Free the type vector. */
tv = TYPEVECTOR (s);
free (tv);
/* Also free the linetable. */
case free_linetable:
/* Everything will be freed either by our `free_ptr'
or by some other symbatb, except for our linetable.
Free that now. */
free (LINETABLE (s));
break;
}
/* If there is a single block of memory to free, free it. */
if (s->free_ptr)
free (s->free_ptr);
/* Free source-related stuff */
if (s->line_charpos)
free (s->line_charpos);
if (s->fullname)
free (s->fullname);
free (s);
}
/* If a symtab for filename NAME is found, free it along
with any dependent breakpoints, displays, etc.
Used when loading new versions of object modules with the "add-file"
command.
FIXME. I think this is not the right way to do this. It needs further
investigation, though. -- gnu@cygnus */
void
free_named_symtab (name)
char *name;
{
register struct symtab *s;
register struct symtab *prev;
struct blockvector *bv;
#if 0 /* FIXME */
/* Look for a symtab with the specified name.
We can't use lookup_symtab () for this, since it
might generate a recursive call to psymtab_to_symtab (). */
for (s = symtab_list; s; s = s->next)
{
if (!strcmp (name, s->filename))
break;
prev = s;
}
if (s)
{
if (s == symtab_list)
symtab_list = s->next;
else
prev->next = s->next;
/* For now, delete all breakpoints, displays, etc., whether or
not they depend on the symtab being freed. This should be
changed so that only those data structures affected are deleted. */
/* But don't delete anything if the symtab is empty.
This test is necessary due to a bug in "dbxread.c" that
causes empty symtabs to be created for N_SO symbols that
contain the pathname of the object file. (This problem
has been fixed in GDB 3.9x). */
bv = BLOCKLIST (s);
if (BLOCKLIST_NBLOCKS (bv) > 2
|| BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, 0))
|| BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, 1)))
{
/* Took the following line out because GDB ends up printing it
many times when a given module is loaded, because each module
contains many symtabs. */
/*
printf ("Clearing breakpoints and resetting debugger state.\n");
*/
clear_value_history ();
clear_displays ();
clear_internalvars ();
clear_breakpoints ();
set_default_breakpoint (0, 0, 0, 0);
current_source_symtab = 0;
}
free_symtab (s);
}
else
/* It is still possible that some breakpoints will be affected
even though no symtab was found, since the file might have
been compiled without debugging, and hence not be associated
with a symtab. In order to handle this correctly, we would need
to keep a list of text address ranges for undebuggable files.
For now, we do nothing, since this is a fairly obscure case. */
;
#endif /* FIXME */
}
static int block_depth ();
static void print_symbol ();
void
print_symtabs (filename)
char *filename;
{
FILE *outfile;
register struct symtab *s;
register int i, j;
int len, blen;
register struct linetable *l;
struct blockvector *bv;
register struct block *b;
int depth;
struct cleanup *cleanups;
extern int fclose();
if (filename == 0)
error_no_arg ("file to write symbol data in");
filename = tilde_expand (filename);
make_cleanup (free, filename);
outfile = fopen (filename, "w");
if (outfile == 0)
perror_with_name (filename);
cleanups = make_cleanup (fclose, outfile);
immediate_quit++;
for (s = symtab_list; s; s = s->next)
{
/* First print the line table. */
fprintf (outfile, "Symtab for file %s\n\n", s->filename);
fprintf (outfile, "Line table:\n\n");
l = LINETABLE (s);
len = l->nitems;
for (i = 0; i < len; i++)
fprintf (outfile, " line %d at %x\n", l->item[i].line,
l->item[i].pc);
/* Now print the block info. */
fprintf (outfile, "\nBlockvector:\n\n");
bv = BLOCKVECTOR (s);
len = BLOCKVECTOR_NBLOCKS (bv);
for (i = 0; i < len; i++)
{
b = BLOCKVECTOR_BLOCK (bv, i);
depth = block_depth (b) * 2;
print_spaces (depth, outfile);
fprintf (outfile, "block #%03d (object 0x%x) ", i, b);
fprintf (outfile, "[0x%x..0x%x]", BLOCK_START (b), BLOCK_END (b));
if (BLOCK_SUPERBLOCK (b))
fprintf (outfile, " (under 0x%x)", BLOCK_SUPERBLOCK (b));
if (BLOCK_FUNCTION (b))
fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b)));
fputc ('\n', outfile);
blen = BLOCK_NSYMS (b);
for (j = 0; j < blen; j++)
{
print_symbol (BLOCK_SYM (b, j), depth + 1, outfile);
}
}
fprintf (outfile, "\n\n");
}
immediate_quit--;
do_cleanups (cleanups);
}
static void
print_symbol (symbol, depth, outfile)
struct symbol *symbol;
int depth;
FILE *outfile;
{
print_spaces (depth, outfile);
if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE)
{
fprintf (outfile, "label %s at 0x%x\n", SYMBOL_NAME (symbol),
SYMBOL_VALUE_ADDRESS (symbol));
return;
}
if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE)
{
if (TYPE_NAME (SYMBOL_TYPE (symbol)))
{
type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
}
else
{
fprintf (outfile, "%s %s = ",
(TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM
? "enum"
: (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT
? "struct" : "union")),
SYMBOL_NAME (symbol));
type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
}
fprintf (outfile, ";\n");
}
else
{
if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF)
fprintf (outfile, "typedef ");
if (SYMBOL_TYPE (symbol))
{
type_print_1 (SYMBOL_TYPE (symbol), SYMBOL_NAME (symbol),
outfile, 1, depth);
fprintf (outfile, "; ");
}
else
fprintf (outfile, "%s ", SYMBOL_NAME (symbol));
switch (SYMBOL_CLASS (symbol))
{
case LOC_CONST:
fprintf (outfile, "const %ld (0x%lx),",
SYMBOL_VALUE (symbol), SYMBOL_VALUE (symbol));
break;
case LOC_CONST_BYTES:
fprintf (outfile, "const %u hex bytes:",
TYPE_LENGTH (SYMBOL_TYPE (symbol)));
{
unsigned i;
for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++)
fprintf (outfile, " %2x",
(unsigned)SYMBOL_VALUE_BYTES (symbol) [i]);
fprintf (outfile, ",");
}
break;
case LOC_STATIC:
fprintf (outfile, "static at 0x%x,", SYMBOL_VALUE_ADDRESS (symbol));
break;
case LOC_REGISTER:
fprintf (outfile, "register %ld,", SYMBOL_VALUE (symbol));
break;
case LOC_ARG:
fprintf (outfile, "arg at 0x%lx,", SYMBOL_VALUE (symbol));
break;
case LOC_LOCAL_ARG:
fprintf (outfile, "arg at offset 0x%x from fp,",
SYMBOL_VALUE (symbol));
case LOC_REF_ARG:
fprintf (outfile, "reference arg at 0x%lx,", SYMBOL_VALUE (symbol));
break;
case LOC_REGPARM:
fprintf (outfile, "parameter register %ld,", SYMBOL_VALUE (symbol));
break;
case LOC_LOCAL:
fprintf (outfile, "local at 0x%lx,", SYMBOL_VALUE (symbol));
break;
case LOC_TYPEDEF:
break;
case LOC_LABEL:
fprintf (outfile, "label at 0x%lx", SYMBOL_VALUE_ADDRESS (symbol));
break;
case LOC_BLOCK:
fprintf (outfile, "block (object 0x%x) starting at 0x%x,",
SYMBOL_BLOCK_VALUE (symbol),
BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)));
break;
case LOC_EXTERNAL:
fprintf (outfile, "external at 0x%x", SYMBOL_VALUE_ADDRESS (symbol));
break;
default:
fprintf (outfile, "botched symbol class %x", SYMBOL_CLASS (symbol));
break;
}
}
fprintf (outfile, "\n");
}
/* Return the nexting depth of a block within other blocks in its symtab. */
static int
block_depth (block)
struct block *block;
{
register int i = 0;
while (block = BLOCK_SUPERBLOCK (block)) i++;
return i;
}
/*
* Free all partial_symtab storage.
*/
void
free_all_psymtabs()
{
obstack_free (psymbol_obstack, 0);
obstack_init (psymbol_obstack);
partial_symtab_list = (struct partial_symtab *) 0;
}
void
_initialize_symmisc ()
{
symtab_list = (struct symtab *) 0;
partial_symtab_list = (struct partial_symtab *) 0;
add_com ("printsyms", class_obscure, print_symtabs,
"Print dump of current symbol definitions to file OUTFILE.");
}

2622
gdb/symtab.c Normal file

File diff suppressed because it is too large Load diff

884
gdb/symtab.h Normal file
View file

@ -0,0 +1,884 @@
/* Symbol table definitions for GDB.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (SYMTAB_H)
#define SYMTAB_H 1
#include <obstack.h>
/* An obstack to hold objects that should be freed
when we load a new symbol table.
This includes the symbols made by dbxread
and the types that are not permanent. */
extern struct obstack *symbol_obstack;
extern struct obstack *psymbol_obstack;
/* Some definitions and declarations to go with use of obstacks. */
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
#ifdef __STDC__
extern void *xmalloc ();
#else
extern char *xmalloc ();
#endif
extern void free ();
/* Some macros for char-based bitfields. */
#define B_SET(a,x) (a[x>>3] |= (1 << (x&7)))
#define B_CLR(a,x) (a[x>>3] &= ~(1 << (x&7)))
#define B_TST(a,x) (a[x>>3] & (1 << (x&7)))
#define B_TYPE unsigned char
#define B_BYTES(x) ( 1 + ((x)>>3) )
#define B_CLRALL(a,x) bzero (a, B_BYTES(x))
/* gdb can know one or several symbol tables at the same time;
the ultimate intent is to have one for each separately-compiled module.
Each such symbol table is recorded by a struct symtab, and they
are all chained together. */
/* In addition, gdb can record any number of miscellaneous undebuggable
functions' addresses. In a system that appends _ to function names,
the _'s are removed from the names stored in this table. */
/* Actually, the misc function list is used to store *all* of the
global symbols (text, data, bss, and abs). It is sometimes used
to figure out what symtabs to read in. The "type" field is used
occasionally.
The misc_info field is available for machine-specific information
that can be cached along with a misc function vector entry. The
AMD 29000 tdep.c uses it to remember things it has decoded from the
instructions in the function header, so it doesn't have to rederive
the info constantly (over a serial line). It is initialized to zero
and stays that way until target-dependent code sets it. */
enum misc_function_type {mf_unknown = 0, mf_text, mf_data, mf_bss, mf_abs};
struct misc_function
{
char *name;
CORE_ADDR address;
char *misc_info; /* Random pointer to misc info. void * but for old C */
enum misc_function_type type;
};
/* Address and length of the vector recording all misc function names/addresses. */
struct misc_function *misc_function_vector;
int misc_function_count;
enum language {language_unknown, language_c};
/* All data types of symbols in the compiled program
are represented by `struct type' objects.
All of these objects are pointed to by the typevector.
The type vector may have empty slots that contain zero. */
struct typevector
{
int length; /* Number of types described */
struct type *type[1];
};
/* Different kinds of data types are distinguished by the `code' field. */
enum type_code
{
TYPE_CODE_UNDEF, /* Not used; catches errors */
TYPE_CODE_PTR, /* Pointer type */
TYPE_CODE_ARRAY, /* Array type, lower bound zero */
TYPE_CODE_STRUCT, /* C struct or Pascal record */
TYPE_CODE_UNION, /* C union or Pascal variant part */
TYPE_CODE_ENUM, /* Enumeration type */
TYPE_CODE_FUNC, /* Function type */
TYPE_CODE_INT, /* Integer type */
TYPE_CODE_FLT, /* Floating type */
TYPE_CODE_VOID, /* Void type (values zero length) */
TYPE_CODE_SET, /* Pascal sets */
TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
TYPE_CODE_PASCAL_ARRAY, /* Array with explicit type of index */
TYPE_CODE_ERROR, /* Unknown type */
/* C++ */
TYPE_CODE_MEMBER, /* Member type */
TYPE_CODE_METHOD, /* Method type */
TYPE_CODE_REF, /* C++ Reference types */
};
/* This appears in a type's flags word for an unsigned integer type. */
#define TYPE_FLAG_UNSIGNED 1
/* This appears in a type's flags word
if it is a (pointer to a|function returning a)* built in scalar type.
These types are never freed. */
#define TYPE_FLAG_PERM 4
/* This appears in a type's flags word if it is a stub type (eg. if
someone referenced a type that wasn't definined in a source file
via (struct sir_not_appearing_in_this_film *)). */
#define TYPE_FLAG_STUB 8
/* Set when a class has a constructor defined */
#define TYPE_FLAG_HAS_CONSTRUCTOR 256
/* Set when a class has a destructor defined */
#define TYPE_FLAG_HAS_DESTRUCTOR 512
struct type
{
/* Code for kind of type */
enum type_code code;
/* Name of this type, or zero if none.
This is used for printing only, except by poorly designed C++ code.
Type names specified as input are defined by symbols. */
char *name;
/* Length in bytes of storage for a value of this type */
unsigned length;
/* For a pointer type, describes the type of object pointed to.
For an array type, describes the type of the elements.
For a function or method type, describes the type of the value.
For a range type, describes the type of the full range.
Unused otherwise. */
struct type *target_type;
/* Type that is a pointer to this type.
Zero if no such pointer-to type is known yet.
The debugger may add the address of such a type
if it has to construct one later. */
struct type *pointer_type;
/* C++: also need a reference type. */
struct type *reference_type;
struct type **arg_types;
/* Type that is a function returning this type.
Zero if no such function type is known here.
The debugger may add the address of such a type
if it has to construct one later. */
struct type *function_type;
/* Handling of pointers to members:
TYPE_MAIN_VARIANT is used for pointer and pointer
to member types. Normally it the value of the address of its
containing type. However, for pointers to members, we must be
able to allocate pointer to member types and look them up
from some place of reference.
NEXT_VARIANT is the next element in the chain.
A long time ago (Jul 88; GDB 2.5) Tiemann said that main_variant
may no longer be necessary and that he might eliminate it. I don't
know whether this is still true (or ever was). */
struct type *main_variant, *next_variant;
/* Flags about this type. */
short flags;
/* Number of fields described for this type */
short nfields;
/* For structure and union types, a description of each field.
For set and pascal array types, there is one "field",
whose type is the domain type of the set or array.
For range types, there are two "fields",
the minimum and maximum values (both inclusive).
For enum types, each possible value is described by one "field".
Using a pointer to a separate array of fields
allows all types to have the same size, which is useful
because we can allocate the space for a type before
we know what to put in it. */
struct field
{
/* Position of this field, counting in bits from start of
containing structure. For a function type, this is the
position in the argument list of this argument.
For a range bound or enum value, this is the value itself. */
int bitpos;
/* Size of this field, in bits, or zero if not packed.
For an unpacked field, the field's type's length
says how many bytes the field occupies. */
int bitsize;
/* In a struct or enum type, type of this field.
In a function type, type of this argument.
In an array type, the domain-type of the array. */
struct type *type;
/* Name of field, value or argument.
Zero for range bounds and array domains. */
char *name;
} *fields;
/* C++ */
B_TYPE *virtual_field_bits; /* if base class is virtual */
B_TYPE *private_field_bits;
B_TYPE *protected_field_bits;
/* Number of methods described for this type */
short nfn_fields;
/* Number of base classes this type derives from. */
short n_baseclasses;
/* Number of methods described for this type plus all the
methods that it derives from. */
int nfn_fields_total;
/* For classes, structures, and unions, a description of each field,
which consists of an overloaded name, followed by the types of
arguments that the method expects, and then the name after it
has been renamed to make it distinct. */
struct fn_fieldlist
{
/* The overloaded name. */
char *name;
/* The number of methods with this name. */
int length;
/* The list of methods. */
struct fn_field
{
#if 0
/* The overloaded name */
char *name;
#endif
/* The return value of the method */
struct type *type;
/* The argument list */
struct type **args;
/* The name after it has been processed */
char *physname;
/* For virtual functions. */
/* First baseclass that defines this virtual function. */
struct type *fcontext;
/* Index into that baseclass's virtual function table,
minus 1; else if static: VOFFSET_STATIC; else: 0. */
int voffset;
# define VOFFSET_STATIC (-1)
} *fn_fields;
B_TYPE *private_fn_field_bits;
B_TYPE *protected_fn_field_bits;
} *fn_fieldlists;
unsigned char via_protected;
unsigned char via_public;
/* For types with virtual functions, VPTR_BASETYPE is the base class which
defined the virtual function table pointer. VPTR_FIELDNO is
the field number of that pointer in the structure.
For types that are pointer to member types, VPTR_BASETYPE
ifs the type that this pointer is a member of.
Unused otherwise. */
struct type *vptr_basetype;
int vptr_fieldno;
};
/* All of the name-scope contours of the program
are represented by `struct block' objects.
All of these objects are pointed to by the blockvector.
Each block represents one name scope.
Each lexical context has its own block.
The first two blocks in the blockvector are special.
The first one contains all the symbols defined in this compilation
whose scope is the entire program linked together.
The second one contains all the symbols whose scope is the
entire compilation excluding other separate compilations.
In C, these correspond to global symbols and static symbols.
Each block records a range of core addresses for the code that
is in the scope of the block. The first two special blocks
give, for the range of code, the entire range of code produced
by the compilation that the symbol segment belongs to.
The blocks appear in the blockvector
in order of increasing starting-address,
and, within that, in order of decreasing ending-address.
This implies that within the body of one function
the blocks appear in the order of a depth-first tree walk. */
struct blockvector
{
/* Number of blocks in the list. */
int nblocks;
/* The blocks themselves. */
struct block *block[1];
};
struct block
{
/* Addresses in the executable code that are in this block.
Note: in an unrelocated symbol segment in a file,
these are always zero. They can be filled in from the
N_LBRAC and N_RBRAC symbols in the loader symbol table. */
CORE_ADDR startaddr, endaddr;
/* The symbol that names this block,
if the block is the body of a function;
otherwise, zero.
Note: In an unrelocated symbol segment in an object file,
this field may be zero even when the block has a name.
That is because the block is output before the name
(since the name resides in a higher block).
Since the symbol does point to the block (as its value),
it is possible to find the block and set its name properly. */
struct symbol *function;
/* The `struct block' for the containing block, or 0 if none. */
/* Note that in an unrelocated symbol segment in an object file
this pointer may be zero when the correct value should be
the second special block (for symbols whose scope is one compilation).
This is because the compiler ouptuts the special blocks at the
very end, after the other blocks. */
struct block *superblock;
/* A flag indicating whether or not the fucntion corresponding
to this block was compiled with gcc or not. If there is no
function corresponding to this block, this meaning of this flag
is undefined. (In practice it will be 1 if the block was created
while processing a file compiled with gcc and 0 when not). */
unsigned char gcc_compile_flag;
/* Number of local symbols. */
int nsyms;
/* The symbols. */
struct symbol *sym[1];
};
/* Represent one symbol name; a variable, constant, function or typedef. */
/* Different name spaces for symbols. Looking up a symbol specifies
a namespace and ignores symbol definitions in other name spaces.
VAR_NAMESPACE is the usual namespace.
In C, this contains variables, function names, typedef names
and enum type values.
STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
Thus, if `struct foo' is used in a C program,
it produces a symbol named `foo' in the STRUCT_NAMESPACE.
LABEL_NAMESPACE may be used for names of labels (for gotos);
currently it is not used and labels are not recorded at all. */
/* For a non-global symbol allocated statically,
the correct core address cannot be determined by the compiler.
The compiler puts an index number into the symbol's value field.
This index number can be matched with the "desc" field of
an entry in the loader symbol table. */
enum namespace
{
UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE,
};
/* An address-class says where to find the value of a symbol. */
enum address_class
{
LOC_UNDEF, /* Not used; catches errors */
LOC_CONST, /* Value is constant int SYMBOL_VALUE, host byteorder */
LOC_STATIC, /* Value is at fixed address SYMBOL_VALUE_ADDRESS */
LOC_REGISTER, /* Value is in register */
LOC_ARG, /* Value is at spec'd offset in arglist */
LOC_REF_ARG, /* Value address is at spec'd offset in arglist. */
LOC_REGPARM, /* Value is at spec'd offset in register window */
LOC_LOCAL, /* Value is at spec'd offset in stack frame */
LOC_TYPEDEF, /* Value not used; definition in SYMBOL_TYPE
Symbols in the namespace STRUCT_NAMESPACE
all have this class. */
LOC_LABEL, /* Value is address SYMBOL_VALUE_ADDRESS in the code */
LOC_BLOCK, /* Value is address SYMBOL_VALUE_BLOCK of a
`struct block'. Function names have this class. */
LOC_EXTERNAL, /* Value is at address SYMBOL_VALUE_ADDRESS not in
this compilation.
This is used only in psymtabs; in symtabs
LOC_STATIC is used instead (since in that case
we take the time to find the address). */
LOC_CONST_BYTES, /* Value is a constant byte-sequence pointed to by
SYMBOL_VALUE_ADDRESS, in target byte order. */
LOC_LOCAL_ARG, /* Value is arg at spec'd offset in stack frame.
Differs from LOC_LOCAL in that symbol is an
argument; differs from LOC_ARG in that we find it
in the frame (FRAME_LOCALS_ADDRESS), not in the
arglist (FRAME_ARGS_ADDRESS). Added for i960,
which passes args in regs then copies to frame. */
};
struct symbol
{
/* Symbol name */
char *name;
/* Name space code. */
enum namespace namespace;
/* Address class */
enum address_class class;
/* Data type of value */
struct type *type;
/* Line number of definition. */
unsigned short line;
/* constant value, or address if static, or register number,
or offset in arguments, or offset in stack frame. All of
these are in host byte order (though what they point to might
be in target byte order, e.g. LOC_CONST_BYTES). */
union
{
long value; /* for LOC_CONST, LOC_REGISTER, LOC_ARG,
LOC_REF_ARG, LOC_REGPARM, LOC_LOCAL */
struct block *block; /* for LOC_BLOCK */
char *bytes; /* for LOC_CONST_BYTES */
CORE_ADDR address; /* for LOC_STATIC, LOC_LABEL, LOC_EXTERNAL */
struct symbol *chain; /* for opaque typedef struct chain */
}
value;
};
/* A partial_symbol records the name, namespace, and address class of
symbols whose types we have not parsed yet. For functions, it also
contains their memory address, so we can find them from a PC value.
Each partial_symbol sits in a partial_symtab, all of which are chained
on the partial_symtab_list and which points to the corresponding
normal symtab once the partial_symtab has been referenced. */
struct partial_symbol
{
/* Symbol name */
char *name;
/* Name space code. */
enum namespace namespace;
/* Address class (for info_symbols) */
enum address_class class;
/* Value (only used for static functions currently). Done this
way so that we can use the struct symbol macros.
Note that the address of a function is SYMBOL_VALUE_ADDRESS (pst)
in a partial symbol table, but BLOCK_START (SYMBOL_BLOCK_VALUE (st))
in a symbol table. */
union
{
long value;
CORE_ADDR address;
}
value;
};
/* Source-file information.
This describes the relation between source files and line numbers
and addresses in the program text. */
struct sourcevector
{
int length; /* Number of source files described */
struct source *source[1]; /* Descriptions of the files */
};
/* Each item represents a line-->pc (or the reverse) mapping. This is
somewhat more wasteful of space than one might wish, but since only
the files which are actually debugged are read in to core, we don't
waste much space.
Each item used to be an int; either minus a line number, or a
program counter. If it represents a line number, that is the line
described by the next program counter value. If it is positive, it
is the program counter at which the code for the next line starts. */
struct linetable_entry
{
int line;
CORE_ADDR pc;
};
struct linetable
{
int nitems;
struct linetable_entry item[1];
};
/* All the information on one source file. */
struct source
{
char *name; /* Name of file */
struct linetable contents;
};
/* Each source file is represented by a struct symtab.
These objects are chained through the `next' field. */
struct symtab
{
/* Chain of all existing symtabs. */
struct symtab *next;
/* List of all symbol scope blocks for this symtab. */
struct blockvector *blockvector;
/* Table mapping core addresses to line numbers for this file. */
struct linetable *linetable;
/* Vector containing all types defined for this symtab. */
struct typevector *typevector;
/* Name of this source file. */
char *filename;
/* Directory in which it was compiled, or NULL if we don't know. */
char *dirname;
/* This component says how to free the data we point to:
free_contents => do a tree walk and free each object.
free_nothing => do nothing; some other symtab will free
the data this one uses.
free_linetable => free just the linetable. */
enum free_code {free_nothing, free_contents, free_linetable}
free_code;
/* Pointer to one block of storage to be freed, if nonzero. */
/* This is IN ADDITION to the action indicated by free_code. */
char *free_ptr;
/* Total number of lines found in source file. */
int nlines;
/* Array mapping line number to character position. */
int *line_charpos;
/* Language of this source file. */
enum language language;
/* String of version information. May be zero. */
char *version;
/* Full name of file as found by searching the source path.
0 if not yet known. */
char *fullname;
};
/* Each source file that has not been fully read in is represented by
a partial_symtab. This contains the information on where in the
executable the debugging symbols for a specific file are, and a
list of names of global symbols which are located in this file.
They are all chained on partial_symtab_list.
Even after the source file has been read into a symtab, the
partial_symtab remains around. They are allocated on an obstack,
psymbol_obstack. FIXME, this is bad for dynamic linking or VxWorks-
style execution of a bunch of .o's. */
struct partial_symtab
{
/* Chain of all existing partial symtabs. */
struct partial_symtab *next;
/* Name of the source file which this partial_symtab defines */
char *filename;
/* Name of the symbol file from which symbols should be read. */
char *symfile_name;
/* Address relative to which the symbols in this file are. Need to
relocate by this amount when reading in symbols from the symbol
file. */
CORE_ADDR addr;
/* Offset within loader symbol table of first local symbol for this
file and length (in bytes) of the section of the symbol table
devoted to this file's symbols (actually, the section bracketed
may contain more than just this files symbols
If ldsymlen is 0, the only reason for this things existence is
the dependency list below. Nothing else will happen when it is
read in. */
int ldsymoff, ldsymlen;
/* Range of text addresses covered by this file; texthigh is the
beginning of the next section. */
CORE_ADDR textlow, texthigh;
/* Array of pointers to all of the partial_symtab's which this one
depends on. Since this array can only be set to previous or
the current (?) psymtab, this dependency tree is guaranteed not
to have any loops. */
struct partial_symtab **dependencies;
int number_of_dependencies;
/* Global symbol list. This list will be sorted after readin to
improve access. Binary search will be the usual method of
finding a symbol within it. globals_offset is an integer offset
within ps_globals */
int globals_offset, n_global_syms;
/* Static symbol list. This list will *not* be sorted after readin;
to find a symbol in it, exhaustive search must be used. This is
reasonable because searches through this list will eventually
lead to either the read in of a files symbols for real (assumed
to take a *lot* of time; check) or an error (and we don't care
how long errors take). */
int statics_offset, n_static_syms;
/* Pointer to symtab eventually allocated for this source file, 0 if
!readin or if we haven't looked for the symtab after it was readin. */
struct symtab *symtab;
/* Pointer to function which will read in the symtab corresponding to
this psymtab. */
void (*read_symtab) ();
/* Non-zero if the symtab corresponding to this psymtab has been
readin */
unsigned char readin;
};
/* A fast way to get from a psymtab to its symtab (after the first time). */
#define PSYMTAB_TO_SYMTAB(pst) ((pst)->symtab? \
(pst)->symtab: \
psymtab_to_symtab (pst) )
/* This is the list of struct symtab's that gdb considers current. */
struct symtab *symtab_list;
/* This is the list of struct partial_symtab's that gdb may need to access */
struct partial_symtab *partial_symtab_list;
/* This symtab variable specifies the current file for printing source lines */
struct symtab *current_source_symtab;
/* This is the next line to print for listing source lines. */
int current_source_line;
#define BLOCKLIST(symtab) (symtab)->blockvector
#define BLOCKVECTOR(symtab) (symtab)->blockvector
#define TYPEVECTOR(symtab) (symtab)->typevector
#define LINELIST(symtab) (symtab)->linetable
#define LINETABLE(symtab) (symtab)->linetable
/* Macros normally used to access components of symbol table structures. */
#define BLOCKLIST_NBLOCKS(blocklist) (blocklist)->nblocks
#define BLOCKLIST_BLOCK(blocklist,n) (blocklist)->block[n]
#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks
#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n]
#define TYPEVECTOR_NTYPES(typelist) (typelist)->length
#define TYPEVECTOR_TYPE(typelist,n) (typelist)->type[n]
#define BLOCK_START(bl) (bl)->startaddr
#define BLOCK_END(bl) (bl)->endaddr
#define BLOCK_NSYMS(bl) (bl)->nsyms
#define BLOCK_SYM(bl, n) (bl)->sym[n]
#define BLOCK_FUNCTION(bl) (bl)->function
#define BLOCK_SUPERBLOCK(bl) (bl)->superblock
#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag
/* Nonzero if symbols of block BL should be sorted alphabetically. */
#define BLOCK_SHOULD_SORT(bl) ((bl)->nsyms >= 40)
#define SYMBOL_NAME(symbol) (symbol)->name
#define SYMBOL_NAMESPACE(symbol) (symbol)->namespace
#define SYMBOL_CLASS(symbol) (symbol)->class
#define SYMBOL_VALUE(symbol) (symbol)->value.value
#define SYMBOL_VALUE_ADDRESS(symbol) (symbol)->value.address
#define SYMBOL_VALUE_BYTES(symbol) (symbol)->value.bytes
#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->value.block
#define SYMBOL_VALUE_CHAIN(symbol) (symbol)->value.chain
#define SYMBOL_TYPE(symbol) (symbol)->type
#define SYMBOL_LINE(symbol) (symbol)->line
#define TYPE_NAME(thistype) (thistype)->name
#define TYPE_TARGET_TYPE(thistype) (thistype)->target_type
#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type
#define TYPE_FUNCTION_TYPE(thistype) (thistype)->function_type
#define TYPE_MAIN_VARIANT(thistype) (thistype)->main_variant
#define TYPE_NEXT_VARIANT(thistype) (thistype)->next_variant
#define TYPE_LENGTH(thistype) (thistype)->length
#define TYPE_FLAGS(thistype) (thistype)->flags
#define TYPE_UNSIGNED(thistype) ((thistype)->flags & TYPE_FLAG_UNSIGNED)
#define TYPE_CODE(thistype) (thistype)->code
#define TYPE_NFIELDS(thistype) (thistype)->nfields
#define TYPE_FIELDS(thistype) (thistype)->fields
/* C++ */
#define TYPE_VPTR_BASETYPE(thistype) (thistype)->vptr_basetype
#define TYPE_DOMAIN_TYPE(thistype) (thistype)->vptr_basetype
#define TYPE_VPTR_FIELDNO(thistype) (thistype)->vptr_fieldno
#define TYPE_FN_FIELDS(thistype) (thistype)->fn_fields
#define TYPE_NFN_FIELDS(thistype) (thistype)->nfn_fields
#define TYPE_NFN_FIELDS_TOTAL(thistype) (thistype)->nfn_fields_total
#define TYPE_ARG_TYPES(thistype) (thistype)->arg_types
#define TYPE_BASECLASS(thistype,index) (thistype)->fields[index].type
#define TYPE_N_BASECLASSES(thistype) (thistype)->n_baseclasses
#define TYPE_BASECLASS_NAME(thistype,index) (thistype)->fields[index].name
#define TYPE_BASECLASS_BITPOS(thistype,index) (thistype)->fields[index].bitpos
#define BASETYPE_VIA_PUBLIC(thistype, index) (!TYPE_FIELD_PRIVATE(thistype, index))
#define BASETYPE_VIA_VIRTUAL(thistype, index) B_TST((thistype)->virtual_field_bits, (index))
#define TYPE_FIELD(thistype, n) (thistype)->fields[n]
#define TYPE_FIELD_TYPE(thistype, n) (thistype)->fields[n].type
#define TYPE_FIELD_NAME(thistype, n) (thistype)->fields[n].name
#define TYPE_FIELD_VALUE(thistype, n) (* (int*) &(thistype)->fields[n].type)
#define TYPE_FIELD_BITPOS(thistype, n) (thistype)->fields[n].bitpos
#define TYPE_FIELD_BITSIZE(thistype, n) (thistype)->fields[n].bitsize
#define TYPE_FIELD_PACKED(thistype, n) (thistype)->fields[n].bitsize
#define TYPE_FIELD_PRIVATE_BITS(thistype) (thistype)->private_field_bits
#define TYPE_FIELD_PROTECTED_BITS(thistype) (thistype)->protected_field_bits
#define TYPE_FIELD_VIRTUAL_BITS(thistype) (thistype)->virtual_field_bits
#define SET_TYPE_FIELD_PRIVATE(thistype, n) B_SET ((thistype)->private_field_bits, (n))
#define SET_TYPE_FIELD_PROTECTED(thistype, n) B_SET ((thistype)->protected_field_bits, (n))
#define SET_TYPE_FIELD_VIRTUAL(thistype, n) B_SET ((thistype)->virtual_field_bits, (n))
#define TYPE_FIELD_PRIVATE(thistype, n) B_TST((thistype)->private_field_bits, (n))
#define TYPE_FIELD_PROTECTED(thistype, n) B_TST((thistype)->protected_field_bits, (n))
#define TYPE_FIELD_VIRTUAL(thistype, n) B_TST((thistype)->virtual_field_bits, (n))
#define TYPE_HAS_DESTRUCTOR(thistype) ((thistype)->flags & TYPE_FLAG_HAS_DESTRUCTOR)
#define TYPE_HAS_CONSTRUCTOR(thistype) ((thistype)->flags & TYPE_FLAG_HAS_CONSTRUCTOR)
#define TYPE_FIELD_STATIC(thistype, n) ((thistype)->fields[n].bitpos == -1)
#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) ((char *)(thistype)->fields[n].bitsize)
#define TYPE_FN_FIELDLISTS(thistype) (thistype)->fn_fieldlists
#define TYPE_FN_FIELDLIST(thistype, n) (thistype)->fn_fieldlists[n]
#define TYPE_FN_FIELDLIST1(thistype, n) (thistype)->fn_fieldlists[n].fn_fields
#define TYPE_FN_FIELDLIST_NAME(thistype, n) (thistype)->fn_fieldlists[n].name
#define TYPE_FN_FIELDLIST_LENGTH(thistype, n) (thistype)->fn_fieldlists[n].length
#define TYPE_FN_FIELD(thistype, n) (thistype)[n]
#define TYPE_FN_FIELD_NAME(thistype, n) (thistype)[n].name
#define TYPE_FN_FIELD_TYPE(thistype, n) (thistype)[n].type
#define TYPE_FN_FIELD_ARGS(thistype, n) TYPE_ARG_TYPES ((thistype)[n].type)
#define TYPE_FN_FIELD_PHYSNAME(thistype, n) (thistype)[n].physname
#define TYPE_FN_FIELD_VIRTUAL_P(thistype, n) ((thistype)[n].voffset > 0)
#define TYPE_FN_FIELD_STATIC_P(thistype, n) ((thistype)[n].voffset == VOFFSET_STATIC)
#define TYPE_FN_FIELD_VOFFSET(thistype, n) ((thistype)[n].voffset-1)
#define TYPE_FN_FIELD_FCONTEXT(thistype, n) ((thistype)[n].fcontext)
#define TYPE_FN_PRIVATE_BITS(thistype) (thistype).private_fn_field_bits
#define TYPE_FN_PROTECTED_BITS(thistype) (thistype).protected_fn_field_bits
#define SET_TYPE_FN_PRIVATE(thistype, n) B_SET ((thistype).private_fn_field_bits, n)
#define SET_TYPE_FN_PROTECTED(thistype, n) B_SET ((thistype).protected_fn_field_bits, n)
#define TYPE_FN_PRIVATE(thistype, n) B_TST ((thistype).private_fn_field_bits, n)
#define TYPE_FN_PROTECTED(thistype, n) B_TST ((thistype).protected_fn_field_bits, n)
/* The virtual function table is now an array of structures
which have the form { int16 offset, delta; void *pfn; }.
Gee, can we have more documentation than that? FIXME. -- gnu */
#define VTBL_FNADDR_OFFSET 2
/* Functions that work on the objects described above */
extern struct symtab *lookup_symtab ();
extern struct symbol *lookup_symbol ();
extern struct symbol *lookup_block_symbol ();
extern int lookup_misc_func ();
extern void check_stub_type ();
extern void check_stub_method ();
extern struct type *lookup_primitive_typename ();
extern struct type *lookup_typename ();
extern struct type *lookup_unsigned_typename ();
extern struct type *lookup_struct ();
extern struct type *lookup_union ();
extern struct type *lookup_enum ();
extern struct type *lookup_struct_elt_type ();
extern struct type *lookup_pointer_type ();
extern struct type *lookup_function_type ();
extern struct type *lookup_basetype_type ();
extern struct type *create_array_type ();
extern struct symbol *block_function ();
extern struct symbol *find_pc_function ();
extern int find_pc_partial_function ();
extern void clearpc_function_cache ();
extern struct partial_symtab *lookup_partial_symtab ();
extern struct partial_symtab *find_pc_psymtab ();
extern struct symtab *find_pc_symtab ();
extern struct partial_symbol *find_pc_psymbol ();
extern int find_pc_misc_function ();
extern int find_pc_line_pc_range ();
extern char *type_name_no_tag ();
extern int contained_in();
/* C++ stuff. */
extern struct type *lookup_reference_type ();
extern struct type *lookup_member_type ();
extern struct type *lookup_class ();
extern void smash_to_method_type ();
/* end of C++ stuff. */
extern void free_all_symtabs ();
extern void free_all_psymtabs ();
extern void free_inclink_symtabs ();
extern void reread_symbols ();
extern struct type *builtin_type_void;
extern struct type *builtin_type_char;
extern struct type *builtin_type_short;
extern struct type *builtin_type_int;
extern struct type *builtin_type_long;
extern struct type *builtin_type_unsigned_char;
extern struct type *builtin_type_unsigned_short;
extern struct type *builtin_type_unsigned_int;
extern struct type *builtin_type_unsigned_long;
extern struct type *builtin_type_float;
extern struct type *builtin_type_double;
/* This type represents a type that was unrecognized in symbol
read-in. */
extern struct type *builtin_type_error;
#ifdef LONG_LONG
extern struct type *builtin_type_long_long;
extern struct type *builtin_type_unsigned_long_long;
#define BUILTIN_TYPE_LONGEST builtin_type_long_long
#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long_long
/* This should not be a typedef, because "unsigned LONGEST" needs
to work. */
#define LONGEST long long
#else /* not LONG_LONG. */
#define BUILTIN_TYPE_LONGEST builtin_type_long
#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long
#define LONGEST long
#endif /* not LONG_LONG. */
struct symtab_and_line
{
struct symtab *symtab;
int line;
CORE_ADDR pc;
CORE_ADDR end;
};
struct symtabs_and_lines
{
struct symtab_and_line *sals;
int nelts;
};
/* Given a pc value, return line number it is in.
Second arg nonzero means if pc is on the boundary
use the previous statement's line number. */
struct symtab_and_line find_pc_line ();
/* Given a symtab and line number, return the pc there. */
extern CORE_ADDR find_line_pc ();
extern int find_line_pc_range ();
/* Given a string, return the line specified by it.
For commands like "list" and "breakpoint". */
struct symtabs_and_lines decode_line_spec ();
struct symtabs_and_lines decode_line_spec_1 ();
struct symtabs_and_lines decode_line_1 ();
/* Symbol-reading stuff in symfile.c and solib.c. */
struct symtab *psymtab_to_symtab ();
void clear_solib ();
void symbol_file_add ();
/* source.c */
int identify_source_line ();
void print_source_lines ();
char **make_symbol_completion_list ();
/* The entry point of a file we are reading. */
extern CORE_ADDR entry_point;
#endif /* symtab.h not already included. */

563
gdb/target.c Normal file
View file

@ -0,0 +1,563 @@
/* Select target systems and architectures at runtime for GDB.
Copyright (C) 1990 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include "defs.h"
#include "target.h"
#include "gdbcmd.h"
#include "symtab.h"
#include "inferior.h"
#include "bfd.h"
#include "symfile.h"
extern int memory_insert_breakpoint(), memory_remove_breakpoint();
extern void host_convert_to_virtual(), host_convert_from_virtual();
static void cleanup_target ();
/* Pointer to array of target architecture structures; the size of the
array; the current index into the array; the allocated size of the
array. */
struct target_ops **target_structs;
unsigned target_struct_size;
unsigned target_struct_index;
unsigned target_struct_allocsize;
#define DEFAULT_ALLOCSIZE 10
/* The initial current target, so that there is always a semi-valid
current target. */
struct target_ops dummy_target = {"None", "None",
0, 0, 0, 0, /* open, close, attach, detach */
0, 0, /* resume, wait */
0, 0, 0, 0, 0, /* registers */
0, 0, /* memory */
0, 0, /* bkpts */
0, 0, 0, 0, 0, /* terminal */
0, 0, 0, /* kill, load, add_syms */
0, 0, /* call_function, lookup_symbol */
0, 0, /* create_inferior, mourn_inferior */
dummy_stratum, 0, /* stratum, next */
0, 0, 0, 0, 0, /* all mem, mem, stack, regs, exec */
OPS_MAGIC,
};
/* The target structure we are currently using to talk to a process
or file or whatever "inferior" we have. */
struct target_ops *current_target;
/* The stack of target structures that have been pushed. */
struct target_ops **current_target_stack;
/* Add a possible target architecture to the list. */
void
add_target (t)
struct target_ops *t;
{
if (t->to_magic != OPS_MAGIC)
{
fprintf(stderr, "Magic number of %s target struct wrong\n",
t->to_shortname);
abort();
}
if (!target_structs)
{
target_struct_allocsize = DEFAULT_ALLOCSIZE;
target_structs = (struct target_ops **) xmalloc
(target_struct_allocsize * sizeof (*target_structs));
}
if (target_struct_size >= target_struct_allocsize)
{
target_struct_allocsize *= 2;
target_structs = (struct target_ops **) xrealloc (target_structs,
target_struct_allocsize * sizeof (*target_structs));
}
target_structs[target_struct_size++] = t;
cleanup_target (t);
}
/* Stub functions */
static void
ignore ()
{
}
/* ARGSUSED */
static int
nomemory (memaddr, myaddr, len, write)
CORE_ADDR memaddr;
char *myaddr;
int len;
int write;
{
return 0; /* No bytes handled */
}
static void
tcomplain ()
{
error ("You can't do that when your target is `%s'",
current_target->to_shortname);
}
static int
noprocess ()
{
error ("You can't do that without a process to debug");
}
static int
nosymbol (name, addrp)
char *name;
CORE_ADDR *addrp;
{
return 1; /* Symbol does not exist in target env */
}
static void
default_terminal_info (args, from_tty)
char *args;
int from_tty;
{
printf("No saved terminal information.\n");
}
#if 0
/* With strata, this function is no longer needed. FIXME. */
/* This is the default target_create_inferior function. It looks up
the stack for some target that cares to create inferiors, then
calls it -- or complains if not found. */
static void
upstack_create_inferior (exec, args, env)
char *exec;
char *args;
char **env;
{
struct target_ops *t;
for (t = current_target;
t;
t = t->to_next)
{
if (t->to_create_inferior != upstack_create_inferior)
{
t->to_create_inferior (exec, args, env);
return;
}
}
tcomplain();
}
#endif
/* This is the default target_create_inferior and target_attach function.
If the current target is executing, it asks whether to kill it off.
If this function returns without calling error(), it has killed off
the target, and the operation should be attempted. */
static void
kill_or_be_killed (from_tty)
int from_tty;
{
struct target_ops *savecur;
if (target_has_execution)
{
printf ("You are already running a program:\n");
target_files_info ();
if (query ("Kill it? ")) {
savecur = current_target;
target_kill (0, from_tty);
if (target_has_execution)
error ("Killing the program did not help.");
return;
} else {
error ("Program not killed.");
}
}
tcomplain();
}
static void
maybe_kill_then_attach (args, from_tty)
char *args;
int from_tty;
{
kill_or_be_killed (from_tty);
target_attach (args, from_tty);
}
static void
maybe_kill_then_create_inferior (exec, args, env)
char *exec;
char *args;
char **env;
{
kill_or_be_killed (0);
target_create_inferior (exec, args, env);
}
/* Clean up a target struct so it no longer has any zero pointers in it.
We default entries, at least to stubs that print error messages. */
static void
cleanup_target (t)
struct target_ops *t;
{
/* Check magic number. If wrong, it probably means someone changed
the struct definition, but not all the places that initialize one. */
if (t->to_magic != OPS_MAGIC)
{
fprintf(stderr, "Magic number of %s target struct wrong\n",
t->to_shortname);
abort();
}
#define de_fault(field, value) \
if (!t->field) t->field = value
/* FIELD DEFAULT VALUE */
de_fault (to_open, tcomplain);
de_fault (to_close, (void (*)())ignore);
de_fault (to_attach, maybe_kill_then_attach);
de_fault (to_detach, (void (*)())ignore);
de_fault (to_resume, (void (*)())noprocess);
de_fault (to_wait, noprocess);
de_fault (to_fetch_registers, noprocess);
de_fault (to_store_registers, noprocess);
de_fault (to_prepare_to_store, (void (*)())noprocess);
de_fault (to_convert_to_virtual, host_convert_to_virtual);
de_fault (to_convert_from_virtual, host_convert_from_virtual);
de_fault (to_xfer_memory, nomemory);
de_fault (to_files_info, ignore);
de_fault (to_insert_breakpoint, memory_insert_breakpoint);
de_fault (to_remove_breakpoint, memory_remove_breakpoint);
de_fault (to_terminal_init, ignore);
de_fault (to_terminal_inferior, ignore);
de_fault (to_terminal_ours_for_output,ignore);
de_fault (to_terminal_ours, ignore);
de_fault (to_terminal_info, default_terminal_info);
de_fault (to_kill, (void (*)())noprocess);
de_fault (to_load, tcomplain);
de_fault (to_add_syms, tcomplain);
de_fault (to_call_function, (struct value *(*)())noprocess);
de_fault (to_lookup_symbol, nosymbol);
de_fault (to_create_inferior, maybe_kill_then_create_inferior);
de_fault (to_mourn_inferior, (void (*)())noprocess);
de_fault (to_next, 0);
de_fault (to_has_all_memory, 0);
de_fault (to_has_memory, 0);
de_fault (to_has_stack, 0);
de_fault (to_has_registers, 0);
de_fault (to_has_execution, 0);
#undef de_fault
}
/* Push a new target type into the stack of the existing target accessors,
possibly superseding some of the existing accessors.
Result is zero if the pushed target ended up on top of the stack,
nonzero if at least one target is on top of it.
Rather than allow an empty stack, we always have the dummy target at
the bottom stratum, so we can call the function vectors without
checking them. */
int
push_target (t)
struct target_ops *t;
{
struct target_ops *st, *prev;
for (prev = 0, st = current_target;
st;
prev = st, st = st->to_next) {
if ((int)(t->to_stratum) >= (int)(st->to_stratum))
break;
}
while (t->to_stratum == st->to_stratum) {
/* There's already something on this stratum. Close it off. */
(st->to_close) (0);
if (prev)
prev->to_next = st->to_next; /* Unchain old target_ops */
else
current_target = st->to_next; /* Unchain first on list */
st = st->to_next;
}
/* We have removed all targets in our stratum, now add ourself. */
t->to_next = st;
if (prev)
prev->to_next = t;
else
current_target = t;
cleanup_target (current_target);
return prev != 0;
}
/* Remove a target_ops vector from the stack, wherever it may be.
Return how many times it was removed (0 or 1 unless bug). */
int
unpush_target (t)
struct target_ops *t;
{
struct target_ops *u, *v;
int result = 0;
for (u = current_target, v = 0;
u;
v = u, u = u->to_next)
if (u == t)
{
if (v == 0)
pop_target(); /* unchain top copy */
else {
(t->to_close)(0); /* Let it clean up */
v->to_next = t->to_next; /* unchain middle copy */
}
result++;
}
return result;
}
void
pop_target ()
{
(current_target->to_close)(0); /* Let it clean up */
current_target = current_target->to_next;
if (!current_target) /* At bottom, push dummy. */
push_target (&dummy_target);
}
/* Print things about the whole set of targets and about the
current target stack. */
static void
targets_info ()
{
int i;
printf("Possible targets:\n\n");
for (i = 0; i < target_struct_size; i++)
printf ("%-15s %s\n",
target_structs[i]->to_shortname,
target_structs[i]->to_longname);
}
/* Move memory to or from the targets. Iterate until all of it has
been moved, if necessary. The top target gets priority; anything
it doesn't want, is offered to the next one down, etc. Note the
business with curlen: if an early target says "no, but I have a
boundary overlapping this xfer" then we shorten what we offer to
the subsequent targets so the early guy will get a chance at the
tail before the subsequent ones do.
Result is 0 or errno value. */
int
target_read_memory (memaddr, myaddr, len)
CORE_ADDR memaddr;
char *myaddr;
int len;
{
return target_xfer_memory (memaddr, myaddr, len, 0);
}
int
target_write_memory (memaddr, myaddr, len)
CORE_ADDR memaddr;
char *myaddr;
int len;
{
return target_xfer_memory (memaddr, myaddr, len, 1);
}
int
target_xfer_memory (memaddr, myaddr, len, write)
CORE_ADDR memaddr;
char *myaddr;
int len;
int write;
{
int curlen;
int res;
struct target_ops *t;
/* The quick case is that the top target does it all. */
res = current_target->to_xfer_memory(memaddr, myaddr, len, write);
if (res == len)
return 0;
if (res > 0)
goto bump;
/* If res <= 0 then we call it again in the loop. Ah well. */
for (; len > 0;)
{
curlen = len; /* Want to do it all */
for (t = current_target;
t;
t = t->to_has_all_memory? 0: t->to_next)
{
res = t->to_xfer_memory(memaddr, myaddr, curlen, write);
if (res > 0) break; /* Handled all or part of xfer */
if (res == 0) continue; /* Handled none */
curlen = -res; /* Could handle once we get past res bytes */
}
if (res <= 0)
{
/* If this address is for nonexistent memory,
read zeros if reading, or do nothing if writing. Return error. */
if (!write)
bzero (myaddr, len);
return EIO;
}
bump:
memaddr += res;
myaddr += res;
len -= res;
}
return 0; /* We managed to cover it all somehow. */
}
static void
target_info (args, from_tty)
char *args;
int from_tty;
{
struct target_ops *t;
int has_all_mem = 0;
if (symfile != 0)
printf ("Symbols from \"%s\".\n", symfile);
#ifdef FILES_INFO_HOOK
if (FILES_INFO_HOOK ())
return;
#endif
for (t = current_target;
t;
t = t->to_next)
{
if ((int)(t->to_stratum) <= (int)dummy_stratum)
continue;
if (has_all_mem)
printf("\tWhile running this, gdb does not access memory from...\n");
printf("%s:\n", t->to_longname);
(t->to_files_info)();
has_all_mem = t->to_has_all_memory;
}
}
/* The target command selects a target and calls its open routine.
The open routine takes the rest of the parameters from the command,
and (if successful) pushes a new target onto the stack. */
static void
target_command (args, from_tty)
char *args;
int from_tty;
{
int i;
char *rest;
dont_repeat();
if (!args)
error (
"Argument required (target name). `info targets' lists possible targets");
if (target_has_execution)
{
if (query ("A program is being debugged already. Kill it? "))
target_kill ((char *)0, from_tty);
else
error ("Program not killed.");
}
/* Skip to first space, or end of args */
for (rest = args; *rest && !isspace(*rest); rest++) ;
if (*rest == '\0')
rest = 0; /* Only one word in args */
else
{
*rest = '\0'; /* Terminate first word, scan for next */
for (rest++; isspace (*rest); rest++) ;
if (*rest == '\0') /* Only one word w/trailing blanks */
rest = 0;
}
/* Search target list for a match */
for (i = 0; i < target_struct_size; i++)
{
if (!strcmp (args, target_structs[i]->to_shortname))
goto gotit;
}
error ("No such target. `info targets' will list all targets");
gotit:
(*target_structs[i]->to_open) (rest, from_tty);
}
static char targ_desc[] =
"Names of targets and files being debugged.\n\
Shows the entire stack of targets currently in use (including the exec-file,\n\
core-file, and process, if any), as well as the symbol file name.";
void
_initialize_targets ()
{
current_target = &dummy_target;
cleanup_target (current_target);
add_info ("targets", targets_info,
"Names of all possible targets.\n\
A target is typically a protocol for talking to debugging facilities;\n\
for example, `child' for Unix child processes, or `vxworks' for a\n\
TCP/IP link to a VxWorks system.");
add_info ("target", target_info, targ_desc);
add_info ("files", target_info, targ_desc);
add_com ("target", class_run, target_command,
"Connect to a target machine or process.\n\
The first argument is the type or protocol of the target machine. Remaining\n\
arguments are interpreted by the target protocol, but typically include\n\
things like device names or host names to connect with, process numbers,\n\
baud rates, etc. You can list all possible targets with the `info targets'\n\
command.");
}

406
gdb/target.h Normal file
View file

@ -0,0 +1,406 @@
/* Interface between GDB and target environments, including files and processes
Copyright 1990, 1991 Free Software Foundation, Inc.
Contributed by Cygnus Support. Written by John Gilmore.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This include file defines the interface between the main part
of the debugger, and the part which is target-specific, or
specific to the communications interface between us and the
target.
A TARGET is an interface between the debugger and a particular
kind of file or process. Targets can be STACKED in STRATA,
so that more than one target can potentially respond to a request.
In particular, memory accesses will walk down the stack of targets
until they find a target that is interested in handling that particular
address. STRATA are artificial boundaries on the stack, within
which particular kinds of targets live. Strata exist so that
people don't get confused by pushing e.g. a process target and then
a file target, and wondering why they can't see the current values
of variables any more (the file target is handling them and they
never get to the process target). So when you push a file target,
it goes into the file stratum, which is always below the process
stratum. */
enum strata {
dummy_stratum, /* The lowest of the low */
file_stratum, /* Executable files, etc */
core_stratum, /* Core dump files */
process_stratum, /* Executing processes */
};
struct target_ops {
char *to_shortname; /* Name this target type */
char *to_longname; /* Name for printing */
#ifdef __STDC__
void (*to_open) (char *name, int from_tty);
void (*to_close) (int quitting);
void (*to_attach) (char *name, int from_tty);
void (*to_detach) (char *args, int from_tty);
void (*to_resume) (int step, int siggnal);
int (*to_wait) (int *status);
int (*to_fetch_registers) (int regno);
int (*to_store_registers) (int regno);
void (*to_prepare_to_store) ();
void (*to_convert_to_virtual) (int regnum, char *from, char *to);
void (*to_convert_from_virtual) (int regnum, char *from, char *to);
int (*to_xfer_memory) (CORE_ADDR memaddr, char *myaddr, int len, int w);
void (*to_files_info) ();
int (*to_insert_breakpoint) (CORE_ADDR addr, char *save);
int (*to_remove_breakpoint) (CORE_ADDR addr, char *save);
void (*to_terminal_init) ();
void (*to_terminal_inferior) ();
void (*to_terminal_ours_for_output) ();
void (*to_terminal_ours) ();
void (*to_terminal_info) (char *arg, int from_tty);
void (*to_kill) (char *arg, int from_tty);
void (*to_load) (char *arg, int from_tty);
void (*to_add_syms) (char *arg, int from_tty);
struct value *(*to_call_function) (struct value *function,
int nargs, struct value **args);
int (*to_lookup_symbol) (char *name, CORE_ADDR *addrp);
void (*to_create_inferior) (char *exec, char *args, char **env);
void (*to_mourn_inferior) ();
enum strata to_stratum;
struct target_ops *to_next;
int to_has_all_memory;
int to_has_memory;
int to_has_stack;
int to_has_registers;
int to_has_execution;
int to_magic;
/* Need sub-structure for target machine related rather than comm related? */
#else /* STDC */
void (*to_open) ();
void (*to_close) ();
void (*to_attach) ();
void (*to_detach) ();
void (*to_resume) ();
int (*to_wait) ();
int (*to_fetch_registers) ();
int (*to_store_registers) ();
void (*to_prepare_to_store) ();
void (*to_convert_to_virtual) ();
void (*to_convert_from_virtual) ();
int (*to_xfer_memory) ();
void (*to_files_info) ();
int (*to_insert_breakpoint) ();
int (*to_remove_breakpoint) ();
void (*to_terminal_init) ();
void (*to_terminal_inferior) ();
void (*to_terminal_ours_for_output) ();
void (*to_terminal_ours) ();
void (*to_terminal_info) ();
void (*to_kill) ();
void (*to_load) ();
void (*to_add_syms) ();
struct value *(*to_call_function) ();
int (*to_lookup_symbol) ();
void (*to_create_inferior) ();
void (*to_mourn_inferior) ();
enum strata to_stratum;
struct target_ops *to_next;
int to_has_all_memory;
int to_has_memory;
int to_has_stack;
int to_has_registers;
int to_has_execution;
int to_magic;
/* Need sub-structure for target machine related rather than comm related? */
#endif
};
/* Magic number for checking ops size. If a struct doesn't end with this
number, somebody changed the declaration but didn't change all the
places that initialize one. */
#define OPS_MAGIC 3840
/* The ops structure for our "current" target process. */
extern struct target_ops *current_target;
/* Define easy words for doing these operations on our current target. */
#define target_shortname (current_target->to_shortname)
#define target_longname (current_target->to_longname)
#define target_open(name, from_tty) \
(*current_target->to_open) (name, from_tty)
/* Does whatever cleanup is required for a target that we are no longer
going to be calling. Argument says whether we are quitting gdb and
should not get hung in case of errors, or whether we want a clean
termination even if it takes a while. This routine is automatically
always called just before a routine is popped off the target stack.
Closing file descriptors and freeing memory are typical things it should
do. */
#define target_close(quitting) \
(*current_target->to_close) (quitting)
/* Attaches to a process on the target side. */
#define target_attach(args, from_tty) \
(*current_target->to_attach) (args, from_tty)
/* Takes a program previously attached to and detaches it.
The program may resume execution (some targets do, some don't) and will
no longer stop on signals, etc. We better not have left any breakpoints
in the program or it'll die when it hits one. ARGS is arguments
typed by the user (e.g. a signal to send the process). FROM_TTY
says whether to be verbose or not. */
#define target_detach(args, from_tty) \
(*current_target->to_detach) (args, from_tty)
/* Resume execution of the target process. STEP says whether to single-step
or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given
to the target, or zero for no signal. */
#define target_resume(step, siggnal) \
(*current_target->to_resume) (step, siggnal)
/* Wait for inferior process to do something. Return pid of child,
or -1 in case of error; store status through argument pointer STATUS. */
#define target_wait(status) \
(*current_target->to_wait) (status)
/* Fetch register REGNO, or all regs if regno == -1. Result is 0
for success, -1 for problems. */
#define target_fetch_registers(regno) \
(*current_target->to_fetch_registers) (regno)
/* Store at least register REGNO, or all regs if REGNO == -1.
It can store as many registers as it wants to, so the entire registers
array must be valid. Result is 0 for success, -1 for problems. */
#define target_store_registers(regs) \
(*current_target->to_store_registers) (regs)
/* Get ready to modify the registers array. On machines which store
individual registers, this doesn't need to do anything. On machines
which store all the registers in one fell swoop, this makes sure
that REGISTERS contains all the registers from the program being
debugged. */
#define target_prepare_to_store() \
(*current_target->to_prepare_to_store) ()
/* Convert data from raw format for register REGNUM
to virtual format for register REGNUM. */
#define target_convert_to_virtual(regnum, from, to) \
(*current_target->to_convert_to_virtual) (regnum, from, to)
/* Convert data from virtual format for register REGNUM
to raw format for register REGNUM. */
#define target_convert_from_virtual(regnum, from, to) \
(*current_target->to_convert_from_virtual) (regnum, from, to)
/* Reading and writing memory actually happens through a glue
function which iterates across the various targets. Result is
0 for success, or an errno value. */
#ifdef __STDC__
/* Needs defs.h for CORE_ADDR */
extern int target_read_memory(CORE_ADDR memaddr, char *myaddr, int len);
extern int target_write_memory(CORE_ADDR memaddr, char *myaddr, int len);
extern int target_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len,
int write);
#else
extern int target_read_memory();
extern int target_write_memory();
extern int target_xfer_memory();
#endif
/* Print a line about the current target. */
#define target_files_info() \
(*current_target->to_files_info) ()
/* Insert a breakpoint at address ADDR in the target machine.
SAVE is a pointer to memory allocated for saving the
target contents. It is guaranteed by the caller to be long enough
to save "sizeof BREAKPOINT" bytes. Result is 0 for success, or
an errno value. */
#define target_insert_breakpoint(addr, save) \
(*current_target->to_insert_breakpoint) (addr, save)
/* Remove a breakpoint at address ADDR in the target machine.
SAVE is a pointer to the same save area
that was previously passed to target_insert_breakpoint.
Result is 0 for success, or an errno value. */
#define target_remove_breakpoint(addr, save) \
(*current_target->to_remove_breakpoint) (addr, save)
/* Initialize the terminal settings we record for the inferior,
before we actually run the inferior. */
#define target_terminal_init() \
(*current_target->to_terminal_init) ()
/* Put the inferior's terminal settings into effect.
This is preparation for starting or resuming the inferior. */
#define target_terminal_inferior() \
(*current_target->to_terminal_inferior) ()
/* 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. */
#define target_terminal_ours_for_output() \
(*current_target->to_terminal_ours_for_output) ()
/* Put our terminal settings into effect.
First record the inferior's terminal settings
so they can be restored properly later. */
#define target_terminal_ours() \
(*current_target->to_terminal_ours) ()
/* Print useful information about our terminal status, if such a thing
exists. */
#define target_terminal_info(arg, from_tty) \
(*current_target->to_terminal_info) (arg, from_tty)
/* Kill the inferior process. Make it go away. */
#define target_kill(arg, from_tty) \
(*current_target->to_kill) (arg, from_tty)
/* Load an executable file into the target process. This is expected to
not only bring new code into the target process, but also to update
GDB's symbol tables to match. */
#define target_load(arg, from_tty) \
(*current_target->to_load) (arg, from_tty)
/* Add the symbols from an executable file into GDB's symbol table, as if
the file had been loaded at a particular address (or set of addresses).
This does not change any state in the target system, only in GDB. */
#define target_add_syms(arg, from_tty) \
(*current_target->to_add_syms) (arg, from_tty)
/* Perform a function call in the inferior.
ARGS is a vector of values of arguments (NARGS of them).
FUNCTION is a value, the function to be called.
Returns a value representing what the function returned.
May fail to return, if a breakpoint or signal is hit
during the execution of the function. */
#define target_call_function(function, nargs, args) \
(*current_target->to_call_function) (function, nargs, args)
/* Look up a symbol in the target's symbol table. NAME is the symbol
name. ADDRP is a CORE_ADDR * pointing to where the value of the symbol
should be returned. The result is 0 if successful, nonzero if the
symbol does not exist in the target environment. This function should
not call error() if communication with the target is interrupted, since
it is called from symbol reading, but should return nonzero, possibly
doing a complain(). */
#define target_lookup_symbol(name, addrp) \
(*current_target->to_lookup_symbol) (name, addrp)
/* Start an inferior process and set inferior_pid to its pid.
EXEC_FILE is the file to run.
ALLARGS is a string containing the arguments to the program.
ENV is the environment vector to pass. Errors reported with error().
On VxWorks and various standalone systems, we ignore exec_file. */
#define target_create_inferior(exec_file, args, env) \
(*current_target->to_create_inferior) (exec_file, args, env)
/* The inferior process has died. Do what is right. */
#define target_mourn_inferior() \
(*current_target->to_mourn_inferior) ()
/* Pointer to next target in the chain, e.g. a core file and an exec file. */
#define target_next \
(current_target->to_next)
/* Does the target include all of memory, or only part of it? This
determines whether we look up the target chain for other parts of
memory if this target can't satisfy a request. */
#define target_has_all_memory \
(current_target->to_has_all_memory)
/* Does the target include memory? (Dummy targets don't.) */
#define target_has_memory \
(current_target->to_has_memory)
/* Does the target have a stack? (Exec files don't, VxWorks doesn't, until
we start a process.) */
#define target_has_stack \
(current_target->to_has_stack)
/* Does the target have registers? (Exec files don't.) */
#define target_has_registers \
(current_target->to_has_registers)
/* Does the target have execution? Can we make it jump (through hoops),
or pop its stack a few times, or set breakpoints? */
#define target_has_execution \
(current_target->to_has_execution)
/* Routines for maintenance of the target structures...
add_target: Add a target to the list of all possible targets.
push_target: Make this target the top of the stack of currently used
targets, within its particular stratum of the stack. Result
is 0 if now atop the stack, nonzero if not on top (maybe
should warn user).
unpush_target: Remove this from the stack of currently used targets,
no matter where it is on the list. Returns 0 if no
change, 1 if removed from stack.
pop_target: Remove the top thing on the stack of current targets. */
#ifdef __STDC__
void add_target (struct target_ops *);
int push_target (struct target_ops *);
int unpush_target (struct target_ops *);
void pop_target ();
#else
void add_target ();
int push_target ();
int unpush_target ();
void pop_target ();
#endif

50
gdb/terminal.h Normal file
View file

@ -0,0 +1,50 @@
/* Terminal interface definitions for GDB, the GNU Debugger.
Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Define a common set of macros -- BSD based -- and redefine whatever
the system offers to make it look like that. */
#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
#ifdef NO_JOB_CONTROL
# undef TIOCGPGRP
# undef TIOCGPGRP
#endif
#else /* no termio */
#include <fcntl.h>
#include <sgtty.h>
#include <sys/ioctl.h>
#define TERMINAL struct sgttyb
#endif /* no termio */
extern void new_tty ();

1294
gdb/utils.c Normal file

File diff suppressed because it is too large Load diff

694
gdb/valarith.c Normal file
View file

@ -0,0 +1,694 @@
/* Perform arithmetic and other operations on values, for GDB.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "param.h"
#include "value.h"
#include "expression.h"
#include "target.h"
#include <string.h>
value value_x_binop ();
value value_subscripted_rvalue ();
value
value_add (arg1, arg2)
value arg1, arg2;
{
register value val, valint, valptr;
register int len;
COERCE_ARRAY (arg1);
COERCE_ARRAY (arg2);
if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
|| TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR)
&&
(TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT
|| TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT))
/* Exactly one argument is a pointer, and one is an integer. */
{
if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
{
valptr = arg1;
valint = arg2;
}
else
{
valptr = arg2;
valint = arg1;
}
len = TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (valptr)));
if (len == 0) len = 1; /* For (void *) */
val = value_from_long (builtin_type_long,
value_as_long (valptr)
+ (len * value_as_long (valint)));
VALUE_TYPE (val) = VALUE_TYPE (valptr);
return val;
}
return value_binop (arg1, arg2, BINOP_ADD);
}
value
value_sub (arg1, arg2)
value arg1, arg2;
{
register value val;
COERCE_ARRAY (arg1);
COERCE_ARRAY (arg2);
if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
{
if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)
{
/* pointer - integer. */
val = value_from_long
(builtin_type_long,
value_as_long (arg1)
- (TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)))
* value_as_long (arg2)));
VALUE_TYPE (val) = VALUE_TYPE (arg1);
return val;
}
else if (VALUE_TYPE (arg1) == VALUE_TYPE (arg2))
{
/* pointer to <type x> - pointer to <type x>. */
val = value_from_long
(builtin_type_long,
(value_as_long (arg1) - value_as_long (arg2))
/ TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))));
return val;
}
else
{
error ("\
First argument of `-' is a pointer and second argument is neither\n\
an integer nor a pointer of the same type.");
}
}
return value_binop (arg1, arg2, BINOP_SUB);
}
/* Return the value of ARRAY[IDX]. */
value
value_subscript (array, idx)
value array, idx;
{
if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_ARRAY
&& VALUE_LVAL (array) != lval_memory)
return value_subscripted_rvalue (array, idx);
else
return value_ind (value_add (array, idx));
}
/* Return the value of EXPR[IDX], expr an aggregate rvalue
(eg, a vector register). This routine used to promote floats
to doubles, but no longer does. */
value
value_subscripted_rvalue (array, idx)
value array, idx;
{
struct type *elt_type = TYPE_TARGET_TYPE (VALUE_TYPE (array));
int elt_size = TYPE_LENGTH (elt_type);
int elt_offs = elt_size * value_as_long (idx);
value v;
if (elt_offs >= TYPE_LENGTH (VALUE_TYPE (array)))
error ("no such vector element");
v = allocate_value (elt_type);
bcopy (VALUE_CONTENTS (array) + elt_offs, VALUE_CONTENTS (v), elt_size);
if (VALUE_LVAL (array) == lval_internalvar)
VALUE_LVAL (v) = lval_internalvar_component;
else
VALUE_LVAL (v) = not_lval;
VALUE_ADDRESS (v) = VALUE_ADDRESS (array);
VALUE_OFFSET (v) = VALUE_OFFSET (array) + elt_offs;
VALUE_BITSIZE (v) = elt_size * 8;
return v;
}
/* Check to see if either argument is a structure. This is called so
we know whether to go ahead with the normal binop or look for a
user defined function instead.
For now, we do not overload the `=' operator. */
int
binop_user_defined_p (op, arg1, arg2)
enum exp_opcode op;
value arg1, arg2;
{
if (op == BINOP_ASSIGN)
return 0;
return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT
|| TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_STRUCT
|| (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
&& TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT)
|| (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_REF
&& TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) == TYPE_CODE_STRUCT));
}
/* Check to see if argument is a structure. This is called so
we know whether to go ahead with the normal unop or look for a
user defined function instead.
For now, we do not overload the `&' operator. */
int unop_user_defined_p (op, arg1)
enum exp_opcode op;
value arg1;
{
if (op == UNOP_ADDR)
return 0;
return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT
|| (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
&& TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT));
}
/* We know either arg1 or arg2 is a structure, so try to find the right
user defined function. Create an argument vector that calls
arg1.operator @ (arg1,arg2) and return that value (where '@' is any
binary operator which is legal for GNU C++). */
value
value_x_binop (arg1, arg2, op, otherop)
value arg1, arg2;
enum exp_opcode op, otherop;
{
value * argvec;
char *ptr;
char tstr[13];
int static_memfuncp;
COERCE_ENUM (arg1);
COERCE_ENUM (arg2);
/* now we know that what we have to do is construct our
arg vector and find the right function to call it with. */
if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT)
error ("Can't do that binary op on that type"); /* FIXME be explicit */
argvec = (value *) alloca (sizeof (value) * 4);
argvec[1] = value_addr (arg1);
argvec[2] = arg2;
argvec[3] = 0;
/* make the right function name up */
strcpy(tstr, "operator__");
ptr = tstr+8;
switch (op)
{
case BINOP_ADD: strcpy(ptr,"+"); break;
case BINOP_SUB: strcpy(ptr,"-"); break;
case BINOP_MUL: strcpy(ptr,"*"); break;
case BINOP_DIV: strcpy(ptr,"/"); break;
case BINOP_REM: strcpy(ptr,"%"); break;
case BINOP_LSH: strcpy(ptr,"<<"); break;
case BINOP_RSH: strcpy(ptr,">>"); break;
case BINOP_LOGAND: strcpy(ptr,"&"); break;
case BINOP_LOGIOR: strcpy(ptr,"|"); break;
case BINOP_LOGXOR: strcpy(ptr,"^"); break;
case BINOP_AND: strcpy(ptr,"&&"); break;
case BINOP_OR: strcpy(ptr,"||"); break;
case BINOP_MIN: strcpy(ptr,"<?"); break;
case BINOP_MAX: strcpy(ptr,">?"); break;
case BINOP_ASSIGN: strcpy(ptr,"="); break;
case BINOP_ASSIGN_MODIFY:
switch (otherop)
{
case BINOP_ADD: strcpy(ptr,"+="); break;
case BINOP_SUB: strcpy(ptr,"-="); break;
case BINOP_MUL: strcpy(ptr,"*="); break;
case BINOP_DIV: strcpy(ptr,"/="); break;
case BINOP_REM: strcpy(ptr,"%="); break;
case BINOP_LOGAND: strcpy(ptr,"&="); break;
case BINOP_LOGIOR: strcpy(ptr,"|="); break;
case BINOP_LOGXOR: strcpy(ptr,"^="); break;
default:
error ("Invalid binary operation specified.");
}
break;
case BINOP_SUBSCRIPT: strcpy(ptr,"[]"); break;
case BINOP_EQUAL: strcpy(ptr,"=="); break;
case BINOP_NOTEQUAL: strcpy(ptr,"!="); break;
case BINOP_LESS: strcpy(ptr,"<"); break;
case BINOP_GTR: strcpy(ptr,">"); break;
case BINOP_GEQ: strcpy(ptr,">="); break;
case BINOP_LEQ: strcpy(ptr,"<="); break;
default:
error ("Invalid binary operation specified.");
}
argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure");
if (argvec[0])
{
if (static_memfuncp)
{
argvec[1] = argvec[0];
argvec++;
}
return target_call_function (argvec[0], 2 - static_memfuncp, argvec + 1);
}
error ("member function %s not found", tstr);
#ifdef lint
return target_call_function (argvec[0], 2 - static_memfuncp, argvec + 1);
#endif
}
/* We know that arg1 is a structure, so try to find a unary user
defined operator that matches the operator in question.
Create an argument vector that calls arg1.operator @ (arg1)
and return that value (where '@' is (almost) any unary operator which
is legal for GNU C++). */
value
value_x_unop (arg1, op)
value arg1;
enum exp_opcode op;
{
value * argvec;
char *ptr;
char tstr[13];
int static_memfuncp;
COERCE_ENUM (arg1);
/* now we know that what we have to do is construct our
arg vector and find the right function to call it with. */
if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT)
error ("Can't do that unary op on that type"); /* FIXME be explicit */
argvec = (value *) alloca (sizeof (value) * 3);
argvec[1] = value_addr (arg1);
argvec[2] = 0;
/* make the right function name up */
strcpy(tstr,"operator__");
ptr = tstr+8;
switch (op)
{
case UNOP_PREINCREMENT: strcpy(ptr,"++"); break;
case UNOP_PREDECREMENT: strcpy(ptr,"++"); break;
case UNOP_POSTINCREMENT: strcpy(ptr,"++"); break;
case UNOP_POSTDECREMENT: strcpy(ptr,"++"); break;
case UNOP_ZEROP: strcpy(ptr,"!"); break;
case UNOP_LOGNOT: strcpy(ptr,"~"); break;
case UNOP_NEG: strcpy(ptr,"-"); break;
default:
error ("Invalid binary operation specified.");
}
argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure");
if (argvec[0])
{
if (static_memfuncp)
{
argvec[1] = argvec[0];
argvec++;
}
return target_call_function (argvec[0], 1 - static_memfuncp, argvec + 1);
}
error ("member function %s not found", tstr);
return 0; /* For lint -- never reached */
}
/* Perform a binary operation on two integers or two floats.
Does not support addition and subtraction on pointers;
use value_add or value_sub if you want to handle those possibilities. */
value
value_binop (arg1, arg2, op)
value arg1, arg2;
int op;
{
register value val;
COERCE_ENUM (arg1);
COERCE_ENUM (arg2);
if ((TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_FLT
&&
TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT)
||
(TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_FLT
&&
TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT))
error ("Argument to arithmetic operation not a number.");
if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT
||
TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_FLT)
{
double v1, v2, v;
v1 = value_as_double (arg1);
v2 = value_as_double (arg2);
switch (op)
{
case BINOP_ADD:
v = v1 + v2;
break;
case BINOP_SUB:
v = v1 - v2;
break;
case BINOP_MUL:
v = v1 * v2;
break;
case BINOP_DIV:
v = v1 / v2;
break;
default:
error ("Integer-only operation on floating point number.");
}
val = allocate_value (builtin_type_double);
SWAP_TARGET_AND_HOST (&v, sizeof (v));
*(double *) VALUE_CONTENTS_RAW (val) = v;
}
else
/* Integral operations here. */
{
/* Should we promote to unsigned longest? */
if ((TYPE_UNSIGNED (VALUE_TYPE (arg1))
|| TYPE_UNSIGNED (VALUE_TYPE (arg2)))
&& (TYPE_LENGTH (VALUE_TYPE (arg1)) >= sizeof (unsigned LONGEST)
|| TYPE_LENGTH (VALUE_TYPE (arg1)) >= sizeof (unsigned LONGEST)))
{
unsigned LONGEST v1, v2, v;
v1 = (unsigned LONGEST) value_as_long (arg1);
v2 = (unsigned LONGEST) value_as_long (arg2);
switch (op)
{
case BINOP_ADD:
v = v1 + v2;
break;
case BINOP_SUB:
v = v1 - v2;
break;
case BINOP_MUL:
v = v1 * v2;
break;
case BINOP_DIV:
v = v1 / v2;
break;
case BINOP_REM:
v = v1 % v2;
break;
case BINOP_LSH:
v = v1 << v2;
break;
case BINOP_RSH:
v = v1 >> v2;
break;
case BINOP_LOGAND:
v = v1 & v2;
break;
case BINOP_LOGIOR:
v = v1 | v2;
break;
case BINOP_LOGXOR:
v = v1 ^ v2;
break;
case BINOP_AND:
v = v1 && v2;
break;
case BINOP_OR:
v = v1 || v2;
break;
case BINOP_MIN:
v = v1 < v2 ? v1 : v2;
break;
case BINOP_MAX:
v = v1 > v2 ? v1 : v2;
break;
default:
error ("Invalid binary operation on numbers.");
}
val = allocate_value (BUILTIN_TYPE_UNSIGNED_LONGEST);
SWAP_TARGET_AND_HOST (&v, sizeof (v));
*(unsigned LONGEST *) VALUE_CONTENTS_RAW (val) = v;
}
else
{
LONGEST v1, v2, v;
v1 = value_as_long (arg1);
v2 = value_as_long (arg2);
switch (op)
{
case BINOP_ADD:
v = v1 + v2;
break;
case BINOP_SUB:
v = v1 - v2;
break;
case BINOP_MUL:
v = v1 * v2;
break;
case BINOP_DIV:
v = v1 / v2;
break;
case BINOP_REM:
v = v1 % v2;
break;
case BINOP_LSH:
v = v1 << v2;
break;
case BINOP_RSH:
v = v1 >> v2;
break;
case BINOP_LOGAND:
v = v1 & v2;
break;
case BINOP_LOGIOR:
v = v1 | v2;
break;
case BINOP_LOGXOR:
v = v1 ^ v2;
break;
case BINOP_AND:
v = v1 && v2;
break;
case BINOP_OR:
v = v1 || v2;
break;
case BINOP_MIN:
v = v1 < v2 ? v1 : v2;
break;
case BINOP_MAX:
v = v1 > v2 ? v1 : v2;
break;
default:
error ("Invalid binary operation on numbers.");
}
val = allocate_value (BUILTIN_TYPE_LONGEST);
SWAP_TARGET_AND_HOST (&v, sizeof (v));
*(LONGEST *) VALUE_CONTENTS_RAW (val) = v;
}
}
return val;
}
/* Simulate the C operator ! -- return 1 if ARG1 contains zeros. */
int
value_zerop (arg1)
value arg1;
{
register int len;
register char *p;
COERCE_ARRAY (arg1);
len = TYPE_LENGTH (VALUE_TYPE (arg1));
p = VALUE_CONTENTS (arg1);
while (--len >= 0)
{
if (*p++)
break;
}
return len < 0;
}
/* Simulate the C operator == by returning a 1
iff ARG1 and ARG2 have equal contents. */
int
value_equal (arg1, arg2)
register value arg1, arg2;
{
register int len;
register char *p1, *p2;
enum type_code code1;
enum type_code code2;
COERCE_ARRAY (arg1);
COERCE_ARRAY (arg2);
code1 = TYPE_CODE (VALUE_TYPE (arg1));
code2 = TYPE_CODE (VALUE_TYPE (arg2));
if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT)
return value_as_long (arg1) == value_as_long (arg2);
else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT)
&& (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT))
return value_as_double (arg1) == value_as_double (arg2);
else if ((code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT)
|| (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT))
return (char *) value_as_long (arg1) == (char *) value_as_long (arg2);
else if (code1 == code2
&& ((len = TYPE_LENGTH (VALUE_TYPE (arg1)))
== TYPE_LENGTH (VALUE_TYPE (arg2))))
{
p1 = VALUE_CONTENTS (arg1);
p2 = VALUE_CONTENTS (arg2);
while (--len >= 0)
{
if (*p1++ != *p2++)
break;
}
return len < 0;
}
else
{
error ("Invalid type combination in equality test.");
return 0; /* For lint -- never reached */
}
}
/* Simulate the C operator < by returning 1
iff ARG1's contents are less than ARG2's. */
int
value_less (arg1, arg2)
register value arg1, arg2;
{
register enum type_code code1;
register enum type_code code2;
COERCE_ARRAY (arg1);
COERCE_ARRAY (arg2);
code1 = TYPE_CODE (VALUE_TYPE (arg1));
code2 = TYPE_CODE (VALUE_TYPE (arg2));
if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT)
{
if (TYPE_UNSIGNED (VALUE_TYPE (arg1))
|| TYPE_UNSIGNED (VALUE_TYPE (arg2)))
return (unsigned)value_as_long (arg1) < (unsigned)value_as_long (arg2);
else
return value_as_long (arg1) < value_as_long (arg2);
}
else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT)
&& (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT))
return value_as_double (arg1) < value_as_double (arg2);
else if ((code1 == TYPE_CODE_PTR || code1 == TYPE_CODE_INT)
&& (code2 == TYPE_CODE_PTR || code2 == TYPE_CODE_INT))
{
/* FIXME, this assumes that host and target char *'s are the same! */
return (char *) value_as_long (arg1) < (char *) value_as_long (arg2);
}
else
{
error ("Invalid type combination in ordering comparison.");
return 0;
}
}
/* The unary operators - and ~. Both free the argument ARG1. */
value
value_neg (arg1)
register value arg1;
{
register struct type *type;
COERCE_ENUM (arg1);
type = VALUE_TYPE (arg1);
if (TYPE_CODE (type) == TYPE_CODE_FLT)
return value_from_double (type, - value_as_double (arg1));
else if (TYPE_CODE (type) == TYPE_CODE_INT)
return value_from_long (type, - value_as_long (arg1));
else {
error ("Argument to negate operation not a number.");
return 0; /* For lint -- never reached */
}
}
value
value_lognot (arg1)
register value arg1;
{
COERCE_ENUM (arg1);
if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT)
error ("Argument to complement operation not an integer.");
return value_from_long (VALUE_TYPE (arg1), ~ value_as_long (arg1));
}

1478
gdb/valops.c Normal file

File diff suppressed because it is too large Load diff

1915
gdb/valprint.c Normal file

File diff suppressed because it is too large Load diff

289
gdb/value.h Normal file
View file

@ -0,0 +1,289 @@
/* Definitions for values of C expressions, for GDB.
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (VALUE_H)
#define VALUE_H 1
/*
* The structure which defines the type of a value. It should never
* be possible for a program lval value to survive over a call to the inferior
* (ie to be put into the history list or an internal variable).
*/
enum lval_type {
/* Not an lval. */
not_lval,
/* In memory. Could be a saved register. */
lval_memory,
/* In a register. */
lval_register,
/* In a gdb internal variable. */
lval_internalvar,
/* Part of a gdb internal variable (structure field). */
lval_internalvar_component,
/* In a register series in a frame not the current one, which may have been
partially saved or saved in different places (otherwise would be
lval_register or lval_memory). */
lval_reg_frame_relative,
};
struct value
{
/* Type of value; either not an lval, or one of the various
different possible kinds of lval. */
enum lval_type lval;
/* Location of value (if lval). */
union
{
/* Address in inferior or byte of registers structure. */
CORE_ADDR address;
/* Pointer to interrnal variable. */
struct internalvar *internalvar;
/* Number of register. Only used with
lval_reg_frame_relative. */
int regnum;
} location;
/* Describes offset of a value within lval a structure in bytes. */
int offset;
/* Only used for bitfields; number of bits contained in them. */
int bitsize;
/* Only used for bitfields; position of start of field. */
int bitpos;
/* Frame value is relative to. In practice, this address is only
used if the value is stored in several registers in other than
the current frame, and these registers have not all been saved
at the same place in memory. This will be described in the
lval enum above as "lval_reg_frame_relative". */
CORE_ADDR frame_addr;
/* Type of the value. */
struct type *type;
/* Values are stored in a chain, so that they can be deleted
easily over calls to the inferior. Values assigned to internal
variables or put into the value history are taken off this
list. */
struct value *next;
/* If an lval is forced to repeat, a new value is created with
these fields set. The new value is not an lval. */
short repeated;
short repetitions;
/* Register number if the value is from a register. Is not kept
if you take a field of a structure that is stored in a
register. Shouldn't it be? */
short regno;
/* If zero, contents of this value are in the contents field.
If nonzero, contents are in inferior memory at address
in the location.address field plus the offset field
(and the lval field should be lval_memory). */
char lazy;
/* If nonzero, this is the value of a variable which does not
actually exist in the program. */
char optimized_out;
/* Actual contents of the value. For use of this value; setting
it uses the stuff above. Not valid if lazy is nonzero.
Target byte-order. We force it to be aligned properly for any
possible value. */
union {
long contents[1];
double force_double_align;
#ifdef LONG_LONG
long long force_longlong_align;
#endif
} aligner;
};
typedef struct value *value;
#define VALUE_TYPE(val) (val)->type
#define VALUE_LAZY(val) (val)->lazy
/* VALUE_CONTENTS and VALUE_CONTENTS_RAW both return the address of
the gdb buffer used to hold a copy of the contents of the lval.
VALUE_CONTENTS is used when the contents of the buffer are needed --
it uses value_fetch_lazy() to load the buffer from the process being
debugged if it hasn't already been loaded. VALUE_CONTENTS_RAW is
used when data is being stored into the buffer, or when it is
certain that the contents of the buffer are valid. */
#define VALUE_CONTENTS_RAW(val) ((char *) (val)->aligner.contents)
#define VALUE_CONTENTS(val) ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)),\
VALUE_CONTENTS_RAW(val))
extern int value_fetch_lazy ();
#define VALUE_LVAL(val) (val)->lval
#define VALUE_ADDRESS(val) (val)->location.address
#define VALUE_INTERNALVAR(val) (val)->location.internalvar
#define VALUE_FRAME_REGNUM(val) ((val)->location.regnum)
#define VALUE_FRAME(val) ((val)->frame_addr)
#define VALUE_OFFSET(val) (val)->offset
#define VALUE_BITSIZE(val) (val)->bitsize
#define VALUE_BITPOS(val) (val)->bitpos
#define VALUE_NEXT(val) (val)->next
#define VALUE_REPEATED(val) (val)->repeated
#define VALUE_REPETITIONS(val) (val)->repetitions
#define VALUE_REGNO(val) (val)->regno
#define VALUE_OPTIMIZED_OUT(val) ((val)->optimized_out)
/* Convert a REF to the object referenced. */
#define COERCE_REF(arg) \
{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF) \
arg = value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg)), \
unpack_long (VALUE_TYPE (arg), \
VALUE_CONTENTS (arg)));}
/* If ARG is an array, convert it to a pointer.
If ARG is an enum, convert it to an integer.
If ARG is a function, convert it to a function pointer.
References are dereferenced. */
#define COERCE_ARRAY(arg) \
{ COERCE_REF(arg); \
if (VALUE_REPEATED (arg) \
|| TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) \
arg = value_coerce_array (arg); \
if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC) \
arg = value_coerce_function (arg); \
if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \
arg = value_cast (builtin_type_unsigned_int, arg); \
}
/* If ARG is an enum, convert it to an integer. */
#define COERCE_ENUM(arg) \
{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF) \
arg = value_ind (arg); \
if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \
arg = value_cast (builtin_type_unsigned_int, arg); \
}
/* Internal variables (variables for convenience of use of debugger)
are recorded as a chain of these structures. */
struct internalvar
{
struct internalvar *next;
char *name;
value value;
};
#include "symtab.h"
LONGEST value_as_long ();
double value_as_double ();
LONGEST unpack_long ();
double unpack_double ();
long unpack_field_as_long ();
value value_from_long ();
value value_from_double ();
value value_at ();
value value_at_lazy ();
value value_from_register ();
value value_of_variable ();
value value_of_register ();
value read_var_value ();
value locate_var_value ();
value allocate_value ();
value allocate_repeat_value ();
value value_string ();
value value_binop ();
value value_add ();
value value_sub ();
value value_coerce_array ();
value value_coerce_function ();
value value_ind ();
value value_addr ();
value value_assign ();
value value_neg ();
value value_lognot ();
value value_struct_elt (), value_struct_elt_for_address ();
value value_field (), value_primitive_field ();
value value_cast ();
value value_zero ();
value value_repeat ();
value value_subscript ();
value value_being_returned ();
int using_struct_return ();
void set_return_value ();
value evaluate_expression ();
value evaluate_type ();
value parse_and_eval ();
value parse_to_comma_and_eval ();
extern CORE_ADDR parse_and_eval_address ();
extern CORE_ADDR parse_and_eval_address_1 ();
value access_value_history ();
value value_of_internalvar ();
void set_internalvar ();
void set_internalvar_component ();
struct internalvar *lookup_internalvar ();
int value_equal ();
int value_less ();
int value_zerop ();
/* C++ */
value value_of_this ();
value value_static_field ();
value value_x_binop ();
value value_x_unop ();
value value_fn_field ();
value value_virtual_fn_field ();
value value_static_field ();
int binop_user_defined_p ();
int unop_user_defined_p ();
int typecmp ();
int fill_in_vptr_fieldno ();
int destructor_name_p ();
#define value_free(val) free (val)
void free_all_values ();
void release_value ();
int record_latest_value ();
void registers_changed ();
void read_register_bytes ();
void write_register_bytes ();
void read_register_gen ();
CORE_ADDR read_register ();
void write_register ();
void supply_register ();
void get_saved_register ();
void modify_field ();
void type_print ();
void type_print_1 ();
/* Possibilities for prettyprint parameters to routines which print
things. */
enum val_prettyprint {
Val_no_prettyprint = 0,
Val_prettyprint,
/* Use the default setting which the user has specified. */
Val_pretty_default
};
char *baseclass_addr ();
void print_floating ();
int value_print ();
int val_print ();
void print_variable_value ();
char *internalvar_name ();
void clear_value_history ();
void clear_internalvars ();
#endif /* value.h not already included. */

249
readline/COPYING Normal file
View file

@ -0,0 +1,249 @@
GNU GENERAL PUBLIC LICENSE
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The license agreements of most software companies try to keep users
at the mercy of those companies. By contrast, our General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. The
General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it.
You can use it for your programs, too.
When we speak of free software, we are referring to freedom, not
price. Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of a such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must tell them their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work based
on the Program" means either the Program or any work containing the
Program or a portion of it, either verbatim or with modifications. Each
licensee is addressed as "you".
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this
General Public License and to the absence of any warranty; and give any
other recipients of the Program a copy of this General Public License
along with the Program. You may charge a fee for the physical act of
transferring a copy.
2. You may modify your copy or copies of the Program 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 the Program or any part thereof, either
with or without modifications, to be licensed at no charge to all
third parties under the terms of this General Public License (except
that you may choose to grant warranty protection to some or all
third parties, at your option).
c) If the modified program normally reads commands interactively when
run, you must cause it, when started running for such interactive use
in the simplest and most usual way, to print or display an
announcement including an appropriate copyright notice and a notice
that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these
conditions, and telling the user how to view a copy of this General
Public License.
d) You may charge a 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 independent work with the Program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other work under the scope of these terms.
3. You may copy and distribute the 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 charge
for the cost of distribution) 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.)
Source code for a work means the preferred form of the work for making
modifications to it. 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, or for standard header files or definitions files that
accompany that operating system.
4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
the Program is void, and will automatically terminate your rights to use
the Program under this License. However, parties who have received
copies, or rights to use copies, from you under this General Public
License will not have their licenses terminated so long as such parties
remain in full compliance.
5. By copying, distributing or modifying the Program (or any work based
on the Program) you indicate your acceptance of this license to do so,
and all its terms and conditions.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these
terms and conditions. You may not impose any further restrictions on the
recipients' exercise of the rights granted herein.
7. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of the license which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
the license, you may choose any version ever published by the Free Software
Foundation.
8. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision 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 generally.
NO WARRANTY
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE 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.
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19xx name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
program `Gnomovision' (a program to direct compilers to make passes
at assemblers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
That's all there is to it!

103
readline/Makefile.in Normal file
View file

@ -0,0 +1,103 @@
## -*- text -*- ####################################################
# #
# Makefile for readline and history libraries. #
# #
####################################################################
# Here is a rule for making .o files from .c files that doesn't force
# the type of the machine (like -sun3) into the flags.
.c.o:
$(CC) -c $(CFLAGS) $(LOCAL_INCLUDES) $(CPPFLAGS) $(READLINE_DEFINES) $<
# Destination installation directory. The libraries are copied to DESTDIR
# when you do a `make install', and the header files to INCDIR/readline/*.h.
DESTDIR = /usr/local/lib
INCDIR = /usr/local/include
# Define TYPES as -DVOID_SIGHANDLER if your operating system uses
# a return type of "void" for signal handlers.
TYPES = -DVOID_SIGHANDLER
# Define SYSV as -DSYSV if you are using a System V operating system.
#SYSV = -DSYSV
# HP-UX compilation requires the BSD library.
#LOCAL_LIBS = -lBSD
# Xenix compilation requires -ldir -lx
#LOCAL_LIBS = -ldir -lx
# Comment out "-DVI_MODE" if you don't think that anyone will ever desire
# the vi line editing mode and features.
READLINE_DEFINES = $(TYPES) -DVI_MODE
DEBUG_FLAGS = -g
LDFLAGS = $(DEBUG_FLAGS)
CFLAGS = $(DEBUG_FLAGS) $(SYSV) -I.
# A good alternative is gcc -traditional.
#CC = gcc -traditional
CC = cc
RANLIB = /usr/bin/ranlib
AR = ar
RM = rm
CP = cp
LOCAL_INCLUDES = -I../
CSOURCES = readline.c history.c funmap.c keymaps.c vi_mode.c \
emacs_keymap.c vi_keymap.c
HSOURCES = readline.h chardefs.h history.h keymaps.h
SOURCES = $(CSOURCES) $(HSOURCES)
DOCUMENTATION = readline.texinfo inc-readline.texinfo \
history.texinfo inc-history.texinfo
SUPPORT = COPYING Makefile $(DOCUMENTATION) ChangeLog
THINGS_TO_TAR = $(SOURCES) $(SUPPORT)
##########################################################################
all: libreadline.a
libreadline.a: readline.o history.o funmap.o keymaps.o
$(RM) -f libreadline.a
$(AR) clq libreadline.a readline.o history.o funmap.o keymaps.o
-if [ -f $(RANLIB) ]; then $(RANLIB) libreadline.a; fi
readline.o: readline.h chardefs.h keymaps.h history.h readline.c vi_mode.c
history.o: history.c history.h
funmap.o: readline.h
keymaps.o: emacs_keymap.c vi_keymap.c keymaps.h chardefs.h keymaps.c
libtest: libreadline.a libtest.c
$(CC) -o libtest $(CFLAGS) $(CPPFLAGS) -L. libtest.c -lreadline -ltermcap
readline: readline.c history.o keymaps.o funmap.o readline.h chardefs.h
$(CC) $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
$(LOCAL_INCLUDES) -DTEST -o readline readline.c funmap.o \
keymaps.o history.o -L. -ltermcap
readline.tar: $(THINGS_TO_TAR)
tar -cf readline.tar $(THINGS_TO_TAR)
readline.tar.Z: readline.tar
compress -f readline.tar
install: $(DESTDIR)/libreadline.a includes
includes:
if [ ! -r $(INCDIR)/readline ]; then\
mkdir $(INCDIR)/readline;\
chmod a+r $(INCDIR)/readline;\
fi
$(CP) readline.h keymaps.h chardefs.h $(INCDIR)/readline/
clean:
rm -f *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc
$(DESTDIR)/libreadline.a: libreadline.a
-mv $(DESTDIR)/libreadline.a $(DESTDIR)/libreadline.old
cp libreadline.a $(DESTDIR)/libreadline.a
$(RANLIB) -t $(DESTDIR)/libreadline.a

50
readline/chardefs.h Normal file
View file

@ -0,0 +1,50 @@
/* chardefs.h -- Character definitions for readline. */
#ifndef _CHARDEFS_
#ifndef savestring
#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
#endif
#ifndef whitespace
#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
#endif
#ifdef CTRL
#undef CTRL
#endif
/* Some character stuff. */
#define control_character_threshold 0x020 /* smaller than this is control */
#define meta_character_threshold 0x07f /* larger than this is Meta. */
#define control_character_bit 0x40 /* 0x000000, must be off. */
#define meta_character_bit 0x080 /* x0000000, must be on. */
#define CTRL(c) ((c) & (~control_character_bit))
#define META(c) ((c) | meta_character_bit)
#define UNMETA(c) ((c) & (~meta_character_bit))
#define UNCTRL(c) to_upper(((c)|control_character_bit))
#define lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1)))
#define uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1)))
#define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c))
#ifndef to_upper
#define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c))
#define to_lower(c) (uppercase_p(c) ? ((c) + 32) : (c))
#endif
#define CTRL_P(c) ((c) < control_character_threshold)
#define META_P(c) ((c) > meta_character_threshold)
#define NEWLINE '\n'
#define RETURN CTRL('M')
#define RUBOUT 0x07f
#define TAB '\t'
#define ABORT_CHAR CTRL('G')
#define PAGE CTRL('L')
#define SPACE 0x020
#define ESC CTRL('[')
#endif /* _CHARDEFS_ */

472
readline/emacs_keymap.c Normal file
View file

@ -0,0 +1,472 @@
/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */
/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
This file is part of GNU Readline, a library for reading lines
of text with interactive input and history editing.
Readline is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any
later version.
Readline is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with Readline; see the file COPYING. If not, write to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef BUFSIZ
#include <stdio.h>
#endif /* BUFSIZ */
#include "readline.h"
/* An array of function pointers, one for each possible key.
If the type byte is ISKMAP, then the pointer is the address of
a keymap. */
KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
/* Control keys. */
{ ISFUNC, (Function *)0x0 }, /* Control-@ */
{ ISFUNC, rl_beg_of_line }, /* Control-a */
{ ISFUNC, rl_backward }, /* Control-b */
{ ISFUNC, (Function *)0x0 }, /* Control-c */
{ ISFUNC, rl_delete }, /* Control-d */
{ ISFUNC, rl_end_of_line }, /* Control-e */
{ ISFUNC, rl_forward }, /* Control-f */
{ ISFUNC, rl_abort }, /* Control-g */
{ ISFUNC, rl_backward }, /* Control-h */
{ ISFUNC, rl_complete }, /* Control-i */
{ ISFUNC, rl_newline }, /* Control-j */
{ ISFUNC, rl_kill_line }, /* Control-k */
{ ISFUNC, rl_clear_screen }, /* Control-l */
{ ISFUNC, rl_newline }, /* Control-m */
{ ISFUNC, rl_get_next_history }, /* Control-n */
{ ISFUNC, (Function *)0x0 }, /* Control-o */
{ ISFUNC, rl_get_previous_history }, /* Control-p */
{ ISFUNC, rl_quoted_insert }, /* Control-q */
{ ISFUNC, rl_reverse_search_history }, /* Control-r */
{ ISFUNC, rl_forward_search_history }, /* Control-s */
{ ISFUNC, rl_transpose_chars }, /* Control-t */
{ ISFUNC, rl_unix_line_discard }, /* Control-u */
{ ISFUNC, rl_quoted_insert }, /* Control-v */
{ ISFUNC, rl_unix_word_rubout }, /* Control-w */
{ ISKMAP, (Function *)emacs_ctlx_keymap }, /* Control-x */
{ ISFUNC, rl_yank }, /* Control-y */
{ ISFUNC, (Function *)0x0 }, /* Control-z */
{ ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */
{ ISFUNC, (Function *)0x0 }, /* Control-\ */
{ ISFUNC, (Function *)0x0 }, /* Control-] */
{ ISFUNC, (Function *)0x0 }, /* Control-^ */
{ ISFUNC, rl_undo_command }, /* Control-_ */
/* The start of printing characters. */
{ ISFUNC, rl_insert }, /* SPACE */
{ ISFUNC, rl_insert }, /* ! */
{ ISFUNC, rl_insert }, /* " */
{ ISFUNC, rl_insert }, /* # */
{ ISFUNC, rl_insert }, /* $ */
{ ISFUNC, rl_insert }, /* % */
{ ISFUNC, rl_insert }, /* & */
{ ISFUNC, rl_insert }, /* ' */
{ ISFUNC, rl_insert }, /* ( */
{ ISFUNC, rl_insert }, /* ) */
{ ISFUNC, rl_insert }, /* * */
{ ISFUNC, rl_insert }, /* + */
{ ISFUNC, rl_insert }, /* , */
{ ISFUNC, rl_insert }, /* - */
{ ISFUNC, rl_insert }, /* . */
{ ISFUNC, rl_insert }, /* / */
/* Regular digits. */
{ ISFUNC, rl_insert }, /* 0 */
{ ISFUNC, rl_insert }, /* 1 */
{ ISFUNC, rl_insert }, /* 2 */
{ ISFUNC, rl_insert }, /* 3 */
{ ISFUNC, rl_insert }, /* 4 */
{ ISFUNC, rl_insert }, /* 5 */
{ ISFUNC, rl_insert }, /* 6 */
{ ISFUNC, rl_insert }, /* 7 */
{ ISFUNC, rl_insert }, /* 8 */
{ ISFUNC, rl_insert }, /* 9 */
/* A little more punctuation. */
{ ISFUNC, rl_insert }, /* : */
{ ISFUNC, rl_insert }, /* ; */
{ ISFUNC, rl_insert }, /* < */
{ ISFUNC, rl_insert }, /* = */
{ ISFUNC, rl_insert }, /* > */
{ ISFUNC, rl_insert }, /* ? */
{ ISFUNC, rl_insert }, /* @ */
/* Uppercase alphabet. */
{ ISFUNC, rl_insert }, /* A */
{ ISFUNC, rl_insert }, /* B */
{ ISFUNC, rl_insert }, /* C */
{ ISFUNC, rl_insert }, /* D */
{ ISFUNC, rl_insert }, /* E */
{ ISFUNC, rl_insert }, /* F */
{ ISFUNC, rl_insert }, /* G */
{ ISFUNC, rl_insert }, /* H */
{ ISFUNC, rl_insert }, /* I */
{ ISFUNC, rl_insert }, /* J */
{ ISFUNC, rl_insert }, /* K */
{ ISFUNC, rl_insert }, /* L */
{ ISFUNC, rl_insert }, /* M */
{ ISFUNC, rl_insert }, /* N */
{ ISFUNC, rl_insert }, /* O */
{ ISFUNC, rl_insert }, /* P */
{ ISFUNC, rl_insert }, /* Q */
{ ISFUNC, rl_insert }, /* R */
{ ISFUNC, rl_insert }, /* S */
{ ISFUNC, rl_insert }, /* T */
{ ISFUNC, rl_insert }, /* U */
{ ISFUNC, rl_insert }, /* V */
{ ISFUNC, rl_insert }, /* W */
{ ISFUNC, rl_insert }, /* X */
{ ISFUNC, rl_insert }, /* Y */
{ ISFUNC, rl_insert }, /* Z */
/* Some more punctuation. */
{ ISFUNC, rl_insert }, /* [ */
{ ISFUNC, rl_insert }, /* \ */
{ ISFUNC, rl_insert }, /* ] */
{ ISFUNC, rl_insert }, /* ^ */
{ ISFUNC, rl_insert }, /* _ */
{ ISFUNC, rl_insert }, /* ` */
/* Lowercase alphabet. */
{ ISFUNC, rl_insert }, /* a */
{ ISFUNC, rl_insert }, /* b */
{ ISFUNC, rl_insert }, /* c */
{ ISFUNC, rl_insert }, /* d */
{ ISFUNC, rl_insert }, /* e */
{ ISFUNC, rl_insert }, /* f */
{ ISFUNC, rl_insert }, /* g */
{ ISFUNC, rl_insert }, /* h */
{ ISFUNC, rl_insert }, /* i */
{ ISFUNC, rl_insert }, /* j */
{ ISFUNC, rl_insert }, /* k */
{ ISFUNC, rl_insert }, /* l */
{ ISFUNC, rl_insert }, /* m */
{ ISFUNC, rl_insert }, /* n */
{ ISFUNC, rl_insert }, /* o */
{ ISFUNC, rl_insert }, /* p */
{ ISFUNC, rl_insert }, /* q */
{ ISFUNC, rl_insert }, /* r */
{ ISFUNC, rl_insert }, /* s */
{ ISFUNC, rl_insert }, /* t */
{ ISFUNC, rl_insert }, /* u */
{ ISFUNC, rl_insert }, /* v */
{ ISFUNC, rl_insert }, /* w */
{ ISFUNC, rl_insert }, /* x */
{ ISFUNC, rl_insert }, /* y */
{ ISFUNC, rl_insert }, /* z */
/* Final punctuation. */
{ ISFUNC, rl_insert }, /* { */
{ ISFUNC, rl_insert }, /* | */
{ ISFUNC, rl_insert }, /* } */
{ ISFUNC, rl_insert }, /* ~ */
{ ISFUNC, rl_rubout } /* RUBOUT */
};
KEYMAP_ENTRY_ARRAY emacs_meta_keymap = {
/* Meta keys. Just like above, but the high bit is set. */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-a */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-b */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-c */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-d */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-e */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-f */
{ ISFUNC, rl_abort }, /* Meta-Control-g */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-h */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-i */
{ ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-k */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-l */
{ ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-n */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-o */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-p */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-q */
{ ISFUNC, rl_revert_line }, /* Meta-Control-r */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-s */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-t */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-u */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-v */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-w */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-x */
{ ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-z */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-[ */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-] */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */
{ ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */
/* The start of printing characters. */
{ ISFUNC, (Function *)0x0 }, /* Meta-SPACE */
{ ISFUNC, (Function *)0x0 }, /* Meta-! */
{ ISFUNC, (Function *)0x0 }, /* Meta-" */
{ ISFUNC, (Function *)0x0 }, /* Meta-# */
{ ISFUNC, (Function *)0x0 }, /* Meta-$ */
{ ISFUNC, (Function *)0x0 }, /* Meta-% */
{ ISFUNC, (Function *)0x0 }, /* Meta-& */
{ ISFUNC, (Function *)0x0 }, /* Meta-' */
{ ISFUNC, (Function *)0x0 }, /* Meta-( */
{ ISFUNC, (Function *)0x0 }, /* Meta-) */
{ ISFUNC, (Function *)0x0 }, /* Meta-* */
{ ISFUNC, (Function *)0x0 }, /* Meta-+ */
{ ISFUNC, (Function *)0x0 }, /* Meta-, */
{ ISFUNC, rl_digit_argument }, /* Meta-- */
{ ISFUNC, (Function *)0x0 }, /* Meta-. */
{ ISFUNC, (Function *)0x0 }, /* Meta-/ */
/* Regular digits. */
{ ISFUNC, rl_digit_argument }, /* Meta-0 */
{ ISFUNC, rl_digit_argument }, /* Meta-1 */
{ ISFUNC, rl_digit_argument }, /* Meta-2 */
{ ISFUNC, rl_digit_argument }, /* Meta-3 */
{ ISFUNC, rl_digit_argument }, /* Meta-4 */
{ ISFUNC, rl_digit_argument }, /* Meta-5 */
{ ISFUNC, rl_digit_argument }, /* Meta-6 */
{ ISFUNC, rl_digit_argument }, /* Meta-7 */
{ ISFUNC, rl_digit_argument }, /* Meta-8 */
{ ISFUNC, rl_digit_argument }, /* Meta-9 */
/* A little more punctuation. */
{ ISFUNC, (Function *)0x0 }, /* Meta-: */
{ ISFUNC, (Function *)0x0 }, /* Meta-; */
{ ISFUNC, rl_beginning_of_history }, /* Meta-< */
{ ISFUNC, (Function *)0x0 }, /* Meta-= */
{ ISFUNC, rl_end_of_history }, /* Meta-> */
{ ISFUNC, rl_possible_completions }, /* Meta-? */
{ ISFUNC, (Function *)0x0 }, /* Meta-@ */
/* Uppercase alphabet. */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-A */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-B */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-C */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-D */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-E */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-F */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-G */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-H */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-I */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-J */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-K */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-L */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-M */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-N */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-O */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-P */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-Q */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-R */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-S */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-T */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-U */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-V */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-W */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-X */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-Y */
{ ISFUNC, rl_do_lowercase_version }, /* Meta-Z */
/* Some more punctuation. */
{ ISFUNC, (Function *)0x0 }, /* Meta-[ */
{ ISFUNC, (Function *)0x0 }, /* Meta-\ */
{ ISFUNC, (Function *)0x0 }, /* Meta-] */
{ ISFUNC, (Function *)0x0 }, /* Meta-^ */
{ ISFUNC, (Function *)0x0 }, /* Meta-_ */
{ ISFUNC, (Function *)0x0 }, /* Meta-` */
/* Lowercase alphabet. */
{ ISFUNC, (Function *)0x0 }, /* Meta-a */
{ ISFUNC, rl_backward_word }, /* Meta-b */
{ ISFUNC, rl_capitalize_word }, /* Meta-c */
{ ISFUNC, rl_kill_word }, /* Meta-d */
{ ISFUNC, (Function *)0x0 }, /* Meta-e */
{ ISFUNC, rl_forward_word }, /* Meta-f */
{ ISFUNC, (Function *)0x0 }, /* Meta-g */
{ ISFUNC, (Function *)0x0 }, /* Meta-h */
{ ISFUNC, (Function *)0x0 }, /* Meta-i */
{ ISFUNC, (Function *)0x0 }, /* Meta-j */
{ ISFUNC, (Function *)0x0 }, /* Meta-k */
{ ISFUNC, rl_downcase_word }, /* Meta-l */
{ ISFUNC, (Function *)0x0 }, /* Meta-m */
{ ISFUNC, (Function *)0x0 }, /* Meta-n */
{ ISFUNC, (Function *)0x0 }, /* Meta-o */
{ ISFUNC, (Function *)0x0 }, /* Meta-p */
{ ISFUNC, (Function *)0x0 }, /* Meta-q */
{ ISFUNC, rl_revert_line }, /* Meta-r */
{ ISFUNC, (Function *)0x0 }, /* Meta-s */
{ ISFUNC, rl_transpose_words }, /* Meta-t */
{ ISFUNC, rl_upcase_word }, /* Meta-u */
{ ISFUNC, (Function *)0x0 }, /* Meta-v */
{ ISFUNC, (Function *)0x0 }, /* Meta-w */
{ ISFUNC, (Function *)0x0 }, /* Meta-x */
{ ISFUNC, rl_yank_pop }, /* Meta-y */
{ ISFUNC, (Function *)0x0 }, /* Meta-z */
/* Final punctuation. */
{ ISFUNC, (Function *)0x0 }, /* Meta-{ */
{ ISFUNC, (Function *)0x0 }, /* Meta-| */
{ ISFUNC, (Function *)0x0 }, /* Meta-} */
{ ISFUNC, (Function *)0x0 }, /* Meta-~ */
{ ISFUNC, rl_backward_kill_word } /* Meta-rubout */
};
KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = {
/* Control keys. */
{ ISFUNC, (Function *)0x0 }, /* Control-@ */
{ ISFUNC, (Function *)0x0 }, /* Control-a */
{ ISFUNC, (Function *)0x0 }, /* Control-b */
{ ISFUNC, (Function *)0x0 }, /* Control-c */
{ ISFUNC, (Function *)0x0 }, /* Control-d */
{ ISFUNC, (Function *)0x0 }, /* Control-e */
{ ISFUNC, (Function *)0x0 }, /* Control-f */
{ ISFUNC, rl_abort }, /* Control-g */
{ ISFUNC, (Function *)0x0 }, /* Control-h */
{ ISFUNC, (Function *)0x0 }, /* Control-i */
{ ISFUNC, (Function *)0x0 }, /* Control-j */
{ ISFUNC, (Function *)0x0 }, /* Control-k */
{ ISFUNC, (Function *)0x0 }, /* Control-l */
{ ISFUNC, (Function *)0x0 }, /* Control-m */
{ ISFUNC, (Function *)0x0 }, /* Control-n */
{ ISFUNC, (Function *)0x0 }, /* Control-o */
{ ISFUNC, (Function *)0x0 }, /* Control-p */
{ ISFUNC, (Function *)0x0 }, /* Control-q */
{ ISFUNC, rl_re_read_init_file }, /* Control-r */
{ ISFUNC, (Function *)0x0 }, /* Control-s */
{ ISFUNC, (Function *)0x0 }, /* Control-t */
{ ISFUNC, rl_undo_command }, /* Control-u */
{ ISFUNC, (Function *)0x0 }, /* Control-v */
{ ISFUNC, (Function *)0x0 }, /* Control-w */
{ ISFUNC, (Function *)0x0 }, /* Control-x */
{ ISFUNC, (Function *)0x0 }, /* Control-y */
{ ISFUNC, (Function *)0x0 }, /* Control-z */
{ ISFUNC, (Function *)0x0 }, /* Control-[ */
{ ISFUNC, (Function *)0x0 }, /* Control-\ */
{ ISFUNC, (Function *)0x0 }, /* Control-] */
{ ISFUNC, (Function *)0x0 }, /* Control-^ */
{ ISFUNC, (Function *)0x0 }, /* Control-_ */
/* The start of printing characters. */
{ ISFUNC, (Function *)0x0 }, /* SPACE */
{ ISFUNC, (Function *)0x0 }, /* ! */
{ ISFUNC, (Function *)0x0 }, /* " */
{ ISFUNC, (Function *)0x0 }, /* # */
{ ISFUNC, (Function *)0x0 }, /* $ */
{ ISFUNC, (Function *)0x0 }, /* % */
{ ISFUNC, (Function *)0x0 }, /* & */
{ ISFUNC, (Function *)0x0 }, /* ' */
{ ISFUNC, rl_start_kbd_macro }, /* ( */
{ ISFUNC, rl_end_kbd_macro }, /* ) */
{ ISFUNC, (Function *)0x0 }, /* * */
{ ISFUNC, (Function *)0x0 }, /* + */
{ ISFUNC, (Function *)0x0 }, /* , */
{ ISFUNC, (Function *)0x0 }, /* - */
{ ISFUNC, (Function *)0x0 }, /* . */
{ ISFUNC, (Function *)0x0 }, /* / */
/* Regular digits. */
{ ISFUNC, (Function *)0x0 }, /* 0 */
{ ISFUNC, (Function *)0x0 }, /* 1 */
{ ISFUNC, (Function *)0x0 }, /* 2 */
{ ISFUNC, (Function *)0x0 }, /* 3 */
{ ISFUNC, (Function *)0x0 }, /* 4 */
{ ISFUNC, (Function *)0x0 }, /* 5 */
{ ISFUNC, (Function *)0x0 }, /* 6 */
{ ISFUNC, (Function *)0x0 }, /* 7 */
{ ISFUNC, (Function *)0x0 }, /* 8 */
{ ISFUNC, (Function *)0x0 }, /* 9 */
/* A little more punctuation. */
{ ISFUNC, (Function *)0x0 }, /* : */
{ ISFUNC, (Function *)0x0 }, /* ; */
{ ISFUNC, (Function *)0x0 }, /* < */
{ ISFUNC, (Function *)0x0 }, /* = */
{ ISFUNC, (Function *)0x0 }, /* > */
{ ISFUNC, (Function *)0x0 }, /* ? */
{ ISFUNC, (Function *)0x0 }, /* @ */
/* Uppercase alphabet. */
{ ISFUNC, rl_do_lowercase_version }, /* A */
{ ISFUNC, rl_do_lowercase_version }, /* B */
{ ISFUNC, rl_do_lowercase_version }, /* C */
{ ISFUNC, rl_do_lowercase_version }, /* D */
{ ISFUNC, rl_do_lowercase_version }, /* E */
{ ISFUNC, rl_do_lowercase_version }, /* F */
{ ISFUNC, rl_do_lowercase_version }, /* G */
{ ISFUNC, rl_do_lowercase_version }, /* H */
{ ISFUNC, rl_do_lowercase_version }, /* I */
{ ISFUNC, rl_do_lowercase_version }, /* J */
{ ISFUNC, rl_do_lowercase_version }, /* K */
{ ISFUNC, rl_do_lowercase_version }, /* L */
{ ISFUNC, rl_do_lowercase_version }, /* M */
{ ISFUNC, rl_do_lowercase_version }, /* N */
{ ISFUNC, rl_do_lowercase_version }, /* O */
{ ISFUNC, rl_do_lowercase_version }, /* P */
{ ISFUNC, rl_do_lowercase_version }, /* Q */
{ ISFUNC, rl_do_lowercase_version }, /* R */
{ ISFUNC, rl_do_lowercase_version }, /* S */
{ ISFUNC, rl_do_lowercase_version }, /* T */
{ ISFUNC, rl_do_lowercase_version }, /* U */
{ ISFUNC, rl_do_lowercase_version }, /* V */
{ ISFUNC, rl_do_lowercase_version }, /* W */
{ ISFUNC, rl_do_lowercase_version }, /* X */
{ ISFUNC, rl_do_lowercase_version }, /* Y */
{ ISFUNC, rl_do_lowercase_version }, /* Z */
/* Some more punctuation. */
{ ISFUNC, (Function *)0x0 }, /* [ */
{ ISFUNC, (Function *)0x0 }, /* \ */
{ ISFUNC, (Function *)0x0 }, /* ] */
{ ISFUNC, (Function *)0x0 }, /* ^ */
{ ISFUNC, (Function *)0x0 }, /* _ */
{ ISFUNC, (Function *)0x0 }, /* ` */
/* Lowercase alphabet. */
{ ISFUNC, (Function *)0x0 }, /* a */
{ ISFUNC, (Function *)0x0 }, /* b */
{ ISFUNC, (Function *)0x0 }, /* c */
{ ISFUNC, (Function *)0x0 }, /* d */
{ ISFUNC, rl_call_last_kbd_macro }, /* e */
{ ISFUNC, (Function *)0x0 }, /* f */
{ ISFUNC, (Function *)0x0 }, /* g */
{ ISFUNC, (Function *)0x0 }, /* h */
{ ISFUNC, (Function *)0x0 }, /* i */
{ ISFUNC, (Function *)0x0 }, /* j */
{ ISFUNC, (Function *)0x0 }, /* k */
{ ISFUNC, (Function *)0x0 }, /* l */
{ ISFUNC, (Function *)0x0 }, /* m */
{ ISFUNC, (Function *)0x0 }, /* n */
{ ISFUNC, (Function *)0x0 }, /* o */
{ ISFUNC, (Function *)0x0 }, /* p */
{ ISFUNC, (Function *)0x0 }, /* q */
{ ISFUNC, (Function *)0x0 }, /* r */
{ ISFUNC, (Function *)0x0 }, /* s */
{ ISFUNC, (Function *)0x0 }, /* t */
{ ISFUNC, (Function *)0x0 }, /* u */
{ ISFUNC, (Function *)0x0 }, /* v */
{ ISFUNC, (Function *)0x0 }, /* w */
{ ISFUNC, (Function *)0x0 }, /* x */
{ ISFUNC, (Function *)0x0 }, /* y */
{ ISFUNC, (Function *)0x0 }, /* z */
/* Final punctuation. */
{ ISFUNC, (Function *)0x0 }, /* { */
{ ISFUNC, (Function *)0x0 }, /* | */
{ ISFUNC, (Function *)0x0 }, /* } */
{ ISFUNC, (Function *)0x0 }, /* ~ */
{ ISFUNC, rl_backward_kill_line } /* RUBOUT */
};

212
readline/funmap.c Normal file
View file

@ -0,0 +1,212 @@
/* funmap.c -- attach names to functions. */
/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
This file is part of GNU Readline, a library for reading lines
of text with interactive input and history editing.
Readline is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any
later version.
Readline is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with Readline; see the file COPYING. If not, write to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define STATIC_MALLOC
#ifndef STATIC_MALLOC
extern char *xmalloc (), *xrealloc ();
#else
static char *xmalloc (), *xrealloc ();
#endif
#ifndef FILE
#include <stdio.h>
#endif /* FILE */
#include "readline.h"
FUNMAP **funmap = (FUNMAP **)NULL;
static int funmap_size = 0;
static int funmap_entry = 0;
static FUNMAP default_funmap[] = {
{ "beginning-of-line", rl_beg_of_line },
{ "backward-char", rl_backward },
{ "delete-char", rl_delete },
{ "end-of-line", rl_end_of_line },
{ "forward-char", rl_forward },
{ "accept-line", rl_newline },
{ "kill-line", rl_kill_line },
{ "clear-screen", rl_clear_screen },
{ "next-history", rl_get_next_history },
{ "previous-history", rl_get_previous_history },
{ "quoted-insert", rl_quoted_insert },
{ "reverse-search-history", rl_reverse_search_history },
{ "forward-search-history", rl_forward_search_history },
{ "transpose-chars", rl_transpose_chars },
{ "unix-line-discard", rl_unix_line_discard },
{ "unix-word-rubout", rl_unix_word_rubout },
{ "yank", rl_yank },
{ "yank-pop", rl_yank_pop },
{ "yank-nth-arg", rl_yank_nth_arg },
{ "backward-delete-char", rl_rubout },
{ "backward-word", rl_backward_word },
{ "kill-word", rl_kill_word },
{ "forward-word", rl_forward_word },
{ "tab-insert", rl_tab_insert },
{ "backward-kill-word", rl_backward_kill_word },
{ "backward-kill-line", rl_backward_kill_line },
{ "transpose-words", rl_transpose_words },
{ "digit-argument", rl_digit_argument },
{ "complete", rl_complete },
{ "possible-completions", rl_possible_completions },
{ "do-lowercase-version", rl_do_lowercase_version },
{ "digit-argument", rl_digit_argument },
{ "universal-argument", rl_universal_argument },
{ "abort", rl_abort },
{ "undo", rl_undo_command },
{ "upcase-word", rl_upcase_word },
{ "downcase-word", rl_downcase_word },
{ "capitalize-word", rl_capitalize_word },
{ "revert-line", rl_revert_line },
{ "beginning-of-history", rl_beginning_of_history },
{ "end-of-history", rl_end_of_history },
{ "self-insert", rl_insert },
{ "start-kbd-macro", rl_start_kbd_macro },
{ "end-kbd-macro", rl_end_kbd_macro },
{ "re-read-init-file", rl_re_read_init_file },
#ifdef VI_MODE
{ "vi-movement-mode", rl_vi_movement_mode },
{ "vi-insertion-mode", rl_vi_insertion_mode },
{ "vi-arg-digit", rl_vi_arg_digit },
{ "vi-prev-word", rl_vi_prev_word },
{ "vi-next-word", rl_vi_next_word },
{ "vi-char-search", rl_vi_char_search },
{ "vi-editing-mode", rl_vi_editing_mode },
{ "vi-eof-maybe", rl_vi_eof_maybe },
{ "vi-append-mode", rl_vi_append_mode },
{ "vi-put", rl_vi_put },
{ "vi-append-eol", rl_vi_append_eol },
{ "vi-insert-beg", rl_vi_insert_beg },
{ "vi-delete", rl_vi_delete },
{ "vi-comment", rl_vi_comment },
{ "vi-first-print", rl_vi_first_print },
{ "vi-fword", rl_vi_fword },
{ "vi-fWord", rl_vi_fWord },
{ "vi-bword", rl_vi_bword },
{ "vi-bWord", rl_vi_bWord },
{ "vi-eword", rl_vi_eword },
{ "vi-eWord", rl_vi_eWord },
{ "vi-end-word", rl_vi_end_word },
{ "vi-change-case", rl_vi_change_case },
{ "vi-match", rl_vi_match },
{ "vi-bracktype", rl_vi_bracktype },
{ "vi-change-char", rl_vi_change_char },
{ "vi-yank-arg", rl_vi_yank_arg },
{ "vi-search", rl_vi_search },
{ "vi-search-again", rl_vi_search_again },
{ "vi-dosearch", rl_vi_dosearch },
{ "vi-subst", rl_vi_subst },
{ "vi-overstrike", rl_vi_overstrike },
{ "vi-overstrike-delete", rl_vi_overstrike_delete },
{ "vi-replace, ", rl_vi_replace },
{ "vi-column", rl_vi_column },
{ "vi-delete-to", rl_vi_delete_to },
{ "vi-change-to", rl_vi_change_to },
{ "vi-yank-to", rl_vi_yank_to },
{ "vi-complete", rl_vi_complete },
#endif /* VI_MODE */
{(char *)NULL, (Function *)NULL }
};
rl_add_funmap_entry (name, function)
char *name;
Function *function;
{
if (funmap_entry + 2 >= funmap_size)
if (!funmap)
funmap = (FUNMAP **)xmalloc ((funmap_size = 80) * sizeof (FUNMAP *));
else
funmap =
(FUNMAP **)xrealloc (funmap, (funmap_size += 80) * sizeof (FUNMAP *));
funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP));
funmap[funmap_entry]->name = name;
funmap[funmap_entry]->function = function;
funmap[++funmap_entry] = (FUNMAP *)NULL;
}
static int funmap_initialized = 0;
/* Make the funmap contain all of the default entries. */
rl_initialize_funmap ()
{
register int i;
if (funmap_initialized)
return;
for (i = 0; default_funmap[i].name; i++)
rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function);
funmap_initialized = 1;
}
/* Things that mean `Control'. */
char *possible_control_prefixes[] = {
"Control-", "C-", "CTRL-", (char *)NULL
};
char *possible_meta_prefixes[] = {
"Meta", "M-", (char *)NULL
};
#ifdef STATIC_MALLOC
/* **************************************************************** */
/* */
/* xmalloc and xrealloc () */
/* */
/* **************************************************************** */
static void memory_error_and_abort ();
static char *
xmalloc (bytes)
int bytes;
{
char *temp = (char *)malloc (bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static char *
xrealloc (pointer, bytes)
char *pointer;
int bytes;
{
char *temp = (char *)realloc (pointer, bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static void
memory_error_and_abort ()
{
fprintf (stderr, "history: Out of virtual memory!\n");
abort ();
}
#endif /* STATIC_MALLOC */

1478
readline/history.c Normal file

File diff suppressed because it is too large Load diff

108
readline/history.h Normal file
View file

@ -0,0 +1,108 @@
/* History.h -- the names of functions that you can call in history. */
typedef struct _hist_entry {
char *line;
char *data;
} HIST_ENTRY;
/* For convenience only. You set this when interpreting history commands.
It is the logical offset of the first history element. */
extern int history_base;
/* Begin a session in which the history functions might be used. This
just initializes the interactive variables. */
extern void using_history ();
/* Place STRING at the end of the history list.
The associated data field (if any) is set to NULL. */
extern void add_history ();
/* Returns the number which says what history element we are now
looking at. */
extern int where_history ();
/* Set the position in the history list to POS. */
int history_set_pos ();
/* Search for STRING in the history list, starting at POS, an
absolute index into the list. DIR, if negative, says to search
backwards from POS, else forwards.
Returns the absolute index of the history element where STRING
was found, or -1 otherwise. */
extern int history_search_pos ();
/* A reasonably useless function, only here for completeness. WHICH
is the magic number that tells us which element to delete. The
elements are numbered from 0. */
extern HIST_ENTRY *remove_history ();
/* Stifle the history list, remembering only MAX number of entries. */
extern void stifle_history ();
/* Stop stifling the history. This returns the previous amount the
history was stifled by. The value is positive if the history was
stifled, negative if it wasn't. */
extern int unstifle_history ();
/* Add the contents of FILENAME to the history list, a line at a time.
If FILENAME is NULL, then read from ~/.history. Returns 0 if
successful, or errno if not. */
extern int read_history ();
/* Append the current history to FILENAME. If FILENAME is NULL,
then append the history list to ~/.history. Values returned
are as in read_history (). */
extern int write_history ();
/* Make the history entry at WHICH have LINE and DATA. This returns
the old entry so you can dispose of the data. In the case of an
invalid WHICH, a NULL pointer is returned. */
extern HIST_ENTRY *replace_history_entry ();
/* Return the history entry at the current position, as determined by
history_offset. If there is no entry there, return a NULL pointer. */
HIST_ENTRY *current_history ();
/* Back up history_offset to the previous history entry, and return
a pointer to that entry. If there is no previous entry, return
a NULL pointer. */
extern HIST_ENTRY *previous_history ();
/* Move history_offset forward to the next item in the input_history,
and return the a pointer to that entry. If there is no next entry,
return a NULL pointer. */
extern HIST_ENTRY *next_history ();
/* Return a NULL terminated array of HIST_ENTRY which is the current input
history. Element 0 of this list is the beginning of time. If there
is no history, return NULL. */
extern HIST_ENTRY **history_list ();
/* Search the history for STRING, starting at history_offset.
If DIRECTION < 0, then the search is through previous entries,
else through subsequent. If the string is found, then
current_history () is the history entry, and the value of this function
is the offset in the line of that history entry that the string was
found in. Otherwise, nothing is changed, and a -1 is returned. */
extern int history_search ();
/* Expand the string STRING, placing the result into OUTPUT, a pointer
to a string. Returns:
0) If no expansions took place (or, if the only change in
the text was the de-slashifying of the history expansion
character)
1) If expansions did take place
-1) If there was an error in expansion.
If an error ocurred in expansion, then OUTPUT contains a descriptive
error message. */
extern int history_expand ();
/* Extract a string segment consisting of the FIRST through LAST
arguments present in STRING. Arguments are broken up as in
the shell. */
extern char *history_arg_extract ();

172
readline/keymaps.c Normal file
View file

@ -0,0 +1,172 @@
/* keymaps.c -- Functions and keymaps for the GNU Readline library. */
/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
This file is part of GNU Readline, a library for reading lines
of text with interactive input and history editing.
Readline is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any
later version.
Readline is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with Readline; see the file COPYING. If not, write to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "keymaps.h"
#include "emacs_keymap.c"
#ifdef VI_MODE
#include "vi_keymap.c"
#endif
/* Remove these declarations when we have a complete libgnu.a. */
#define STATIC_MALLOC
#ifndef STATIC_MALLOC
extern char *xmalloc (), *xrealloc ();
#else
static char *xmalloc (), *xrealloc ();
#endif
/* **************************************************************** */
/* */
/* Functions for manipulating Keymaps. */
/* */
/* **************************************************************** */
/* Return a new, empty keymap.
Free it with free() when you are done. */
Keymap
rl_make_bare_keymap ()
{
register int i;
Keymap keymap = (Keymap)xmalloc (128 * sizeof (KEYMAP_ENTRY));
for (i = 0; i < 128; i++)
{
keymap[i].type = ISFUNC;
keymap[i].function = (Function *)NULL;
}
for (i = 'A'; i < ('Z' + 1); i++)
{
keymap[i].type = ISFUNC;
keymap[i].function = rl_do_lowercase_version;
}
return (keymap);
}
/* Return a new keymap which is a copy of MAP. */
Keymap
rl_copy_keymap (map)
Keymap map;
{
register int i;
Keymap temp = rl_make_bare_keymap ();
for (i = 0; i < 128; i++)
{
temp[i].type = map[i].type;
temp[i].function = map[i].function;
}
return (temp);
}
/* Return a new keymap with the printing characters bound to rl_insert,
the uppercase Meta characters bound to run their lowercase equivalents,
and the Meta digits bound to produce numeric arguments. */
Keymap
rl_make_keymap ()
{
extern rl_insert (), rl_rubout (), rl_do_lowercase_version ();
extern rl_digit_argument ();
register int i;
Keymap newmap;
newmap = rl_make_bare_keymap ();
/* All printing characters are self-inserting. */
for (i = ' '; i < 126; i++)
newmap[i].function = rl_insert;
newmap[TAB].function = rl_insert;
newmap[RUBOUT].function = rl_rubout;
return (newmap);
}
/* Free the storage associated with MAP. */
rl_discard_keymap (map)
Keymap (map);
{
int i;
if (!map)
return;
for (i = 0; i < 128; i++)
{
switch (map[i].type)
{
case ISFUNC:
break;
case ISKMAP:
rl_discard_keymap ((Keymap)map[i].function);
break;
case ISMACR:
free ((char *)map[i].function);
break;
}
}
}
#ifdef STATIC_MALLOC
/* **************************************************************** */
/* */
/* xmalloc and xrealloc () */
/* */
/* **************************************************************** */
static void memory_error_and_abort ();
static char *
xmalloc (bytes)
int bytes;
{
char *temp = (char *)malloc (bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static char *
xrealloc (pointer, bytes)
char *pointer;
int bytes;
{
char *temp = (char *)realloc (pointer, bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static void
memory_error_and_abort ()
{
fprintf (stderr, "readline: Out of virtual memory!\n");
abort ();
}
#endif /* STATIC_MALLOC */

53
readline/keymaps.h Normal file
View file

@ -0,0 +1,53 @@
/* keymaps.h -- Manipulation of readline keymaps. */
#ifndef _KEYMAPS_H_
#define _KEYMAPS_H_
#include <readline/chardefs.h>
#ifndef __FUNCTION_DEF
typedef int Function ();
#define __FUNCTION_DEF
#endif
/* A keymap contains one entry for each key in the ASCII set.
Each entry consists of a type and a pointer.
POINTER is the address of a function to run, or the
address of a keymap to indirect through.
TYPE says which kind of thing POINTER is. */
typedef struct _keymap_entry {
char type;
Function *function;
} KEYMAP_ENTRY;
/* I wanted to make the above structure contain a union of:
union { Function *function; struct _keymap_entry *keymap; } value;
but this made it impossible for me to create a static array.
Maybe I need C lessons. */
typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[128];
typedef KEYMAP_ENTRY *Keymap;
/* The values that TYPE can have in a keymap entry. */
#define ISFUNC 0
#define ISKMAP 1
#define ISMACR 2
extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap;
extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap;
/* Return a new, empty keymap.
Free it with free() when you are done. */
Keymap rl_make_bare_keymap ();
/* Return a new keymap which is a copy of MAP. */
Keymap rl_copy_keymap ();
/* Return a new keymap with the printing characters bound to rl_insert,
the lowercase Meta characters bound to run their equivalents, and
the Meta digits bound to produce numeric arguments. */
Keymap rl_make_keymap ();
#endif /* _KEYMAPS_H_ */

5641
readline/readline.c Normal file

File diff suppressed because it is too large Load diff

170
readline/readline.h Normal file
View file

@ -0,0 +1,170 @@
/* Readline.h -- the names of functions callable from within readline. */
#ifndef _READLINE_H_
#define _READLINE_H_
#include <readline/keymaps.h>
#ifndef __FUNCTION_DEF
typedef int Function ();
#define __FUNCTION_DEF
#endif
/* The functions for manipulating the text of the line within readline.
Most of these functions are bound to keys by default. */
extern int
rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (),
rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (),
rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (),
rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars
(), rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout
(), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (),
rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (),
rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words
(), rl_complete (), rl_possible_completions (), rl_do_lowercase_version
(), rl_digit_argument (), rl_universal_argument (), rl_abort (),
rl_undo_command (), rl_revert_line (), rl_beginning_of_history (),
rl_end_of_history (), rl_forward_search_history (), rl_insert (),
rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (),
rl_restart_output (), rl_re_read_init_file ();
/* These are *both* defined even when VI_MODE is not. */
extern int rl_vi_editing_mode (), rl_emacs_editing_mode ();
#ifdef VI_MODE
/* Things for vi mode. */
extern int rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (),
rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (),
rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (),
rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (),
rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (),
rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (),
rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), rl_vi_change_char (),
rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (),
rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (),
rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (),
rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete ();
#endif /* VI_MODE */
/* Keyboard macro commands. */
extern int
rl_start_kbd_macro (), rl_end_kbd_macro (), rl_call_last_kbd_macro ();
/* Maintaining the state of undo. We remember individual deletes and inserts
on a chain of things to do. */
/* The actions that undo knows how to undo. Notice that UNDO_DELETE means
to insert some text, and UNDO_INSERT means to delete some text. I.e.,
the code tells undo what to undo, not how to undo it. */
enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END };
/* What an element of THE_UNDO_LIST looks like. */
typedef struct undo_list {
struct undo_list *next;
int start, end; /* Where the change took place. */
char *text; /* The text to insert, if undoing a delete. */
enum undo_code what; /* Delete, Insert, Begin, End. */
} UNDO_LIST;
/* The current undo list for RL_LINE_BUFFER. */
extern UNDO_LIST *rl_undo_list;
/* The data structure for mapping textual names to code addresses. */
typedef struct {
char *name;
Function *function;
} FUNMAP;
extern FUNMAP **funmap;
/* **************************************************************** */
/* */
/* Well Published Variables */
/* */
/* **************************************************************** */
/* The name of the calling program. You should initialize this to
whatever was in argv[0]. It is used when parsing conditionals. */
extern char *rl_readline_name;
/* The line buffer that is in use. */
extern char *rl_line_buffer;
/* The location of point, and end. */
extern int rl_point, rl_end;
/* The name of the terminal to use. */
extern char *rl_terminal_name;
/* The input and output streams. */
extern FILE *rl_instream, *rl_outstream;
/* The basic list of characters that signal a break between words for the
completer routine. The contents of this variable is what breaks words
in the shell, i.e. "n\"\\'`@$>". */
extern char *rl_basic_word_break_characters;
/* The list of characters that signal a break between words for
rl_complete_internal. The default list is the contents of
rl_basic_word_break_characters. */
extern char *rl_completer_word_break_characters;
/* List of characters that are word break characters, but should be left
in TEXT when it is passed to the completion function. The shell uses
this to help determine what kind of completing to do. */
extern char *rl_special_prefixes;
/* Pointer to the generator function for completion_matches ().
NULL means to use filename_entry_function (), the default filename
completer. */
extern Function *rl_completion_entry_function;
/* Pointer to alternative function to create matches.
Function is called with TEXT, START, and END.
START and END are indices in RL_LINE_BUFFER saying what the boundaries
of TEXT are.
If this function exists and returns NULL then call the value of
rl_completion_entry_function to try to match, otherwise use the
array of strings returned. */
extern Function *rl_attempted_completion_function;
/* If non-null, this contains the address of a function to call if the
standard meaning for expanding a tilde fails. The function is called
with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
which is the expansion, or a NULL pointer if there is no expansion. */
extern Function *rl_tilde_expander;
/* If non-zero, then this is the address of a function to call just
before readline_internal () prints the first prompt. */
extern Function *rl_startup_hook;
/* If non-zero, then this is the address of a function to call when
completing on a directory name. The function is called with
the address of a string (the current directory name) as an arg. */
extern Function *rl_symbolic_link_hook;
/* Non-zero means that modified history lines are preceded
with an asterisk. */
extern int rl_show_star;
/* **************************************************************** */
/* */
/* Well Published Functions */
/* */
/* **************************************************************** */
/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */
extern char *readline ();
/* Return an array of strings which are the result of repeatadly calling
FUNC with TEXT. */
extern char **completion_matches ();
/* rl_add_defun (char *name, Function *function, int key)
Add NAME to the list of named functions. Make FUNCTION
be the function that gets called.
If KEY is not -1, then bind it. */
extern int rl_add_defun ();
#endif /* _READLINE_H_ */

474
readline/vi_keymap.c Normal file
View file

@ -0,0 +1,474 @@
/* vi_keymap.c -- the keymap for vi_mode in readline (). */
/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
This file is part of GNU Readline, a library for reading lines
of text with interactive input and history editing.
Readline is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any
later version.
Readline is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with Readline; see the file COPYING. If not, write to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef FILE
#include <stdio.h>
#endif /* FILE */
#include "readline.h"
extern KEYMAP_ENTRY_ARRAY vi_escape_keymap;
/* The keymap arrays for handling vi mode. */
KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
/* The regular control keys come first. */
{ ISFUNC, (Function *)0x0 }, /* Control-@ */
{ ISFUNC, (Function *)0x0 }, /* Control-a */
{ ISFUNC, (Function *)0x0 }, /* Control-b */
{ ISFUNC, (Function *)0x0 }, /* Control-c */
{ ISFUNC, rl_vi_eof_maybe }, /* Control-d */
{ ISFUNC, rl_emacs_editing_mode }, /* Control-e */
{ ISFUNC, (Function *)0x0 }, /* Control-f */
{ ISFUNC, rl_abort }, /* Control-g */
{ ISFUNC, rl_backward }, /* Control-h */
{ ISFUNC, (Function *)0x0 }, /* Control-i */
{ ISFUNC, rl_newline }, /* Control-j */
{ ISFUNC, rl_kill_line }, /* Control-k */
{ ISFUNC, rl_clear_screen }, /* Control-l */
{ ISFUNC, rl_newline }, /* Control-m */
{ ISFUNC, rl_get_next_history }, /* Control-n */
{ ISFUNC, (Function *)0x0 }, /* Control-o */
{ ISFUNC, rl_get_previous_history }, /* Control-p */
{ ISFUNC, rl_quoted_insert }, /* Control-q */
{ ISFUNC, rl_reverse_search_history }, /* Control-r */
{ ISFUNC, rl_forward_search_history }, /* Control-s */
{ ISFUNC, rl_transpose_chars }, /* Control-t */
{ ISFUNC, rl_unix_line_discard }, /* Control-u */
{ ISFUNC, rl_quoted_insert }, /* Control-v */
{ ISFUNC, rl_unix_word_rubout }, /* Control-w */
{ ISFUNC, (Function *)0x0 }, /* Control-x */
{ ISFUNC, rl_yank }, /* Control-y */
{ ISFUNC, (Function *)0x0 }, /* Control-z */
{ ISKMAP, (Function *)vi_escape_keymap }, /* Control-[ */
{ ISFUNC, (Function *)0x0 }, /* Control-\ */
{ ISFUNC, (Function *)0x0 }, /* Control-] */
{ ISFUNC, (Function *)0x0 }, /* Control-^ */
{ ISFUNC, rl_undo_command }, /* Control-_ */
/* The start of printing characters. */
{ ISFUNC, rl_forward }, /* SPACE */
{ ISFUNC, (Function *)0x0 }, /* ! */
{ ISFUNC, (Function *)0x0 }, /* " */
{ ISFUNC, rl_vi_comment }, /* # */
{ ISFUNC, rl_end_of_line }, /* $ */
{ ISFUNC, rl_vi_match }, /* % */
{ ISFUNC, (Function *)0x0 }, /* & */
{ ISFUNC, (Function *)0x0 }, /* ' */
{ ISFUNC, (Function *)0x0 }, /* ( */
{ ISFUNC, (Function *)0x0 }, /* ) */
{ ISFUNC, rl_vi_complete }, /* * */
{ ISFUNC, rl_get_next_history}, /* + */
{ ISFUNC, rl_vi_char_search }, /* , */
{ ISFUNC, rl_get_previous_history }, /* - */
{ ISFUNC, (Function *)0x0 }, /* . */
{ ISFUNC, rl_vi_search }, /* / */
/* Regular digits. */
{ ISFUNC, rl_vi_arg_digit }, /* 0 */
{ ISFUNC, rl_vi_arg_digit }, /* 1 */
{ ISFUNC, rl_vi_arg_digit }, /* 2 */
{ ISFUNC, rl_vi_arg_digit }, /* 3 */
{ ISFUNC, rl_vi_arg_digit }, /* 4 */
{ ISFUNC, rl_vi_arg_digit }, /* 5 */
{ ISFUNC, rl_vi_arg_digit }, /* 6 */
{ ISFUNC, rl_vi_arg_digit }, /* 7 */
{ ISFUNC, rl_vi_arg_digit }, /* 8 */
{ ISFUNC, rl_vi_arg_digit }, /* 9 */
/* A little more punctuation. */
{ ISFUNC, (Function *)0x0 }, /* : */
{ ISFUNC, rl_vi_char_search }, /* ; */
{ ISFUNC, (Function *)0x0 }, /* < */
{ ISFUNC, (Function *)0x0 }, /* = */
{ ISFUNC, (Function *)0x0 }, /* > */
{ ISFUNC, rl_vi_search }, /* ? */
{ ISFUNC, (Function *)0x0 }, /* @ */
/* Uppercase alphabet. */
{ ISFUNC, rl_vi_append_eol }, /* A */
{ ISFUNC, rl_vi_prev_word}, /* B */
{ ISFUNC, rl_vi_change_to }, /* C */
{ ISFUNC, rl_vi_delete_to }, /* D */
{ ISFUNC, rl_vi_end_word }, /* E */
{ ISFUNC, rl_vi_char_search }, /* F */
{ ISFUNC, (Function *)0x0 }, /* G */
{ ISFUNC, (Function *)0x0 }, /* H */
{ ISFUNC, rl_vi_insert_beg }, /* I */
{ ISFUNC, (Function *)0x0 }, /* J */
{ ISFUNC, (Function *)0x0 }, /* K */
{ ISFUNC, (Function *)0x0 }, /* L */
{ ISFUNC, (Function *)0x0 }, /* M */
{ ISFUNC, rl_vi_search_again }, /* N */
{ ISFUNC, (Function *)0x0 }, /* O */
{ ISFUNC, rl_vi_put }, /* P */
{ ISFUNC, (Function *)0x0 }, /* Q */
{ ISFUNC, rl_vi_replace }, /* R */
{ ISFUNC, rl_vi_subst }, /* S */
{ ISFUNC, rl_vi_char_search }, /* T */
{ ISFUNC, rl_revert_line }, /* U */
{ ISFUNC, (Function *)0x0 }, /* V */
{ ISFUNC, rl_vi_next_word }, /* W */
{ ISFUNC, rl_rubout }, /* X */
{ ISFUNC, rl_vi_yank_to }, /* Y */
{ ISFUNC, (Function *)0x0 }, /* Z */
/* Some more punctuation. */
{ ISFUNC, (Function *)0x0 }, /* [ */
{ ISFUNC, (Function *)0x0 }, /* \ */
{ ISFUNC, (Function *)0x0 }, /* ] */
{ ISFUNC, rl_vi_first_print }, /* ^ */
{ ISFUNC, rl_vi_yank_arg }, /* _ */
{ ISFUNC, (Function *)0x0 }, /* ` */
/* Lowercase alphabet. */
{ ISFUNC, rl_vi_append_mode }, /* a */
{ ISFUNC, rl_vi_prev_word }, /* b */
{ ISFUNC, rl_vi_change_to }, /* c */
{ ISFUNC, rl_vi_delete_to }, /* d */
{ ISFUNC, rl_vi_end_word }, /* e */
{ ISFUNC, rl_vi_char_search }, /* f */
{ ISFUNC, (Function *)0x0 }, /* g */
{ ISFUNC, rl_backward }, /* h */
{ ISFUNC, rl_vi_insertion_mode }, /* i */
{ ISFUNC, rl_get_next_history }, /* j */
{ ISFUNC, rl_get_previous_history }, /* k */
{ ISFUNC, rl_forward }, /* l */
{ ISFUNC, (Function *)0x0 }, /* m */
{ ISFUNC, rl_vi_search_again }, /* n */
{ ISFUNC, (Function *)0x0 }, /* o */
{ ISFUNC, rl_vi_put }, /* p */
{ ISFUNC, (Function *)0x0 }, /* q */
{ ISFUNC, rl_vi_change_char }, /* r */
{ ISFUNC, rl_vi_subst }, /* s */
{ ISFUNC, rl_vi_char_search }, /* t */
{ ISFUNC, rl_undo_command }, /* u */
{ ISFUNC, (Function *)0x0 }, /* v */
{ ISFUNC, rl_vi_next_word }, /* w */
{ ISFUNC, rl_vi_delete }, /* x */
{ ISFUNC, rl_vi_yank_to }, /* y */
{ ISFUNC, (Function *)0x0 }, /* z */
/* Final punctuation. */
{ ISFUNC, (Function *)0x0 }, /* { */
{ ISFUNC, rl_vi_column }, /* | */
{ ISFUNC, (Function *)0x0 }, /* } */
{ ISFUNC, rl_vi_change_case }, /* ~ */
{ ISFUNC, rl_backward } /* RUBOUT */
};
KEYMAP_ENTRY_ARRAY vi_insertion_keymap = {
/* The regular control keys come first. */
{ ISFUNC, (Function *)0x0 }, /* Control-@ */
{ ISFUNC, rl_insert }, /* Control-a */
{ ISFUNC, rl_insert }, /* Control-b */
{ ISFUNC, rl_insert }, /* Control-c */
{ ISFUNC, rl_vi_eof_maybe }, /* Control-d */
{ ISFUNC, rl_insert }, /* Control-e */
{ ISFUNC, rl_insert }, /* Control-f */
{ ISFUNC, rl_insert }, /* Control-g */
{ ISFUNC, rl_rubout }, /* Control-h */
{ ISFUNC, rl_complete }, /* Control-i */
{ ISFUNC, rl_newline }, /* Control-j */
{ ISFUNC, rl_insert }, /* Control-k */
{ ISFUNC, rl_insert }, /* Control-l */
{ ISFUNC, rl_newline }, /* Control-m */
{ ISFUNC, rl_insert }, /* Control-n */
{ ISFUNC, rl_insert }, /* Control-o */
{ ISFUNC, rl_insert }, /* Control-p */
{ ISFUNC, rl_insert }, /* Control-q */
{ ISFUNC, rl_reverse_search_history }, /* Control-r */
{ ISFUNC, rl_forward_search_history }, /* Control-s */
{ ISFUNC, rl_transpose_chars }, /* Control-t */
{ ISFUNC, rl_unix_line_discard }, /* Control-u */
{ ISFUNC, rl_quoted_insert }, /* Control-v */
{ ISFUNC, rl_unix_word_rubout }, /* Control-w */
{ ISFUNC, rl_insert }, /* Control-x */
{ ISFUNC, rl_yank }, /* Control-y */
{ ISFUNC, rl_insert }, /* Control-z */
{ ISFUNC, rl_vi_movement_mode }, /* Control-[ */
{ ISFUNC, rl_insert }, /* Control-\ */
{ ISFUNC, rl_insert }, /* Control-] */
{ ISFUNC, rl_insert }, /* Control-^ */
{ ISFUNC, rl_undo_command }, /* Control-_ */
/* The start of printing characters. */
{ ISFUNC, rl_insert }, /* SPACE */
{ ISFUNC, rl_insert }, /* ! */
{ ISFUNC, rl_insert }, /* " */
{ ISFUNC, rl_insert }, /* # */
{ ISFUNC, rl_insert }, /* $ */
{ ISFUNC, rl_insert }, /* % */
{ ISFUNC, rl_insert }, /* & */
{ ISFUNC, rl_insert }, /* ' */
{ ISFUNC, rl_insert }, /* ( */
{ ISFUNC, rl_insert }, /* ) */
{ ISFUNC, rl_insert }, /* * */
{ ISFUNC, rl_insert }, /* + */
{ ISFUNC, rl_insert }, /* , */
{ ISFUNC, rl_insert }, /* - */
{ ISFUNC, rl_insert }, /* . */
{ ISFUNC, rl_insert }, /* / */
/* Regular digits. */
{ ISFUNC, rl_insert }, /* 0 */
{ ISFUNC, rl_insert }, /* 1 */
{ ISFUNC, rl_insert }, /* 2 */
{ ISFUNC, rl_insert }, /* 3 */
{ ISFUNC, rl_insert }, /* 4 */
{ ISFUNC, rl_insert }, /* 5 */
{ ISFUNC, rl_insert }, /* 6 */
{ ISFUNC, rl_insert }, /* 7 */
{ ISFUNC, rl_insert }, /* 8 */
{ ISFUNC, rl_insert }, /* 9 */
/* A little more punctuation. */
{ ISFUNC, rl_insert }, /* : */
{ ISFUNC, rl_insert }, /* ; */
{ ISFUNC, rl_insert }, /* < */
{ ISFUNC, rl_insert }, /* = */
{ ISFUNC, rl_insert }, /* > */
{ ISFUNC, rl_insert }, /* ? */
{ ISFUNC, rl_insert }, /* @ */
/* Uppercase alphabet. */
{ ISFUNC, rl_insert }, /* A */
{ ISFUNC, rl_insert }, /* B */
{ ISFUNC, rl_insert }, /* C */
{ ISFUNC, rl_insert }, /* D */
{ ISFUNC, rl_insert }, /* E */
{ ISFUNC, rl_insert }, /* F */
{ ISFUNC, rl_insert }, /* G */
{ ISFUNC, rl_insert }, /* H */
{ ISFUNC, rl_insert }, /* I */
{ ISFUNC, rl_insert }, /* J */
{ ISFUNC, rl_insert }, /* K */
{ ISFUNC, rl_insert }, /* L */
{ ISFUNC, rl_insert }, /* M */
{ ISFUNC, rl_insert }, /* N */
{ ISFUNC, rl_insert }, /* O */
{ ISFUNC, rl_insert }, /* P */
{ ISFUNC, rl_insert }, /* Q */
{ ISFUNC, rl_insert }, /* R */
{ ISFUNC, rl_insert }, /* S */
{ ISFUNC, rl_insert }, /* T */
{ ISFUNC, rl_insert }, /* U */
{ ISFUNC, rl_insert }, /* V */
{ ISFUNC, rl_insert }, /* W */
{ ISFUNC, rl_insert }, /* X */
{ ISFUNC, rl_insert }, /* Y */
{ ISFUNC, rl_insert }, /* Z */
/* Some more punctuation. */
{ ISFUNC, rl_insert }, /* [ */
{ ISFUNC, rl_insert }, /* \ */
{ ISFUNC, rl_insert }, /* ] */
{ ISFUNC, rl_insert }, /* ^ */
{ ISFUNC, rl_insert }, /* _ */
{ ISFUNC, rl_insert }, /* ` */
/* Lowercase alphabet. */
{ ISFUNC, rl_insert }, /* a */
{ ISFUNC, rl_insert }, /* b */
{ ISFUNC, rl_insert }, /* c */
{ ISFUNC, rl_insert }, /* d */
{ ISFUNC, rl_insert }, /* e */
{ ISFUNC, rl_insert }, /* f */
{ ISFUNC, rl_insert }, /* g */
{ ISFUNC, rl_insert }, /* h */
{ ISFUNC, rl_insert }, /* i */
{ ISFUNC, rl_insert }, /* j */
{ ISFUNC, rl_insert }, /* k */
{ ISFUNC, rl_insert }, /* l */
{ ISFUNC, rl_insert }, /* m */
{ ISFUNC, rl_insert }, /* n */
{ ISFUNC, rl_insert }, /* o */
{ ISFUNC, rl_insert }, /* p */
{ ISFUNC, rl_insert }, /* q */
{ ISFUNC, rl_insert }, /* r */
{ ISFUNC, rl_insert }, /* s */
{ ISFUNC, rl_insert }, /* t */
{ ISFUNC, rl_insert }, /* u */
{ ISFUNC, rl_insert }, /* v */
{ ISFUNC, rl_insert }, /* w */
{ ISFUNC, rl_insert }, /* x */
{ ISFUNC, rl_insert }, /* y */
{ ISFUNC, rl_insert }, /* z */
/* Final punctuation. */
{ ISFUNC, rl_insert }, /* { */
{ ISFUNC, rl_insert }, /* | */
{ ISFUNC, rl_insert }, /* } */
{ ISFUNC, rl_insert }, /* ~ */
{ ISFUNC, rl_rubout } /* RUBOUT */
};
KEYMAP_ENTRY_ARRAY vi_escape_keymap = {
/* The regular control keys come first. */
{ ISFUNC, (Function *)0x0 }, /* Control-@ */
{ ISFUNC, (Function *)0x0 }, /* Control-a */
{ ISFUNC, (Function *)0x0 }, /* Control-b */
{ ISFUNC, (Function *)0x0 }, /* Control-c */
{ ISFUNC, (Function *)0x0 }, /* Control-d */
{ ISFUNC, (Function *)0x0 }, /* Control-e */
{ ISFUNC, (Function *)0x0 }, /* Control-f */
{ ISFUNC, (Function *)0x0 }, /* Control-g */
{ ISFUNC, (Function *)0x0 }, /* Control-h */
{ ISFUNC, rl_tab_insert}, /* Control-i */
{ ISFUNC, rl_emacs_editing_mode}, /* Control-j */
{ ISFUNC, rl_kill_line }, /* Control-k */
{ ISFUNC, (Function *)0x0 }, /* Control-l */
{ ISFUNC, rl_emacs_editing_mode}, /* Control-m */
{ ISFUNC, (Function *)0x0 }, /* Control-n */
{ ISFUNC, (Function *)0x0 }, /* Control-o */
{ ISFUNC, (Function *)0x0 }, /* Control-p */
{ ISFUNC, (Function *)0x0 }, /* Control-q */
{ ISFUNC, (Function *)0x0 }, /* Control-r */
{ ISFUNC, (Function *)0x0 }, /* Control-s */
{ ISFUNC, (Function *)0x0 }, /* Control-t */
{ ISFUNC, (Function *)0x0 }, /* Control-u */
{ ISFUNC, (Function *)0x0 }, /* Control-v */
{ ISFUNC, (Function *)0x0 }, /* Control-w */
{ ISFUNC, (Function *)0x0 }, /* Control-x */
{ ISFUNC, (Function *)0x0 }, /* Control-y */
{ ISFUNC, (Function *)0x0 }, /* Control-z */
{ ISFUNC, rl_vi_movement_mode }, /* Control-[ */
{ ISFUNC, (Function *)0x0 }, /* Control-\ */
{ ISFUNC, (Function *)0x0 }, /* Control-] */
{ ISFUNC, (Function *)0x0 }, /* Control-^ */
{ ISFUNC, rl_undo_command }, /* Control-_ */
/* The start of printing characters. */
{ ISFUNC, (Function *)0x0 }, /* SPACE */
{ ISFUNC, (Function *)0x0 }, /* ! */
{ ISFUNC, (Function *)0x0 }, /* " */
{ ISFUNC, (Function *)0x0 }, /* # */
{ ISFUNC, (Function *)0x0 }, /* $ */
{ ISFUNC, (Function *)0x0 }, /* % */
{ ISFUNC, (Function *)0x0 }, /* & */
{ ISFUNC, (Function *)0x0 }, /* ' */
{ ISFUNC, (Function *)0x0 }, /* ( */
{ ISFUNC, (Function *)0x0 }, /* ) */
{ ISFUNC, (Function *)0x0 }, /* * */
{ ISFUNC, (Function *)0x0 }, /* + */
{ ISFUNC, (Function *)0x0 }, /* , */
{ ISFUNC, (Function *)0x0 }, /* - */
{ ISFUNC, (Function *)0x0 }, /* . */
{ ISFUNC, (Function *)0x0 }, /* / */
/* Regular digits. */
{ ISFUNC, rl_vi_arg_digit }, /* 0 */
{ ISFUNC, rl_vi_arg_digit }, /* 1 */
{ ISFUNC, rl_vi_arg_digit }, /* 2 */
{ ISFUNC, rl_vi_arg_digit }, /* 3 */
{ ISFUNC, rl_vi_arg_digit }, /* 4 */
{ ISFUNC, rl_vi_arg_digit }, /* 5 */
{ ISFUNC, rl_vi_arg_digit }, /* 6 */
{ ISFUNC, rl_vi_arg_digit }, /* 7 */
{ ISFUNC, rl_vi_arg_digit }, /* 8 */
{ ISFUNC, rl_vi_arg_digit }, /* 9 */
/* A little more punctuation. */
{ ISFUNC, (Function *)0x0 }, /* : */
{ ISFUNC, (Function *)0x0 }, /* ; */
{ ISFUNC, (Function *)0x0 }, /* < */
{ ISFUNC, (Function *)0x0 }, /* = */
{ ISFUNC, (Function *)0x0 }, /* > */
{ ISFUNC, (Function *)0x0 }, /* ? */
{ ISFUNC, (Function *)0x0 }, /* @ */
/* Uppercase alphabet. */
{ ISFUNC, rl_do_lowercase_version }, /* A */
{ ISFUNC, rl_do_lowercase_version }, /* B */
{ ISFUNC, rl_do_lowercase_version }, /* C */
{ ISFUNC, rl_do_lowercase_version }, /* D */
{ ISFUNC, rl_do_lowercase_version }, /* E */
{ ISFUNC, rl_do_lowercase_version }, /* F */
{ ISFUNC, rl_do_lowercase_version }, /* G */
{ ISFUNC, rl_do_lowercase_version }, /* H */
{ ISFUNC, rl_do_lowercase_version }, /* I */
{ ISFUNC, rl_do_lowercase_version }, /* J */
{ ISFUNC, rl_do_lowercase_version }, /* K */
{ ISFUNC, rl_do_lowercase_version }, /* L */
{ ISFUNC, rl_do_lowercase_version }, /* M */
{ ISFUNC, rl_do_lowercase_version }, /* N */
{ ISFUNC, rl_do_lowercase_version }, /* O */
{ ISFUNC, rl_do_lowercase_version }, /* P */
{ ISFUNC, rl_do_lowercase_version }, /* Q */
{ ISFUNC, rl_do_lowercase_version }, /* R */
{ ISFUNC, rl_do_lowercase_version }, /* S */
{ ISFUNC, rl_do_lowercase_version }, /* T */
{ ISFUNC, rl_do_lowercase_version }, /* U */
{ ISFUNC, rl_do_lowercase_version }, /* V */
{ ISFUNC, rl_do_lowercase_version }, /* W */
{ ISFUNC, rl_do_lowercase_version }, /* X */
{ ISFUNC, rl_do_lowercase_version }, /* Y */
{ ISFUNC, rl_do_lowercase_version }, /* Z */
/* Some more punctuation. */
{ ISFUNC, (Function *)0x0 }, /* [ */
{ ISFUNC, (Function *)0x0 }, /* \ */
{ ISFUNC, (Function *)0x0 }, /* ] */
{ ISFUNC, (Function *)0x0 }, /* ^ */
{ ISFUNC, (Function *)0x0 }, /* _ */
{ ISFUNC, (Function *)0x0 }, /* ` */
/* Lowercase alphabet. */
{ ISFUNC, (Function *)0x0 }, /* a */
{ ISFUNC, (Function *)0x0 }, /* b */
{ ISFUNC, (Function *)0x0 }, /* c */
{ ISFUNC, (Function *)0x0 }, /* d */
{ ISFUNC, (Function *)0x0 }, /* e */
{ ISFUNC, (Function *)0x0 }, /* f */
{ ISFUNC, (Function *)0x0 }, /* g */
{ ISFUNC, (Function *)0x0 }, /* h */
{ ISFUNC, (Function *)0x0 }, /* i */
{ ISFUNC, (Function *)0x0 }, /* j */
{ ISFUNC, (Function *)0x0 }, /* k */
{ ISFUNC, (Function *)0x0 }, /* l */
{ ISFUNC, (Function *)0x0 }, /* m */
{ ISFUNC, (Function *)0x0 }, /* n */
{ ISFUNC, (Function *)0x0 }, /* o */
{ ISFUNC, (Function *)0x0 }, /* p */
{ ISFUNC, (Function *)0x0 }, /* q */
{ ISFUNC, (Function *)0x0 }, /* r */
{ ISFUNC, (Function *)0x0 }, /* s */
{ ISFUNC, (Function *)0x0 }, /* t */
{ ISFUNC, (Function *)0x0 }, /* u */
{ ISFUNC, (Function *)0x0 }, /* v */
{ ISFUNC, (Function *)0x0 }, /* w */
{ ISFUNC, (Function *)0x0 }, /* x */
{ ISFUNC, (Function *)0x0 }, /* y */
{ ISFUNC, (Function *)0x0 }, /* z */
/* Final punctuation. */
{ ISFUNC, (Function *)0x0 }, /* { */
{ ISFUNC, (Function *)0x0 }, /* | */
{ ISFUNC, (Function *)0x0 }, /* } */
{ ISFUNC, (Function *)0x0 }, /* ~ */
{ ISFUNC, rl_backward_kill_word } /* RUBOUT */
};

925
readline/vi_mode.c Normal file
View file

@ -0,0 +1,925 @@
/* vi_mode.c -- A vi emulation mode for Bash.
Derived from code written by Jeff Sparkes (jeff1@????).
*/
/* **************************************************************** */
/* */
/* VI Emulation Mode */
/* */
/* **************************************************************** */
/* Last string searched for from `/' or `?'. */
static char *vi_last_search = (char *)NULL;
static int vi_histpos;
/* Non-zero means enter insertion mode. */
int vi_doing_insert = 0;
/* *** UNCLEAN *** */
/* Command keys which do movement for xxx_to commands. */
static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
/* Keymap used for vi replace characters. Created dynamically since
rarely used. */
static Keymap vi_replace_map = (Keymap)NULL;
/* The number of characters inserted in the last replace operation. */
static vi_replace_count = 0;
/* Yank the nth arg from the previous line into this line at point. */
rl_vi_yank_arg (count)
int count;
{
rl_yank_nth_arg (count, 0);
}
/* Search again for the last thing searched for. */
rl_vi_search_again (ignore, key)
int ignore, key;
{
switch (key)
{
case 'n':
rl_vi_dosearch (vi_last_search, -1);
break;
case 'N':
rl_vi_dosearch (vi_last_search, 1);
break;
}
}
/* Do a vi style search. */
rl_vi_search (count, key)
int count, key;
{
int dir, c, save_pos;
char *p;
switch (key)
{
case '?':
dir = 1;
break;
case '/':
dir = -1;
break;
default:
ding ();
return;
}
vi_histpos = where_history ();
maybe_save_line ();
save_pos = rl_point;
/* Reuse the line input buffer to read the search string. */
the_line[0] = 0;
rl_end = rl_point = 0;
p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
rl_message (p, 0, 0);
while (c = rl_read_key ())
{
switch (c)
{
case CTRL('H'):
case RUBOUT:
if (rl_point == 0)
{
maybe_unsave_line ();
rl_clear_message ();
rl_point = save_pos;
return;
}
case CTRL('W'):
case CTRL('U'):
rl_dispatch (c, keymap);
break;
case ESC:
case RETURN:
case NEWLINE:
goto dosearch;
break;
case CTRL('C'):
maybe_unsave_line ();
rl_clear_message ();
rl_point = 0;
ding ();
return;
default:
rl_insert (1, c);
break;
}
rl_redisplay ();
}
dosearch:
if (vi_last_search)
free (vi_last_search);
vi_last_search = savestring (the_line);
rl_vi_dosearch (the_line, dir);
}
rl_vi_dosearch (string, dir)
char *string;
int dir;
{
int old, save = vi_histpos;
HIST_ENTRY *h;
if (string == 0 || *string == 0 || vi_histpos < 0)
{
ding ();
return;
}
if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1)
{
maybe_unsave_line ();
rl_clear_message ();
rl_point = 0;
ding ();
return;
}
vi_histpos = save;
old = where_history ();
history_set_pos (vi_histpos);
h = current_history ();
history_set_pos (old);
strcpy (the_line, h->line);
rl_undo_list = (UNDO_LIST *)h->data;
rl_end = strlen (the_line);
rl_point = 0;
rl_clear_message ();
}
/* Completion, from vi's point of view. */
rl_vi_complete (ignore, key)
int ignore, key;
{
if (!whitespace (the_line[rl_point]))
{
if (!whitespace (the_line[rl_point + 1]))
rl_vi_end_word (1, 'E');
rl_point++;
}
if (key == '*')
rl_complete_internal ('*');
else
rl_complete (0, key);
rl_vi_insertion_mode ();
}
/* Previous word in vi mode. */
rl_vi_prev_word (count, key)
int count, key;
{
if (count < 0)
{
rl_vi_next_word (-count, key);
return;
}
if (uppercase_p (key))
rl_vi_bWord (count);
else
rl_vi_bword (count);
}
/* Next word in vi mode. */
rl_vi_next_word (count, key)
int count;
{
if (count < 0)
{
rl_vi_prev_word (-count, key);
return;
}
if (uppercase_p (key))
rl_vi_fWord (count);
else
rl_vi_fword (count);
}
/* Move to the end of the ?next? word. */
rl_vi_end_word (count, key)
int count, key;
{
if (count < 0)
{
ding ();
return;
}
if (uppercase_p (key))
rl_vi_eWord (count);
else
rl_vi_eword (count);
}
/* Move forward a word the way that 'W' does. */
rl_vi_fWord (count)
int count;
{
while (count-- && rl_point < (rl_end - 1))
{
/* Skip until whitespace. */
while (!whitespace (the_line[rl_point]) && rl_point < rl_end)
rl_point++;
/* Now skip whitespace. */
while (whitespace (the_line[rl_point]) && rl_point < rl_end)
rl_point++;
}
}
rl_vi_bWord (count)
int count;
{
while (count-- && rl_point > 0)
{
while (rl_point-- >= 0 && whitespace (the_line[rl_point]));
while (rl_point >= 0 && !whitespace (the_line[rl_point]))
rl_point--;
rl_point++;
}
}
rl_vi_eWord (count)
int count;
{
while (count -- && rl_point < (rl_end - 1))
{
while (rl_point++ < rl_end && whitespace (the_line[rl_point]));
while (rl_point++ < rl_end && !whitespace (the_line[rl_point]));
rl_point--;
}
}
rl_vi_fword (count)
int count;
{
while (count -- && rl_point < (rl_end - 1))
{
if (isident (the_line[rl_point]))
{
while (isident (the_line[rl_point]) && rl_point < rl_end)
rl_point += 1;
}
else if (!whitespace (the_line[rl_point]))
{
while (!isident (the_line[rl_point]) &&
!whitespace (the_line[rl_point]) && rl_point < rl_end)
rl_point += 1;
}
while (whitespace (the_line[rl_point]) && rl_point < rl_end)
rl_point++;
}
}
rl_vi_bword (count)
int count;
{
while (count -- && rl_point > 0)
{
while (--rl_point > 0 && whitespace (the_line[rl_point]));
if (rl_point > 0)
{
if (isident (the_line[rl_point]))
while (--rl_point >= 0 && isident (the_line[rl_point]));
else
while (--rl_point >= 0 && !isident (the_line[rl_point]) &&
!whitespace (the_line[rl_point]));
rl_point++;
}
}
}
rl_vi_eword (count)
int count;
{
while (count -- && rl_point < rl_end - 1)
{
while (++rl_point < rl_end && whitespace (the_line[rl_point]));
if (rl_point < rl_end)
{
if (isident (the_line[rl_point]))
while (++rl_point < rl_end && isident (the_line[rl_point]));
else
while (++rl_point < rl_end && !isident (the_line[rl_point])
&& !whitespace (the_line[rl_point]));
rl_point--;
}
}
}
rl_vi_insert_beg ()
{
rl_beg_of_line ();
rl_vi_insertion_mode ();
return 0;
}
rl_vi_append_mode ()
{
if (rl_point < rl_end)
rl_point += 1;
rl_vi_insertion_mode ();
return 0;
}
rl_vi_append_eol ()
{
rl_end_of_line ();
rl_vi_append_mode ();
return 0;
}
/* What to do in the case of C-d. */
rl_vi_eof_maybe (count, c)
int count, c;
{
rl_newline (1, '\n');
}
/* Insertion mode stuff. */
/* Switching from one mode to the other really just involves
switching keymaps. */
rl_vi_insertion_mode ()
{
keymap = vi_insertion_keymap;
}
rl_vi_movement_mode ()
{
if (rl_point > 0)
rl_backward (1);
keymap = vi_movement_keymap;
vi_done_inserting ();
}
vi_done_inserting ()
{
if (vi_doing_insert)
{
rl_end_undo_group ();
vi_doing_insert = 0;
}
}
rl_vi_arg_digit (count, c)
int count, c;
{
if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
rl_beg_of_line ();
else
rl_digit_argument (count, c);
}
/* Doesn't take an arg count in vi */
rl_vi_change_case (ignore1, ignore2)
int ignore1, ignore2;
{
char c = 0;
if (uppercase_p (the_line[rl_point]))
c = to_lower (the_line[rl_point]);
else if (lowercase_p (the_line[rl_point]))
c = to_upper (the_line[rl_point]);
/* Vi is kind of strange here. */
if (c)
{
rl_begin_undo_group ();
rl_delete (1, c);
rl_insert (1, c);
rl_end_undo_group ();
rl_vi_check ();
}
else
rl_forward (1);
}
rl_vi_put (count, key)
int count, key;
{
if (!uppercase_p (key))
rl_forward (1);
rl_yank ();
rl_backward (1);
}
rl_vi_check ()
{
if (rl_point && rl_point == rl_end)
rl_point--;
}
rl_vi_column (count)
{
if (count > rl_end)
rl_end_of_line ();
else
rl_point = count - 1;
}
int
rl_vi_domove (key, nextkey)
int key, *nextkey;
{
int c, save;
rl_mark = rl_point;
c = rl_read_key ();
*nextkey = c;
if (!member (c, vi_motion))
{
if (digit (c))
{
save = rl_numeric_arg;
rl_digit_loop1 ();
rl_numeric_arg *= save;
}
else if ((key == 'd' && c == 'd') ||
(key == 'c' && c == 'c'))
{
rl_mark = rl_end;
rl_beg_of_line ();
return (0);
}
else
return (-1);
}
rl_dispatch (c, keymap);
/* No change in position means the command failed. */
if (rl_mark == rl_point)
return (-1);
if ((c == 'w' || c == 'W') && rl_point < rl_end)
rl_point--;
if (rl_mark < rl_point)
exchange (rl_point, rl_mark);
return (0);
}
/* A simplified loop for vi. Don't dispatch key at end.
Don't recognize minus sign? */
rl_digit_loop1 ()
{
int key, c;
while (1)
{
rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0);
key = c = rl_read_key ();
if (keymap[c].type == ISFUNC &&
keymap[c].function == rl_universal_argument)
{
rl_numeric_arg *= 4;
continue;
}
c = UNMETA (c);
if (numeric (c))
{
if (rl_explicit_arg)
rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
else
rl_numeric_arg = (c - '0');
rl_explicit_arg = 1;
}
else
{
rl_clear_message ();
rl_stuff_char (key);
}
}
}
rl_vi_delete_to (count, key)
int count, key;
{
int c;
if (uppercase_p (key))
rl_stuff_char ('$');
if (rl_vi_domove (key, &c))
{
ding ();
return;
}
if ((c != '|') && (c != 'h') && rl_mark < rl_end)
rl_mark++;
rl_kill_text (rl_point, rl_mark);
}
rl_vi_change_to (count, key)
int count, key;
{
int c;
if (uppercase_p (key))
rl_stuff_char ('$');
if (rl_vi_domove (key, &c))
{
ding ();
return;
}
if ((c != '|') && (c != 'h') && rl_mark < rl_end)
rl_mark++;
rl_begin_undo_group ();
vi_doing_insert = 1;
rl_kill_text (rl_point, rl_mark);
rl_vi_insertion_mode ();
}
rl_vi_yank_to (count, key)
int count, key;
{
int c, save = rl_point;
if (uppercase_p (key))
rl_stuff_char ('$');
if (rl_vi_domove (key, &c))
{
ding ();
return;
}
rl_begin_undo_group ();
rl_kill_text (rl_point, rl_mark);
rl_end_undo_group ();
rl_do_undo ();
rl_point = save;
}
rl_vi_delete (count)
{
if (rl_point >= rl_end - 1)
{
rl_delete (count, 0);
if (rl_point > 0)
rl_backward (1);
}
else
rl_delete (count, 0);
}
/* Turn the current line into a comment in shell history. A ksh function */
rl_vi_comment ()
{
rl_beg_of_line ();
rl_insert_text (": "); /* # doesn't work in interactive mode */
rl_redisplay ();
rl_newline (1, '\010');
}
rl_vi_first_print ()
{
rl_back_to_indent ();
}
rl_back_to_indent (ignore1, ignore2)
int ignore1, ignore2;
{
rl_beg_of_line ();
while (rl_point < rl_end && whitespace (the_line[rl_point]))
rl_point++;
}
/* NOTE: it is necessary that opposite directions are inverses */
#define FTO 1 /* forward to */
#define BTO -1 /* backward to */
#define FFIND 2 /* forward find */
#define BFIND -2 /* backward find */
rl_vi_char_search (count, key)
int count, key;
{
static char target;
static int orig_dir, dir;
int pos;
if (key == ';' || key == ',')
dir = (key == ';' ? orig_dir : -orig_dir);
else
{
target = rl_getc (in_stream);
switch (key)
{
case 't':
orig_dir = dir = FTO;
break;
case 'T':
orig_dir = dir = BTO;
break;
case 'f':
orig_dir = dir = FFIND;
break;
case 'F':
orig_dir = dir = BFIND;
break;
}
}
pos = rl_point;
if (dir < 0)
{
pos--;
do
{
if (the_line[pos] == target)
{
if (dir == BTO)
rl_point = pos + 1;
else
rl_point = pos;
return;
}
}
while (pos--);
if (pos < 0)
{
ding ();
return;
}
}
else
{ /* dir > 0 */
pos++;
do
{
if (the_line[pos] == target)
{
if (dir == FTO)
rl_point = pos - 1;
else
rl_point = pos;
return;
}
}
while (++pos < rl_end);
if (pos >= (rl_end - 1))
ding ();
}
}
/* Match brackets */
rl_vi_match ()
{
int count = 1, brack, pos;
pos = rl_point;
if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0)
{
while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 &&
rl_point < rl_end - 1)
rl_forward (1);
if (brack <= 0)
{
rl_point = pos;
ding ();
return;
}
}
pos = rl_point;
if (brack < 0)
{
while (count)
{
if (--pos >= 0)
{
int b = rl_vi_bracktype (the_line[pos]);
if (b == -brack)
count--;
else if (b == brack)
count++;
}
else
{
ding ();
return;
}
}
}
else
{ /* brack > 0 */
while (count)
{
if (++pos < rl_end)
{
int b = rl_vi_bracktype (the_line[pos]);
if (b == -brack)
count--;
else if (b == brack)
count++;
}
else
{
ding ();
return;
}
}
}
rl_point = pos;
}
int
rl_vi_bracktype (c)
int c;
{
switch (c)
{
case '(': return 1;
case ')': return -1;
case '[': return 2;
case ']': return -2;
case '{': return 3;
case '}': return -3;
default: return 0;
}
}
rl_vi_change_char ()
{
int c;
c = rl_getc (in_stream);
switch (c)
{
case '\033':
case CTRL('C'):
return;
default:
rl_begin_undo_group ();
rl_delete (1, c);
rl_insert (1, c);
rl_end_undo_group ();
break;
}
}
rl_vi_subst (count, key)
int count, key;
{
rl_begin_undo_group ();
vi_doing_insert = 1;
if (uppercase_p (key))
{
rl_beg_of_line ();
rl_kill_line (1);
}
else
rl_delete (1, key);
rl_vi_insertion_mode ();
}
rl_vi_overstrike (count, key)
int count, key;
{
int i;
if (vi_doing_insert == 0)
{
vi_doing_insert = 1;
rl_begin_undo_group ();
}
for (i = 0; i < count; i++)
{
vi_replace_count++;
rl_begin_undo_group ();
if (rl_point < rl_end)
{
rl_delete (1, key);
rl_insert (1, key);
}
else
rl_insert (1, key);
rl_end_undo_group ();
}
}
rl_vi_overstrike_delete (count)
int count;
{
int i, s;
for (i = 0; i < count; i++)
{
if (vi_replace_count == 0)
{
ding ();
break;
}
s = rl_point;
if (rl_do_undo ())
vi_replace_count--;
if (rl_point == s)
rl_backward (1);
}
if (vi_replace_count == 0 && vi_doing_insert)
{
rl_end_undo_group ();
rl_do_undo ();
vi_doing_insert = 0;
}
}
rl_vi_replace ()
{
int i;
vi_replace_count = 0;
vi_replace_map = rl_make_bare_keymap ();
for (i = ' '; i < 127; i++)
vi_replace_map[i].function = rl_vi_overstrike;
vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
vi_replace_map[ESC].function = rl_vi_movement_mode;
vi_replace_map[RETURN].function = rl_newline;
vi_replace_map[NEWLINE].function = rl_newline;
keymap = vi_replace_map;
}
/*
* Try to complete the word we are standing on or the word that ends with
* the previous character. A space matches everything.
* Word delimiters are space and ;.
*/
rl_vi_possible_completions()
{
int save_pos = rl_point;
if (!index (" ;", the_line[rl_point]))
{
while (!index(" ;", the_line[++rl_point]))
;
}
else if (the_line[rl_point-1] == ';')
{
ding ();
return (0);
}
rl_possible_completions ();
rl_point = save_pos;
return (0);
}