Initial revision
This commit is contained in:
parent
5a131cc7f0
commit
bd5635a1e2
71 changed files with 63772 additions and 0 deletions
249
gdb/COPYING
Normal file
249
gdb/COPYING
Normal 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
4297
gdb/ChangeLog
Normal file
File diff suppressed because it is too large
Load diff
4846
gdb/ChangeLog-3.x
Normal file
4846
gdb/ChangeLog-3.x
Normal file
File diff suppressed because it is too large
Load diff
506
gdb/Makefile.in
Normal file
506
gdb/Makefile.in
Normal 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
259
gdb/README
Normal 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
406
gdb/arm-tdep.c
Normal 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
650
gdb/blockframe.c
Normal 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
2259
gdb/breakpoint.c
Normal file
File diff suppressed because it is too large
Load diff
129
gdb/breakpoint.h
Normal file
129
gdb/breakpoint.h
Normal 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
1969
gdb/coffread.c
Normal file
File diff suppressed because it is too large
Load diff
151
gdb/command.h
Normal file
151
gdb/command.h
Normal 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
55
gdb/copying.awk
Normal 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
217
gdb/copying.c
Normal 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
5348
gdb/dbxread.c
Normal file
File diff suppressed because it is too large
Load diff
173
gdb/defs.h
Normal file
173
gdb/defs.h
Normal 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
187
gdb/environ.c
Normal 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
39
gdb/environ.h
Normal 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
1042
gdb/eval.c
Normal file
File diff suppressed because it is too large
Load diff
350
gdb/exec.c
Normal file
350
gdb/exec.c
Normal 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
324
gdb/expprint.c
Normal 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
200
gdb/expression.h
Normal 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
684
gdb/findvar.c
Normal 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 (®isters[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 (®isters[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, ®isters[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 *) ®isters[REGISTER_BYTE (regno)];
|
||||
SWAP_TARGET_AND_HOST (®, 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 *) ®isters[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, ®isters[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
128
gdb/frame.h
Normal 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
242
gdb/gdb-int.texinfo
Executable 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
63
gdb/gdbcmd.h
Normal 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
82
gdb/gdbcore.h
Normal 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
494
gdb/i386-tdep.c
Normal 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
1088
gdb/infcmd.c
Normal file
File diff suppressed because it is too large
Load diff
201
gdb/inferior.h
Normal file
201
gdb/inferior.h
Normal 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
478
gdb/inflow.c
Normal 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, <c_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, <c_inferior);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLGET, &lmode_inferior);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
sg_ours.c_lflag |= ICANON;
|
||||
if (output_only && !(sg_inferior.c_lflag & ICANON))
|
||||
sg_ours.c_lflag &= ~ICANON;
|
||||
#else /* not HAVE_TERMIO */
|
||||
sg_ours.sg_flags &= ~RAW & ~CBREAK;
|
||||
if (output_only)
|
||||
sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags;
|
||||
#endif /* not HAVE_TERMIO */
|
||||
|
||||
fcntl (0, F_SETFL, tflags_ours);
|
||||
fcntl (0, F_SETFL, tflags_ours);
|
||||
ioctl (0, TIOCSETN, &sg_ours);
|
||||
|
||||
#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
|
||||
ioctl (0, TIOCSETC, &tc_ours);
|
||||
#endif
|
||||
#ifdef TIOCGLTC
|
||||
ioctl (0, TIOCSLTC, <c_ours);
|
||||
#endif
|
||||
#ifdef TIOCLGET
|
||||
ioctl (0, TIOCLSET, &lmode_ours);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMIO
|
||||
sg_ours.c_lflag |= ICANON;
|
||||
#else /* not HAVE_TERMIO */
|
||||
sg_ours.sg_flags &= ~RAW & ~CBREAK;
|
||||
#endif /* not HAVE_TERMIO */
|
||||
}
|
||||
|
||||
/* 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 *)<c_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, <c_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
397
gdb/infptrace.c
Normal 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 *) ®isters[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 *) ®isters[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
1690
gdb/infrun.c
Normal file
File diff suppressed because it is too large
Load diff
182
gdb/inftarg.c
Normal file
182
gdb/inftarg.c
Normal 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
26
gdb/m68k-tdep.c
Normal 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
2127
gdb/main.c
Normal file
File diff suppressed because it is too large
Load diff
178
gdb/mem-break.c
Normal file
178
gdb/mem-break.c
Normal 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
679
gdb/mips-tdep.c
Normal 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
2879
gdb/mipsread.c
Normal file
File diff suppressed because it is too large
Load diff
1960
gdb/printcmd.c
Normal file
1960
gdb/printcmd.c
Normal file
File diff suppressed because it is too large
Load diff
893
gdb/remote-sa.m68k.shar
Executable file
893
gdb/remote-sa.m68k.shar
Executable 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",®isters[ 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
829
gdb/remote.c
Normal 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, ®s[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
245
gdb/solib.c
Normal 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
1186
gdb/source.c
Normal file
File diff suppressed because it is too large
Load diff
586
gdb/sparc-tdep.c
Normal file
586
gdb/sparc-tdep.c
Normal 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
1139
gdb/stack.c
Normal file
File diff suppressed because it is too large
Load diff
746
gdb/symfile.c
Normal file
746
gdb/symfile.c
Normal 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
170
gdb/symfile.h
Normal 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
442
gdb/symmisc.c
Normal 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
2622
gdb/symtab.c
Normal file
File diff suppressed because it is too large
Load diff
884
gdb/symtab.h
Normal file
884
gdb/symtab.h
Normal 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
563
gdb/target.c
Normal 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
406
gdb/target.h
Normal 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
50
gdb/terminal.h
Normal 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
1294
gdb/utils.c
Normal file
File diff suppressed because it is too large
Load diff
694
gdb/valarith.c
Normal file
694
gdb/valarith.c
Normal 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
1478
gdb/valops.c
Normal file
File diff suppressed because it is too large
Load diff
1915
gdb/valprint.c
Normal file
1915
gdb/valprint.c
Normal file
File diff suppressed because it is too large
Load diff
289
gdb/value.h
Normal file
289
gdb/value.h
Normal 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
249
readline/COPYING
Normal 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
103
readline/Makefile.in
Normal 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
50
readline/chardefs.h
Normal 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
472
readline/emacs_keymap.c
Normal 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
212
readline/funmap.c
Normal 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
1478
readline/history.c
Normal file
File diff suppressed because it is too large
Load diff
108
readline/history.h
Normal file
108
readline/history.h
Normal 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
172
readline/keymaps.c
Normal 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
53
readline/keymaps.h
Normal 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
5641
readline/readline.c
Normal file
File diff suppressed because it is too large
Load diff
170
readline/readline.h
Normal file
170
readline/readline.h
Normal 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
474
readline/vi_keymap.c
Normal 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
925
readline/vi_mode.c
Normal 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);
|
||||
}
|
Loading…
Add table
Reference in a new issue