This commit was generated by cvs2svn to compensate for changes in r130803,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Marcel Moolenaar 2004-06-20 18:26:14 +00:00
commit e8077c0e5b
623 changed files with 201604 additions and 34682 deletions

View file

@ -1,6 +1,32 @@
# Configure fragment invoked in the post-target section for subdirs
# wanting multilib support.
#
# Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003
# Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
#
# Please report bugs to <gcc-bugs@gnu.org>
# and send patches to <gcc-patches@gnu.org>.
# It is advisable to support a few --enable/--disable options to let the
# user select which libraries s/he really wants.
#
@ -17,8 +43,6 @@
# . ${srcdir}/../config-ml.in
# fi
#
# See librx/configure.in in the libg++ distribution for an example of how
# to handle autoconf'd libraries.
#
# Things are complicated because 6 separate cases must be handled:
# 2 (native, cross) x 3 (absolute-path, relative-not-dot, dot) = 6.
@ -30,13 +54,10 @@
# The build tree is layed out as
#
# ./
# libg++
# newlib
# m68020/
# libg++
# newlib
# m68881/
# libg++
# newlib
#
# The nice feature about this arrangement is that inter-library references
@ -69,11 +90,6 @@
# newlib. It is up to each target to turn on multilib support for the other
# libraries as desired.
# We have to handle being invoked by both Cygnus configure and Autoconf.
#
# Cygnus configure incoming variables:
# srcdir, subdir, host, arguments
#
# Autoconf incoming variables:
# srcdir, host, ac_configure_args
#
@ -83,26 +99,14 @@
# Note that `host' in this case is GCC's `target'. Target libraries are
# configured for a particular host.
if [ -n "${ac_configure_args}" ]; then
Makefile=${ac_file-Makefile}
ml_config_shell=${CONFIG_SHELL-/bin/sh}
ml_arguments="${ac_configure_args}"
ml_realsrcdir=${srcdir}
else
Makefile=${Makefile-Makefile}
ml_config_shell=${config_shell-/bin/sh}
ml_arguments="${arguments}"
if [ -n "${subdir}" -a "${subdir}" != "." ] ; then
ml_realsrcdir=${srcdir}/${subdir}
else
ml_realsrcdir=${srcdir}
fi
fi
Makefile=${ac_file-Makefile}
ml_config_shell=${CONFIG_SHELL-/bin/sh}
ml_realsrcdir=${srcdir}
# Scan all the arguments and set all the ones we need.
ml_verbose=--verbose
for option in ${ml_arguments}
for option in ${ac_configure_args}
do
case $option in
--*) ;;
@ -128,7 +132,7 @@ do
enableopt=`echo ${option} | sed 's:^--::;s:=.*$::;s:-:_:g'`
eval $enableopt="$optarg"
;;
--norecursion | --no*)
--norecursion | --no-recursion)
ml_norecursion=yes
;;
--silent | --sil* | --quiet | --q*)
@ -156,7 +160,7 @@ done
if [ "${enable_multilib}" = yes ]; then
# Compute whether this is the library's top level directory
# (ie: not a multilib subdirectory, and not a subdirectory like libg++/src).
# (ie: not a multilib subdirectory, and not a subdirectory like newlib/src).
# ${with_multisubdir} tells us we're in the right branch, but we could be
# in a subdir of that.
# ??? The previous version could void this test by separating the process into
@ -397,6 +401,28 @@ mips*-*-*)
esac
;;
powerpc*-*-* | rs6000*-*-*)
if [ x$enable_aix64 = xno ]
then
old_multidirs="${multidirs}"
multidirs=""
for x in ${old_multidirs}; do
case "$x" in
*ppc64* ) : ;;
*) multidirs="${multidirs} ${x}" ;;
esac
done
fi
if [ x$enable_pthread = xno ]
then
old_multidirs="${multidirs}"
multidirs=""
for x in ${old_multidirs}; do
case "$x" in
*pthread* ) : ;;
*) multidirs="${multidirs} ${x}" ;;
esac
done
fi
if [ x$enable_softfloat = xno ]
then
old_multidirs="${multidirs}"
@ -463,17 +489,6 @@ powerpc*-*-* | rs6000*-*-*)
esac
done
fi
if [ x$enable_aix = xno ]
then
old_multidirs="${multidirs}"
multidirs=""
for x in ${old_multidirs}; do
case "$x" in
*mcall-aix* ) : ;;
*) multidirs="${multidirs} ${x}" ;;
esac
done
fi
;;
sparc*-*-*)
case " $multidirs " in
@ -510,14 +525,16 @@ multidirs=`echo "$multidirs" | sed -e 's/^[ ][ ]*//' -e 's/[ ][ ]*$//' -e 's/[ ]
cat > Multi.tem <<\EOF
PWD_COMMAND=$${PWDCMD-pwd}
# FIXME: There should be an @-sign in front of the `if'.
# Leave out until this is tested a bit more.
multi-do:
if [ -z "$(MULTIDIRS)" ]; then \
true; \
else \
rootpre=`pwd`/; export rootpre; \
srcrootpre=`cd $(srcdir); pwd`/; export srcrootpre; \
rootpre=`${PWD_COMMAND}`/; export rootpre; \
srcrootpre=`cd $(srcdir); ${PWD_COMMAND}`/; export srcrootpre; \
lib=`echo $${rootpre} | sed -e 's,^.*/\([^/][^/]*\)/$$,\1,'`; \
compiler="$(CC)"; \
for i in `$${compiler} --print-multi-lib 2>/dev/null`; do \
@ -531,10 +548,17 @@ multi-do:
CFLAGS="$(CFLAGS) $${flags}" \
prefix="$(prefix)" \
exec_prefix="$(exec_prefix)" \
GCJFLAGS="$(GCJFLAGS) $${flags}" \
CXXFLAGS="$(CXXFLAGS) $${flags}" \
LIBCFLAGS="$(LIBCFLAGS) $${flags}" \
LIBCXXFLAGS="$(LIBCXXFLAGS) $${flags}" \
LDFLAGS="$(LDFLAGS) $${flags}" \
MULTIFLAGS="$${flags}" \
DESTDIR="$(DESTDIR)" \
INSTALL="$(INSTALL)" \
INSTALL_DATA="$(INSTALL_DATA)" \
INSTALL_PROGRAM="$(INSTALL_PROGRAM)" \
INSTALL_SCRIPT="$(INSTALL_SCRIPT)" \
$(DO)); then \
true; \
else \
@ -552,7 +576,7 @@ multi-clean:
if [ -z "$(MULTIDIRS)" ]; then \
true; \
else \
lib=`pwd | sed -e 's,^.*/\([^/][^/]*\)$$,\1,'`; \
lib=`${PWD_COMMAND} | sed -e 's,^.*/\([^/][^/]*\)$$,\1,'`; \
for dir in Makefile $(MULTIDIRS); do \
if [ -f ../$${dir}/$${lib}/Makefile ]; then \
if (cd ../$${dir}/$${lib}; $(MAKE) $(FLAGS_TO_PASS) $(DO)); \
@ -659,10 +683,10 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then
if [ "${ml_verbose}" = --verbose ]; then
echo "Running configure in multilib subdirs ${multidirs}"
echo "pwd: `pwd`"
echo "pwd: `${PWDCMD-pwd}`"
fi
ml_origdir=`pwd`
ml_origdir=`${PWDCMD-pwd}`
ml_libdir=`echo $ml_origdir | sed -e 's,^.*/,,'`
# cd to top-level-build-dir/${with_target_subdir}
cd ..
@ -671,7 +695,7 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then
if [ "${ml_verbose}" = --verbose ]; then
echo "Running configure in multilib subdir ${ml_dir}"
echo "pwd: `pwd`"
echo "pwd: `${PWDCMD-pwd}`"
fi
if [ -d ${ml_dir} ]; then true; else
@ -699,7 +723,7 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then
case ${srcdir} in
".")
echo Building symlink tree in `pwd`/${ml_dir}/${ml_libdir}
echo Building symlink tree in `${PWDCMD-pwd}`/${ml_dir}/${ml_libdir}
if [ "${with_target_subdir}" != "." ]; then
ml_unsubdir="../"
else
@ -720,7 +744,7 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then
;;
*)
case "${srcdir}" in
/*) # absolute path
/* | [A-Za-z]:[\\/]* ) # absolute path
ml_newsrcdir=${srcdir}
;;
*) # otherwise relative
@ -733,31 +757,32 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then
esac
case "${progname}" in
/*) ml_recprog=${progname} ;;
/* | [A-Za-z]:[\\/]* ) ml_recprog=${progname} ;;
*) ml_recprog=${dotdot}${progname} ;;
esac
# FIXME: POPDIR=${PWD=`pwd`} doesn't work here.
ML_POPDIR=`pwd`
ML_POPDIR=`${PWDCMD-pwd}`
cd ${ml_dir}/${ml_libdir}
if [ -f ${ml_newsrcdir}/configure ]; then
ml_recprog="${ml_newsrcdir}/configure --cache-file=../config.cache"
ml_recprog="${ml_newsrcdir}/configure"
fi
# find compiler flag corresponding to ${ml_dir}
for i in `${CC-gcc} --print-multi-lib 2>/dev/null`; do
for i in `${CC-gcc} --print-multi-lib 2>/dev/null`; do
dir=`echo $i | sed -e 's/;.*$//'`
if [ "${dir}" = "${ml_dir}" ]; then
flags=`echo $i | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`
break
fi
done
ml_config_env='CC="${CC_}$flags" CXX="${CXX_}$flags"'
ml_config_env='CC="${CC_}$flags" CXX="${CXX_}$flags" GCJ="${GCJ_}$flags"'
if [ "${with_target_subdir}" = "." ]; then
CC_=$CC' '
CXX_=$CXX' '
GCJ_=$GCJ' '
else
# Create a regular expression that matches any string as long
# as ML_POPDIR.
@ -786,6 +811,18 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then
esac
done
GCJ_=
for arg in ${GCJ}; do
case $arg in
-[BIL]"${ML_POPDIR}"/*)
GCJ_="${GCJ_}"`echo "X${arg}" | sed -n "s/X\\(-[BIL]${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X-[BIL]${popdir_rx}\\(.*\\)/\\1/p"`' ' ;;
"${ML_POPDIR}"/*)
GCJ_="${GCJ_}"`echo "X${arg}" | sed -n "s/X\\(${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X${popdir_rx}\\(.*\\)/\\1/p"`' ' ;;
*)
GCJ_="${GCJ_}${arg} " ;;
esac
done
if test "x${LD_LIBRARY_PATH+set}" = xset; then
LD_LIBRARY_PATH_=
for arg in `echo "$LD_LIBRARY_PATH" | tr ':' ' '`; do
@ -823,7 +860,7 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then
if eval ${ml_config_env} ${ml_config_shell} ${ml_recprog} \
--with-multisubdir=${ml_dir} --with-multisrctop=${multisrctop} \
${ml_arguments} ${ml_srcdiroption} ; then
${ac_configure_args} ${ml_srcdiroption} ; then
true
else
exit 1

52
contrib/gdb/djunpack.bat Normal file
View file

@ -0,0 +1,52 @@
@echo off
Rem
Rem WARNING WARNING WARNING: This file needs to have DOS CRLF end-of-line
Rem format, or else stock DOS/Windows shells will refuse to run it.
Rem
Rem This batch file unpacks the GDB distribution while simultaneously
Rem renaming some of the files whose names are invalid on DOS or conflict
Rem with other file names after truncation to DOS 8+3 namespace.
Rem
Rem Invoke like this:
Rem
Rem djunpack gdb-XYZ.tar
Rem
Rem where XYZ is the version number. If the argument includes leading
Rem directories, it MUST use backslashes, not forward slashes.
Rem
Rem The following 2 lines need to be changed with each new GDB release, to
Rem be identical to the name of the top-level directory where the GDB
Rem distribution unpacks itself.
set GDBVER=gdb-6.1.1
if "%GDBVER%"=="gdb-6.1.1" GoTo EnvOk
Rem If their environment space is too small, re-exec with a larger one
command.com /e:4096 /c %0 %1
GoTo End
:EnvOk
if not exist %1 GoTo NoArchive
djtar -x -p -o %GDBVER%/gdb/config/djgpp/fnchange.lst %1 > fnchange.tmp
Rem The following uses a feature of COPY whereby it does not copy
Rem empty files. We need that because the previous line will create
Rem an empty fnchange.tmp even if the command failed for some reason.
copy fnchange.tmp junk.tmp > nul
if not exist junk.tmp GoTo NoDjTar
del junk.tmp
sed -e 's,@V@,%GDBVER%,g' < fnchange.tmp > fnchange.lst
Rem See the comment above about the reason for using COPY.
copy fnchange.lst junk.tmp > nul
if not exist junk.tmp GoTo NoSed
del junk.tmp
djtar -x -n fnchange.lst %1
GoTo End
:NoSed
echo FAIL: Sed is not available.
GoTo End
:NoDjTar
echo FAIL: DJTAR is not available or no fnchange.lst file in %1.
GoTo End
:NoArchive
echo FAIL: the file %1 does not seem to exist.
echo Remember that %1 cannot use forward slashes, only backslashes.
GoTo End
:End
set GDBVER=

View file

@ -1,14 +1,15 @@
GDB Maintainers
Blanket Write Privs
Global Maintainers
(alphabetic)
Jim Blandy jimb@redhat.com
Kevin Buettner kevinb@redhat.com
Andrew Cagney ac131313@redhat.com
J.T. Conklin jtc@redback.com
Andrew Cagney cagney@gnu.org
J.T. Conklin jtc@acorntoolworks.com
Fred Fish fnf@ninemoons.com
Daniel Jacobowitz dan@debian.org
Mark Kettenis kettenis@gnu.org
Peter Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
Stan Shebs shebs@apple.com
@ -23,7 +24,7 @@ Note individuals who maintain parts of the debugger need approval to
check in changes outside of the immediate domain that they maintain.
If there is no maintainer for a given domain then the responsibility
falls to the head maintainer.
falls to a global maintainer.
If there are several maintainers for a given domain then
responsibility falls to the first maintainer. The first maintainer is
@ -47,142 +48,110 @@ fix, since such a change without discussion will result in
instantaneous and loud complaints.
Target/Architecture:
Target Instruction Set Architectures:
Generic ISA (Instruction Set Architecture) issues, API variants, CPU
variants. *-tdep.c. The Target/Architecture maintainer works with the
host maintainer when resolving build issues. The Target/Architecture
maintainer works with the native maintainer when resolving API issues.
a29k OBSOLETE
a29k Deleted.
alpha --target=alpha-dec-osf4.0a -Werror
alpha --target=alpha-elf ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
arc --target=arc-elf ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
arc Deleted.
arm --target=arm-elf -w
Fernando Nasser fnasser@redhat.com
arm --target=arm-elf ,-Werror
Scott Bambrough scottb@netwinder.org
Richard Earnshaw rearnsha@arm.com
Not multi-arch
avr --target=avr ,-Werror
Theodore A. Roth troth@verinet.com
Theodore A. Roth troth@openavr.org
cris --target=cris-elf -w
cris --target=cris-elf ,-Werror
Orjan Friberg orjanf@axis.com
d10v --target=d10v-elf ,-Werror
Maintenance only
d30v --target=d30v-elf ,-Werror
d30v Deleted.
fr30 Deleted.
frv --target=frv-elf ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
djgpp --target=i586-pc-msdosdjgpp ,-Werror
(See native and host)
fr30 --target=fr30-elf -Werror
h8300 --target=h8300hms ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
h8300 --target=h8300hms -Werror
Maintenance only
Not multi-arch, work in progress
h8500 Deleted.
h8500 --target=h8500hms -Werror
Maintenance only
Not multi-arch, work in progress
i386 --target=i386-elf,i386-aout ,-Werror
i386 --target=i386-elf ,-Werror
Mark Kettenis kettenis@gnu.org
i960 --target=i960-coff ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
i960 Deleted.
ia64 --target=ia64-linux ,-Werror
ia64 --target=ia64-linux-gnu ,-Werror
(--target=ia64-elf broken)
Kevin Buettner kevinb@redhat.com
m32r --target=m32r-elf -Werror
Michael Snyder msnyder@redhat.com
Not multi-arch
m32r --target=m32r-elf ,-Werror
m68hc11 --target=m68hc11-elf ,-Werror
Stephane Carrez Stephane.Carrez@worldnet.fr
m68hc11 --target=m68hc11-elf ,-Werror ,
Stephane Carrez stcarrez@nerim.fr
m68k --target=m68k-elf ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
m88k --target=m88k ,-Werror
Known problem in 5.1
m88k Deleted.
mcore --target=mcore-elf ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
mcore --target=mcore-elf,mcore-pe ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
mips --target=mips-elf,mips64-elf ,-Werror
mips --target=mips-elf ,-Werror
Andrew Cagney cagney@redhat.com
mn10200 --target=mn10200-elf ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
mn10200 Deleted.
mn10300 --target=mn10300-elf ,-Werror
Maintenance only
ns32k --target=ns32k-netbsd ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
pa (--target=hppa1.1-hp-proelf broken)
pa (--target=hppa-elf broken)
Maintenance only
OBSOLETE candidate, not multi-arch
powerpc --target=powerpc-eabi ,-Werror
Kevin Buettner kevinb@redhat.com
rs6000 --target=rs6000-ibm-aix4.1 ,-Werror
(see rs6000 native and ppc target)
s390 --target=s390-linux ,-Werror
s390 --target=s390-linux-gnu ,-Werror
(contact DJ Barrow djbarrow@de.ibm.com)
sh --target=sh-hms,sh-elf ,-Werror
sh --target=sh-elf ,-Werror
Elena Zannoni ezannoni@redhat.com
sparc --target=sparc-elf,sparc64-elf ,-Werror
sparc --target=sparc-elf ,-Werror
Maintenance only
tic80 Deleted.
v850 --target=v850-elf ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
vax --target=vax-dec-vms5.5 ,-Werror
vax --target=vax-netbsd ,-Werror
Maintenance only
OBSOLETE candidate, not multi-arch
w65 Deleted.
x86-64 (--target=x86_64-linux-gnu broken)
x86-64 --target=x86_64-linux-gnu ,-Werror
Maintenance only
xstormy16 --target=xstormy16-elf ,-Werror
Corinna Vinschen vinschen@redhat.com
z8k --target=z8k-coff ,-Werror
Known problem in 5.1
Maintenance only
OBSOLETE candidate, not multi-arch
z8k Deleted.
All developers recognized by this file can make arbitrary changes to
OBSOLETE targets.
@ -194,21 +163,8 @@ All recognized developers can make mechanical changes (by virtue of
the obvious fix rule) to ``maintenance only'' targets. The change
shall be sanity checked by compiling with one of the listed targets.
The GAWK segment:
awk < "${maintainers}" '
$2 ~ /--target=.*/ {
targets = gensub (/^.*--target=/, "", 1, $2)
warnings = gensub (/[)]*$/, "", 1, $3)
split (targets, targ, /,/)
for (i in targ) {
print targ[i], warnings
}
}'
can be used to generate a full list of --target=
--enable-gdb-build-warning= pairs.
The Bourne shell script gdb_mbuild.sh can be used to rebuild all the
above targets.
Host/Native:
@ -218,19 +174,19 @@ support - typically shared libraries and quirks to procfs/ptrace/...
The Native maintainer works with the Arch and Core maintainers when
resolving more generic problems.
The host maintainer ensures that gdb (including mmalloc) can be built
as a cross debugger on their platform.
The host maintainer ensures that gdb can be built as a cross debugger on
their platform.
AIX Peter Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
Kevin Buettner kevinb@redhat.com
Joel Brobecker brobecker@gnat.com
djgpp native Eli Zaretskii eliz@gnu.org
DJ Delorie dj@redhat.com
MS Windows (NT, CE, '00, 9x, Me) host & native
Chris Faylor cgf@redhat.com
MS Windows (NT, '00, 9x, Me, XP) host & native
Chris Faylor cgf@alum.bu.edu
GNU/Linux/x86 native & host
Mark Kettenis kettenis@gnu.org
Jim Blandy jimb@redhat.com
GNU/Linux PPC native Kevin Buettner kevinb@redhat.com
GNU/Linux MIPS native & host
Daniel Jacobowitz dan@debian.org
@ -238,12 +194,13 @@ GNU/Linux m68k Andreas Schwab schwab@suse.de
FreeBSD native & host Mark Kettenis kettenis@gnu.org
David O'Brien obrien@freebsd.org
hurd native Mark Kettenis kettenis@gnu.org
NetBSD native & host Jason Thorpe thorpej@wasabisystems.com
SCO/Unixware Robert Lipe rjl@sco.com
GNU/Linux ARM native Scott Bambrough scottb@netwinder.org
Solaris/x86 native & host (devolved)
Peter Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
Solaris/SPARC native & host (devolved)
Michael Snyder msnyder@redhat.com
(Global Maintainers)
@ -253,8 +210,10 @@ generic arch support Andrew Cagney cagney@redhat.com
Any host/target maintainer can add to
gdbarch.{c,h,sh}. Send tricky ones to cagney.
target vector Andrew Cagney cagney@redhat.com
main (main.c, top.c) Elena Zannoni ezannoni@redhat.com
event loop Elena Zannoni ezannoni@redhat.com
For the part of top.c related to the event loop,
send questions to ezannoni@redhat.com
generic symtabs Jim Blandy jimb@redhat.com
Elena Zannoni ezannoni@redhat.com
@ -267,42 +226,39 @@ generic symtabs Jim Blandy jimb@redhat.com
coff reader Philippe De Muyter phdm@macqel.be
xcoff reader Any maintainer can modify this; please send tricky
ones to Kevin Buettner <kevinb@redhat.com>
linespec Jim Blandy jimb@redhat.com
Elena Zannoni ezannoni@redhat.com
Fernando Nasser fnasser@redhat.com
HP/UX readers Any [past] maintainer can modify this.
Please send tricky ones to the symtabs maintainers.
tracing bytecode stuff Jim Blandy jimb@redhat.com
(Global Maintainers)
tracing Michael Snyder msnyder@redhat.com
threads Michael Snyder msnyder@redhat.com
Mark Kettenis kettenis@gnu.org
breakpoints Michael Snyder msnyder@redhat.com
Jim Blandy jimb@redhat.com
breakpoints (Global Maintainers)
language support (Blanket Write Privs Maintainers)
C++ Daniel Jacobowitz dan@debian.org
Java support (devolved)
Per Bothner per@bothner.com
Anthony Green green@redhat.com
Java support (Global Maintainers)
Pascal support Pierre Muller muller@sources.redhat.com
Scheme support Jim Blandy jimb@redhat.com
shared libs (devolved) Jim Blandy jimb@redhat.com
Kevin Buettner kevinb@redhat.com
Objective C support Adam Fedor fedor@gnu.org
shared libs (devolved) Kevin Buettner kevinb@redhat.com
xcoffsolib Peter Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
remote.c Andrew Cagney cagney@redhat.com
include/remote-sim.h, remote-sim.c
Andrew Cagney cagney@redhat.com
sds protocol Fernando Nasser fnasser@redhat.com
rdi/adp protocol Fernando Nasser fnasser@redhat.com
sds protocol (vacant)
rdi/adp protocol (vacant)
documentation Eli Zaretskii eliz@gnu.org
testsuite Fernando Nasser fnasser@redhat.com
config Mark Salter msalter@redhat.com
lib Mark Salter msalter@redhat.com
testsuite Michael Chastain mec.gnu@mindspring.com
(Global Maintainers)
lib/, config/, gdb.base/, ...
Michael Chastain mec.gnu@mindspring.com
(Global Maintainers)
gdbtk (gdb.gdbtk) Keith Seitz keiths@redhat.com
c++ (gdb.c++) Michael Chastain mec@shout.net
c++ (gdb.cp) Michael Chastain mec.gnu@mindspring.com
David Carlton carlton@bactrian.org
mi tests (gdb.mi) Elena Zannoni ezannoni@redhat.com
Andrew Cagney cagney@redhat.com
stabs (gdb.stabs) Elena Zannoni ezannoni@redhat.com
threads (gdb.threads) Michael Snyder msnyder@redhat.com
trace (gdb.trace) Michael Snyder msnyder@redhat.com
hp tests (gdb.hp) (vacant)
@ -312,7 +268,7 @@ Kernel Object Display Fernando Nasser fnasser@redhat.com
UI: External (user) interfaces.
command interpreter Fernando Nasser fnasser@redhat.com
command interpreter (Global Maintainers)
gdbtk (c & tcl) Jim Ingham jingham@apple.com
Fernando Nasser fnasser@redhat.com
Keith Seitz keiths@redhat.com
@ -321,8 +277,8 @@ libgui (w/foundry, sn) Jim Ingham jingham@apple.com
mi (gdb/mi) Andrew Cagney cagney@redhat.com
Elena Zannoni ezannoni@redhat.com
Fernando Nasser fnasser@redhat.com
tui (vacant)
Technical Contact Point wdb@cup.hp.com
tui Stephane Carrez stcarrez@nerim.fr
(Global Maintainers)
Misc:
@ -336,6 +292,8 @@ Makefile.in, configure* ALL
mmalloc/ ALL Host maintainers
NEWS ALL
sim/ See sim/MAINTAINERS
readline/ Master version: ftp://ftp.cwru.edu/pub/bash/
@ -352,49 +310,109 @@ To get recommended for the Write After Approval list you need a valid
FSF assignment and have submitted one good patch.
David Anderson davea@sgi.com
Shrinivas Atre shrinivasa@kpitcummins.com
Scott Bambrough scottb@netwinder.org
Jim Blandy jimb@redhat.com
Philip Blundell philb@gnu.org
Joel Brobecker brobecker@act-europe.fr
Per Bothner per@bothner.com
Joel Brobecker brobecker@gnat.com
Dave Brolley brolley@redhat.com
Paul Brook paul@codesourcery.com
Kevin Buettner kevinb@redhat.com
Andrew Cagney cagney@gnu.org
David Carlton carlton@bactrian.org
Stephane Carrez stcarrez@nerim.fr
Michael Chastain mec.gnu@mindspring.com
Eric Christopher echristo@redhat.com
Randolph Chung tausq@debian.org
Nick Clifton nickc@redhat.com
Brendan Conoboy blc@redhat.com
DJ Delorie dj@redhat.com
Chris G. Demetriou cgd@broadcom.com
Philippe De Muyter phdm@macqel.be
Dhananjay Deshpande dhananjayd@kpitcummins.com
Klee Dienes kdienes@apple.com
Richard Earnshaw rearnsha@arm.com
Frank Ch. Eigler fche@redhat.com
Ben Elliston bje@gnu.org
Brian Ford ford@vss.fsi.com
Raoul Gough RaoulGough@yahoo.co.uk
Anthony Green green@redhat.com
Matthew Green mrg@eterna.com.au
Jerome Guitton guitton@act-europe.fr
Adam Fedor fedor@gnu.org
Fred Fish fnf@ninemoons.com
Orjan Friberg orjanf@axis.com
Ben Harris bjh21@netbsd.org
Richard Henderson rth@redhat.com
Aldy Hernandez aldyh@redhat.com
Paul Hilfinger hilfinger@gnat.com
Matt Hiller hiller@redhat.com
Kazu Hirata kazu@hxi.com
Kazu Hirata kazu@cs.umass.edu
Jeff Holcomb jeffh@redhat.com
Don Howard dhoward@redhat.com
Martin Hunt hunt@redhat.com
Jim Ingham jingham@apple.com
Daniel Jacobowitz dan@debian.org
Andreas Jaeger aj@suse.de
Jeff Johnston jjohnstn@redhat.com
Geoff Keating geoffk@redhat.com
Mark Kettenis kettenis@gnu.org
Jim Kingdon jkingdon@engr.sgi.com ++
Jonathan Larmour jlarmour@redhat.co.uk
Jeff Law law@redhat.com
David Lecomber david@streamline-computing.com
Robert Lipe rjl@sco.com
H.J. Lu hjl@lucon.org
Michal Ludvig mludvig@suse.cz
Glen McCready gkm@redhat.com
Greg McGary greg@mcgary.org
Roland McGrath roland@redhat.com
Bryce McKinlay mckinlay@redhat.com
Jason Merrill jason@redhat.com
David S. Miller davem@redhat.com
Mark Mitchell mark@codesourcery.com
Marko Mlinar markom@opencores.org
Alan Modra amodra@bigpond.net.au
Jason Molenda jmolenda@apple.com
Pierre Muller muller@sources.redhat.com
Fernando Nasser fnasser@redhat.com
Hans-Peter Nilsson hp@bitrange.com
David O'Brien obrien@freebsd.org
Alexandre Oliva aoliva@redhat.com
Tom Rix trix@redhat.com
Theodore A. Roth troth@verinet.com
Nick Roberts nick@nick.uklinux.net
Bob Rossi bob_rossi@cox.net
Theodore A. Roth troth@openavr.org
Ian Roxborough irox@redhat.com
Grace Sainsbury graces@redhat.com
Kei Sakamoto sakamoto.kei@renesas.com
Mark Salter msalter@redhat.com
Richard Sandiford rsandifo@redhat.com
Peter Schauer Peter.Schauer@regent
Andreas Schwab schwab@suse.de
Keith Seitz keiths@redhat.com
Stan Shebs shebs@apple.com
Aidan Skinner aidan@velvet.net
Jiri Smid smid@suse.cz
David Smith dsmith@redhat.com
Stephen P. Smith ischis2@home.com
Stephen P. Smith ischis2@cox.net
Jackie Smith Cashion jsmith@redhat.com
Michael Snyder msnyder@redhat.com
Petr Sorfa petrs@caldera.com
Ian Lance Taylor ian@wasabisystems.com
Gary Thomas gthomas@redhat.com
Jason Thorpe thorpej@wasabisystems.com
Tom Tromey tromey@redhat.com
D Venkatasubramanian dvenkat@noida.hcltech.com
Corinna Vinschen vinschen@redhat.com
Keith Walker keith.walker@arm.com
Kris Warkentin kewarken@qnx.com
Ulrich Weigand uweigand@de.ibm.com
Nathan Williams nathanw@wasabisystems.com
Jim Wilson wilson@specifixinc.com
Elena Zannoni ezannoni@redhat.com
Eli Zaretskii eliz@gnu.org
@ -408,12 +426,18 @@ David Taylor (d10v, sparc, utils, defs,
expression evaluator, language support) taylor at candd dot org
J.T. Conklin (dcache, NetBSD, remote) jtc at redback dot com
Frank Ch. Eigler (sim) fche at redhat dot com
Per Bothner (Java) per at bothner dot com
Anthony Green (Java) green at redhat dot com
Fernando Nasser (testsuite/, mi, cli) fnasser at redhat dot com
Mark Salter (testsuite/lib+config) msalter at redhat dot com
Folks that have been caught up in a paper trail:
Chris Faylor cgf@alum.bu.edu
Jim Kingdon jkingdon@engr.sgi.com
David Carlton carlton@bactrian.org
--

View file

@ -1,6 +1,439 @@
What has changed in GDB?
(Organized release by release)
*** Changes in GDB 6.1.1:
* TUI (Text-mode User Interface) built-in (also included in GDB 6.1)
The TUI (Text-mode User Interface) is now built as part of a default
GDB configuration. It is enabled by either selecting the TUI with the
command line option "-i=tui" or by running the separate "gdbtui"
program. For more information on the TUI, see the manual "Debugging
with GDB".
* Pending breakpoint support (also included in GDB 6.1)
Support has been added to allow you to specify breakpoints in shared
libraries that have not yet been loaded. If a breakpoint location
cannot be found, and the "breakpoint pending" option is set to auto,
GDB queries you if you wish to make the breakpoint pending on a future
shared-library load. If and when GDB resolves the breakpoint symbol,
the pending breakpoint is removed as one or more regular breakpoints
are created.
Pending breakpoints are very useful for GCJ Java debugging.
* Fixed ISO-C build problems
The files bfd/elf-bfd.h, gdb/dictionary.c and gdb/types.c contained
non ISO-C code that stopped them being built using a more strict ISO-C
compiler (e.g., IBM's C compiler).
* Fixed build problem on IRIX 5
Due to header problems with <sys/proc.h>, the file gdb/proc-api.c
wasn't able to compile compile on an IRIX 5 system.
* Added execute permission to gdb/gdbserver/configure
The shell script gdb/testsuite/gdb.stabs/configure lacked execute
permission. This bug would cause configure to fail on a number of
systems (Solaris, IRIX). Ref: server/519.
* Fixed build problem on hpux2.0w-hp-hpux11.00 using the HP ANSI C compiler
Older HPUX ANSI C compilers did not accept variable array sizes. somsolib.c
has been updated to use constant array sizes.
* Fixed a panic in the DWARF Call Frame Info code on Solaris 2.7
GCC 3.3.2, on Solaris 2.7, includes the DW_EH_PE_funcrel encoding in
its generated DWARF Call Frame Info. This encoding was causing GDB to
panic, that panic has been fixed. Ref: gdb/1628.
* Fixed a problem when examining parameters in shared library code.
When examining parameters in optimized shared library code generated
by a mainline GCC, GDB would incorrectly report ``Variable "..." is
not available''. GDB now correctly displays the variable's value.
*** Changes in GDB 6.1:
* Removed --with-mmalloc
Support for the mmalloc memory manager has been removed, as it
conflicted with the internal gdb byte cache.
* Changes in AMD64 configurations
The AMD64 target now includes the %cs and %ss registers. As a result
the AMD64 remote protocol has changed; this affects the floating-point
and SSE registers. If you rely on those registers for your debugging,
you should upgrade gdbserver on the remote side.
* Revised SPARC target
The SPARC target has been completely revised, incorporating the
FreeBSD/sparc64 support that was added for GDB 6.0. As a result
support for LynxOS and SunOS 4 has been dropped. Calling functions
from within GDB on operating systems with a non-executable stack
(Solaris, OpenBSD) now works.
* New C++ demangler
GDB has a new C++ demangler which does a better job on the mangled
names generated by current versions of g++. It also runs faster, so
with this and other changes gdb should now start faster on large C++
programs.
* DWARF 2 Location Expressions
GDB support for location expressions has been extended to support function
arguments and frame bases. Older versions of GDB could crash when they
encountered these.
* C++ nested types and namespaces
GDB's support for nested types and namespaces in C++ has been
improved, especially if you use the DWARF 2 debugging format. (This
is the default for recent versions of GCC on most platforms.)
Specifically, if you have a class "Inner" defined within a class or
namespace "Outer", then GDB realizes that the class's name is
"Outer::Inner", not simply "Inner". This should greatly reduce the
frequency of complaints about not finding RTTI symbols. In addition,
if you are stopped at inside of a function defined within a namespace,
GDB modifies its name lookup accordingly.
* New native configurations
NetBSD/amd64 x86_64-*-netbsd*
OpenBSD/amd64 x86_64-*-openbsd*
OpenBSD/alpha alpha*-*-openbsd*
OpenBSD/sparc sparc-*-openbsd*
OpenBSD/sparc64 sparc64-*-openbsd*
* New debugging protocols
M32R with SDI protocol m32r-*-elf*
* "set prompt-escape-char" command deleted.
The command "set prompt-escape-char" has been deleted. This command,
and its very obscure effet on GDB's prompt, was never documented,
tested, nor mentioned in the NEWS file.
* OBSOLETE configurations and files
Configurations that have been declared obsolete in this release have
been commented out. Unless there is activity to revive these
configurations, the next release of GDB will have their sources
permanently REMOVED.
Sun 3, running SunOS 3 m68*-*-sunos3*
Sun 3, running SunOS 4 m68*-*-sunos4*
Sun 2, running SunOS 3 m68000-*-sunos3*
Sun 2, running SunOS 4 m68000-*-sunos4*
Motorola 680x0 running LynxOS m68*-*-lynxos*
AT&T 3b1/Unix pc m68*-att-*
Bull DPX2 (68k, System V release 3) m68*-bull-sysv*
decstation mips-dec-* mips-little-*
riscos mips-*-riscos* mips-*-sysv*
sonymips mips-sony-*
sysv mips*-*-sysv4* (IRIX 5/6 not included)
* REMOVED configurations and files
SGI Irix-4.x mips-sgi-irix4 or iris4
SGI Iris (MIPS) running Irix V3: mips-sgi-irix or iris
Z8000 simulator z8k-zilog-none or z8ksim
Matsushita MN10200 w/simulator mn10200-*-*
H8/500 simulator h8500-hitachi-hms or h8500hms
HP/PA running BSD hppa*-*-bsd*
HP/PA running OSF/1 hppa*-*-osf*
HP/PA Pro target hppa*-*-pro*
PMAX (MIPS) running Mach 3.0 mips*-*-mach3*
386BSD i[3456]86-*-bsd*
Sequent family i[3456]86-sequent-sysv4*
i[3456]86-sequent-sysv*
i[3456]86-sequent-bsd*
SPARC running LynxOS sparc-*-lynxos*
SPARC running SunOS 4 sparc-*-sunos4*
Tsqware Sparclet sparclet-*-*
Fujitsu SPARClite sparclite-fujitsu-none or sparclite
*** Changes in GDB 6.0:
* Objective-C
Support for debugging the Objective-C programming language has been
integrated into GDB.
* New backtrace mechanism (includes DWARF 2 Call Frame Information).
DWARF 2's Call Frame Information makes available compiler generated
information that more exactly describes the program's run-time stack.
By using this information, GDB is able to provide more robust stack
backtraces.
The i386, amd64 (nee, x86-64), Alpha, m68hc11, ia64, and m32r targets
have been updated to use a new backtrace mechanism which includes
DWARF 2 CFI support.
* Hosted file I/O.
GDB's remote protocol has been extended to include support for hosted
file I/O (where the remote target uses GDB's file system). See GDB's
remote protocol documentation for details.
* All targets using the new architecture framework.
All of GDB's targets have been updated to use the new internal
architecture framework. The way is now open for future GDB releases
to include cross-architecture native debugging support (i386 on amd64,
ppc32 on ppc64).
* GNU/Linux's Thread Local Storage (TLS)
GDB now includes support for for the GNU/Linux implementation of
per-thread variables.
* GNU/Linux's Native POSIX Thread Library (NPTL)
GDB's thread code has been updated to work with either the new
GNU/Linux NPTL thread library or the older "LinuxThreads" library.
* Separate debug info.
GDB, in conjunction with BINUTILS, now supports a mechanism for
automatically loading debug information from a separate file. Instead
of shipping full debug and non-debug versions of system libraries,
system integrators can now instead ship just the stripped libraries
and optional debug files.
* DWARF 2 Location Expressions
DWARF 2 Location Expressions allow the compiler to more completely
describe the location of variables (even in optimized code) to the
debugger.
GDB now includes preliminary support for location expressions (support
for DW_OP_piece is still missing).
* Java
A number of long standing bugs that caused GDB to die while starting a
Java application have been fixed. GDB's Java support is now
considered "useable".
* GNU/Linux support for fork, vfork, and exec.
The "catch fork", "catch exec", "catch vfork", and "set follow-fork-mode"
commands are now implemented for GNU/Linux. They require a 2.5.x or later
kernel.
* GDB supports logging output to a file
There are two new commands, "set logging" and "show logging", which can be
used to capture GDB's output to a file.
* The meaning of "detach" has changed for gdbserver
The "detach" command will now resume the application, as documented. To
disconnect from gdbserver and leave it stopped, use the new "disconnect"
command.
* d10v, m68hc11 `regs' command deprecated
The `info registers' command has been updated so that it displays the
registers using a format identical to the old `regs' command.
* Profiling support
A new command, "maint set profile on/off", has been added. This command can
be used to enable or disable profiling while running GDB, to profile a
session or a set of commands. In addition there is a new configure switch,
"--enable-profiling", which will cause GDB to be compiled with profiling
data, for more informative profiling results.
* Default MI syntax changed to "mi2".
The default MI (machine interface) syntax, enabled by the command line
option "-i=mi", has been changed to "mi2". The previous MI syntax,
"mi1", can be enabled by specifying the option "-i=mi1".
Support for the original "mi0" syntax (included in GDB 5.0) has been
removed.
Fix for gdb/192: removed extraneous space when displaying frame level.
Fix for gdb/672: update changelist is now output in mi list format.
Fix for gdb/702: a -var-assign that updates the value now shows up
in a subsequent -var-update.
* New native configurations.
FreeBSD/amd64 x86_64-*-freebsd*
* Multi-arched targets.
HP/PA HPUX11 hppa*-*-hpux*
Renesas M32R/D w/simulator m32r-*-elf*
* OBSOLETE configurations and files
Configurations that have been declared obsolete in this release have
been commented out. Unless there is activity to revive these
configurations, the next release of GDB will have their sources
permanently REMOVED.
Z8000 simulator z8k-zilog-none or z8ksim
Matsushita MN10200 w/simulator mn10200-*-*
H8/500 simulator h8500-hitachi-hms or h8500hms
HP/PA running BSD hppa*-*-bsd*
HP/PA running OSF/1 hppa*-*-osf*
HP/PA Pro target hppa*-*-pro*
PMAX (MIPS) running Mach 3.0 mips*-*-mach3*
Sequent family i[3456]86-sequent-sysv4*
i[3456]86-sequent-sysv*
i[3456]86-sequent-bsd*
Tsqware Sparclet sparclet-*-*
Fujitsu SPARClite sparclite-fujitsu-none or sparclite
* REMOVED configurations and files
V850EA ISA
Motorola Delta 88000 running Sys V m88k-motorola-sysv or delta88
IBM AIX PS/2 i[3456]86-*-aix
i386 running Mach 3.0 i[3456]86-*-mach3*
i386 running Mach i[3456]86-*-mach*
i386 running OSF/1 i[3456]86-*osf1mk*
HP/Apollo 68k Family m68*-apollo*-sysv*,
m68*-apollo*-bsd*,
m68*-hp-bsd*, m68*-hp-hpux*
Argonaut Risc Chip (ARC) arc-*-*
Mitsubishi D30V d30v-*-*
Fujitsu FR30 fr30-*-elf*
OS/9000 i[34]86-*-os9k
I960 with MON960 i960-*-coff
* MIPS $fp behavior changed
The convenience variable $fp, for the MIPS, now consistently returns
the address of the current frame's base. Previously, depending on the
context, $fp could refer to either $sp or the current frame's base
address. See ``8.10 Registers'' in the manual ``Debugging with GDB:
The GNU Source-Level Debugger''.
*** Changes in GDB 5.3:
* GNU/Linux shared library multi-threaded performance improved.
When debugging a multi-threaded application on GNU/Linux, GDB now uses
`/proc', in preference to `ptrace' for memory reads. This may result
in an improvement in the start-up time of multi-threaded, shared
library applications when run under GDB. One GDB user writes: ``loads
shared libs like mad''.
* ``gdbserver'' now supports multi-threaded applications on some targets
Support for debugging multi-threaded applications which use
the GNU/Linux LinuxThreads package has been added for
arm*-*-linux*-gnu*, i[3456]86-*-linux*-gnu*, mips*-*-linux*-gnu*,
powerpc*-*-linux*-gnu*, and sh*-*-linux*-gnu*.
* GDB now supports C/C++ preprocessor macros.
GDB now expands preprocessor macro invocations in C/C++ expressions,
and provides various commands for showing macro definitions and how
they expand.
The new command `macro expand EXPRESSION' expands any macro
invocations in expression, and shows the result.
The new command `show macro MACRO-NAME' shows the definition of the
macro named MACRO-NAME, and where it was defined.
Most compilers don't include information about macros in the debugging
information by default. In GCC 3.1, for example, you need to compile
your program with the options `-gdwarf-2 -g3'. If the macro
information is present in the executable, GDB will read it.
* Multi-arched targets.
DEC Alpha (partial) alpha*-*-*
DEC VAX (partial) vax-*-*
NEC V850 v850-*-*
National Semiconductor NS32000 (partial) ns32k-*-*
Motorola 68000 (partial) m68k-*-*
Motorola MCORE mcore-*-*
* New targets.
Fujitsu FRV architecture added by Red Hat frv*-*-*
* New native configurations
Alpha NetBSD alpha*-*-netbsd*
SH NetBSD sh*-*-netbsdelf*
MIPS NetBSD mips*-*-netbsd*
UltraSPARC NetBSD sparc64-*-netbsd*
* OBSOLETE configurations and files
Configurations that have been declared obsolete in this release have
been commented out. Unless there is activity to revive these
configurations, the next release of GDB will have their sources
permanently REMOVED.
Mitsubishi D30V d30v-*-*
OS/9000 i[34]86-*-os9k
IBM AIX PS/2 i[3456]86-*-aix
Fujitsu FR30 fr30-*-elf*
Motorola Delta 88000 running Sys V m88k-motorola-sysv or delta88
Argonaut Risc Chip (ARC) arc-*-*
i386 running Mach 3.0 i[3456]86-*-mach3*
i386 running Mach i[3456]86-*-mach*
i386 running OSF/1 i[3456]86-*osf1mk*
HP/Apollo 68k Family m68*-apollo*-sysv*,
m68*-apollo*-bsd*,
m68*-hp-bsd*, m68*-hp-hpux*
I960 with MON960 i960-*-coff
* OBSOLETE languages
CHILL, a Pascal like language used by telecommunications companies.
* REMOVED configurations and files
AMD 29k family via UDI a29k-amd-udi, udi29k
A29K VxWorks a29k-*-vxworks
AMD 29000 embedded, using EBMON a29k-none-none
AMD 29000 embedded with COFF a29k-none-coff
AMD 29000 embedded with a.out a29k-none-aout
testsuite/gdb.hp/gdb.threads-hp/ directory
* New command "set max-user-call-depth <nnn>"
This command allows the user to limit the call depth of user-defined
commands. The default is 1024.
* Changes in FreeBSD/i386 native debugging.
Support for the "generate-core-file" has been added.
* New commands "dump", "append", and "restore".
These commands allow data to be copied from target memory
to a bfd-format or binary file (dump and append), and back
from a file into memory (restore).
* Improved "next/step" support on multi-processor Alpha Tru64.
The previous single-step mechanism could cause unpredictable problems,
including the random appearance of SIGSEGV or SIGTRAP signals. The use
of a software single-step mechanism prevents this.
*** Changes in GDB 5.2.1:
* New targets.

View file

@ -1,32 +1,113 @@
Known problems in GDB 5.2
Known problems in GDB 6.1
See also: http://www.gnu.org/software/gdb/bugs/
hppa2.0-hp-hpux10.20
--------------------
*** Build problems
gdb/487: The top level make files used to build GDB are not compatible
with HP/UX make. As a workaround, use GNU make.
build/1458: comple failed on hpux11
gdb/486: The HP/UX C compiler defaults to K&R mode but GDB only builds
with an ISO C compiler. The top level configuration incorrectly sets
CC to `cc' instead of `cc -Ae'. As a workaround, the correct compiler
can be specified as part of the configuration vis:
GDB 6.1 is known to have build problems on HP/UX 11.00 using the
vendor supplied compilers (GDB does build on HP/UX 11.11, and using
GCC).
$ 'CC=cc -Ae' ./configure
*** Misc
gdb/1560: Control-C does not always interrupt GDB.
s390*-*-*
---------
When GDB is busy processing a command which takes a long time to
complete, hitting Control-C does not have the expected effect.
The command execution is not aborted, and the "QUIT" message confirming
the abortion is displayed only after the command has been completed.
gdb/513: GDB does not build on s390 GNU/Linux. The problem should be
fixed in more recent sources.
*** C++ support
gdb/931: GDB could be more generous when reading types C++ templates on input
i386-*-freebsd4.4*
------------------
When the user types a template, GDB frequently requires the type to be
typed in a certain way (e.g. "const char*" as opposed to "const char *"
or "char const *" or "char const*").
gdb/455: GDB doesn't build on a FreeBSD 4.4-STABLE system. The
problem is still being investigated.
gdb/1512: no canonical way to output names of C++ types
We currently don't have any canonical way to output names of C++ types.
E.g. "const char *" versus "char const *"; more subtleties arise when
dealing with templates.
gdb/1516: [regression] local classes, gcc 2.95.3, dwarf-2
With gcc 2.95.3 and the dwarf-2 debugging format, classes which are
defined locally to a function include the demangled name of the function
as part of their name. For example, if a function "foobar" contains a
local class definition "Local", gdb will say that the name of the class
type is "foobar__Fi.0:Local".
This applies only to classes where the class type is defined inside a
function, not to variables defined with types that are defined somewhere
outside any function (which most types are).
gdb/1588: names of c++ nested types in casts must be enclosed in quotes
You must type
(gdb) print ('Foo::Bar') x
or
(gdb) print ('Foo::Bar' *) y
instead of
(gdb) print (Foo::Bar) x
or
(gdb) print (Foo::Bar *) y
respectively.
gdb/1091: Constructor breakpoints ignored
gdb/1193: g++ 3.3 creates multiple constructors: gdb 5.3 can't set breakpoints
When gcc 3.x compiles a C++ constructor or C++ destructor, it generates
2 or 3 different versions of the object code. These versions have
unique mangled names (they have to, in order for linking to work), but
they have identical source code names, which leads to a great deal of
confusion. Specifically, if you set a breakpoint in a constructor or a
destructor, gdb will put a breakpoint in one of the versions, but your
program may execute the other version. This makes it impossible to set
breakpoints reliably in constructors or destructors.
gcc 3.x generates these multiple object code functions in order to
implement virtual base classes. gcc 2.x generated just one object code
function with a hidden parameter, but gcc 3.x conforms to a multi-vendor
ABI for C++ which requires multiple object code functions.
*** Stack backtraces
GDB's core code base has been updated to use a new backtrace
mechanism. This mechanism makes it possible to support new features
such DWARF 2 Call Frame Information (which in turn makes possible
backtraces through optimized code).
Since this code is new, it is known to still have a few problems:
gdb/1505: [regression] gdb prints a bad backtrace for a thread
When backtracing a thread, gdb does not stop when it reaches the
outermost frame, instead continuing until it hits garbage. This is
sensitive to the operating system and thread library.
hppa*-*-*
mips*-*-*
The MIPS and HPPA backtrace code has only very recently been updated
to use GDB's new frame mechanism. At present there are still a few
problems, in particular backtraces through signal handlers do not
work.
People encountering problems with these architectures should consult
GDB's web pages and mailing lists (http://www.gnu.org/software/gdb/)
to see if there are updates.
powerpc*-*-*
PowerPC architecture support, in 6.1, does not use the new frame code.
Fortunately, PowerPC architecture support, in GDB's mainline sources,
have been updated. People encountering problems should consider
downloading a more current snapshot of GDB
(http://www.gnu.org/software/gdb/current/).

View file

@ -1,5 +1,5 @@
README for gdb-5.2.1 release
Updated 19 July, 2002 by Andrew Cagney
README for gdb-6.1 release
Updated 29 February, 2004 by Andrew Cagney
This is GDB, the GNU source-level debugger.
@ -20,7 +20,7 @@ Unpacking and Installation -- quick overview
In this release, the GDB debugger sources, the generic GNU include
files, the BFD ("binary file description") library, the readline
library, and other libraries all have directories of their own
underneath the gdb-5.2.1 directory. The idea is that a variety of GNU
underneath the gdb-6.1 directory. The idea is that a variety of GNU
tools can share a common copy of these things. Be aware of variation
over time--for example don't try to build gdb with a copy of bfd from
a release other than the gdb release (such as a binutils release),
@ -29,8 +29,8 @@ Configuration scripts and makefiles exist to cruise up and down this
directory tree and automatically build all the pieces in the right
order.
When you unpack the gdb-5.2.1.tar.gz file, you'll find a directory
called `gdb-5.2.1', which contains:
When you unpack the gdb-6.1.tar.gz file, you'll find a directory
called `gdb-6.1', which contains:
COPYING config.sub intl missing opcodes
COPYING.LIB configure libiberty mkinstalldirs readline
@ -44,7 +44,7 @@ called `gdb-5.2.1', which contains:
You can build GDB right in the source directory:
cd gdb-5.2.1
cd gdb-6.1
./configure
make
cp gdb/gdb /usr/local/bin/gdb (or wherever you want)
@ -58,18 +58,31 @@ You can build GDB in any empty build directory:
mkdir build
cd build
<full path to your sources>/gdb-5.2.1/configure
<full path to your sources>/gdb-6.1/configure
make
cp gdb/gdb /usr/local/bin/gdb (or wherever you want)
(Building GDB with DJGPP tools for MS-DOS/MS-Windows is slightly
different; see the file gdb-5.2.1/gdb/config/djgpp/README for details.)
different; see the file gdb-6.1/gdb/config/djgpp/README for details.)
This will configure and build all the libraries as well as GDB. If
`configure' can't determine your system type, specify one as its
argument, e.g., `./configure sun4' or `./configure decstation'.
If you get compiler errors during this stage, see the `Reporting
Make sure that your 'configure' line ends in 'gdb-6.1/configure':
/berman/migchain/source/gdb-6.1/configure # RIGHT
/berman/migchain/source/gdb-6.1/gdb/configure # WRONG
The gdb package contains several subdirectories, such as 'gdb',
'bfd', and 'readline'. If your 'configure' line ends in
'gdb-6.1/gdb/configure', then you are configuring only the gdb
subdirectory, not the whole gdb package. This leads to build errors
such as:
make: *** No rule to make target `../bfd/bfd.h', needed by `gdb.o'. Stop.
If you get other compiler errors during this stage, see the `Reporting
Bugs' section below; there are a few known problems.
GDB requires an ISO C (ANSI C) compiler. If you do not have an ISO
@ -94,7 +107,7 @@ documentation and TeX (or `texi2roff') to typeset the printed version.
GDB includes an already formatted copy of the on-line Info version
of this manual in the `gdb/doc' subdirectory. The main Info file is
`gdb-5.2.1/gdb/doc/gdb.info', and it refers to subordinate files
`gdb-6.1/gdb/doc/gdb.info', and it refers to subordinate files
matching `gdb.info*' in the same directory. If necessary, you can
print out these files, or read them with any editor; but they are
easier to read using the `info' subsystem in GNU Emacs or the
@ -106,7 +119,7 @@ Info formatting programs, such as `texinfo-format-buffer' or
`makeinfo'.
If you have `makeinfo' installed, and are in the top level GDB
source directory (`gdb-5.2.1', in the case of version 5.2.1), you can make
source directory (`gdb-6.1', in the case of version 6.1), you can make
the Info file by typing:
cd gdb/doc
@ -115,7 +128,7 @@ the Info file by typing:
If you want to typeset and print copies of this manual, you need
TeX, a program to print its DVI output files, and `texinfo.tex', the
Texinfo definitions file. This file is included in the GDB
distribution, in the directory `gdb-5.2.1/texinfo'.
distribution, in the directory `gdb-6.1/texinfo'.
TeX is a typesetting program; it does not print files directly, but
produces output files called DVI files. To print a typeset document,
@ -129,11 +142,11 @@ without any extension or a `.dvi' extension.
This file tells TeX how to typeset a document written in Texinfo
format. On its own, TeX cannot read, much less typeset a Texinfo file.
`texinfo.tex' is distributed with GDB and is located in the
`gdb-5.2.1/texinfo' directory.
`gdb-6.1/texinfo' directory.
If you have TeX and a DVI printer program installed, you can typeset
and print this manual. First switch to the the `gdb' subdirectory of
the main source directory (for example, to `gdb-5.2.1/gdb') and then type:
the main source directory (for example, to `gdb-6.1/gdb') and then type:
make doc/gdb.dvi
@ -156,55 +169,55 @@ preparing GDB for installation; you can then use `make' to build the
a single directory, whose name is usually composed by appending the
version number to `gdb'.
For example, the GDB version 5.2.1 distribution is in the `gdb-5.2.1'
For example, the GDB version 6.1 distribution is in the `gdb-6.1'
directory. That directory contains:
`gdb-5.2.1/{COPYING,COPYING.LIB}'
`gdb-6.1/{COPYING,COPYING.LIB}'
Standard GNU license files. Please read them.
`gdb-5.2.1/bfd'
`gdb-6.1/bfd'
source for the Binary File Descriptor library
`gdb-5.2.1/config*'
`gdb-6.1/config*'
script for configuring GDB, along with other support files
`gdb-5.2.1/gdb'
`gdb-6.1/gdb'
the source specific to GDB itself
`gdb-5.2.1/include'
`gdb-6.1/include'
GNU include files
`gdb-5.2.1/libiberty'
`gdb-6.1/libiberty'
source for the `-liberty' free software library
`gdb-5.2.1/mmalloc'
`gdb-6.1/mmalloc'
source for the GNU memory-mapped malloc package
`gdb-5.2.1/opcodes'
`gdb-6.1/opcodes'
source for the library of opcode tables and disassemblers
`gdb-5.2.1/readline'
`gdb-6.1/readline'
source for the GNU command-line interface
NOTE: The readline library is compiled for use by GDB, but will
not be installed on your system when "make install" is issued.
`gdb-5.2.1/sim'
`gdb-6.1/sim'
source for some simulators (ARM, D10V, SPARC, M32R, MIPS, PPC, V850, etc)
`gdb-5.2.1/intl'
`gdb-6.1/intl'
source for the GNU gettext library, for internationalization.
This is slightly modified from the standalone gettext
distribution you can get from GNU.
`gdb-5.2.1/texinfo'
`gdb-6.1/texinfo'
The `texinfo.tex' file, which you need in order to make a printed
manual using TeX.
`gdb-5.2.1/etc'
`gdb-6.1/etc'
Coding standards, useful files for editing GDB, and other
miscellanea.
`gdb-5.2.1/utils'
`gdb-6.1/utils'
A grab bag of random utilities.
Note: the following instructions are for building GDB on Unix or
@ -213,14 +226,14 @@ MS-DOS/MS-Windows are in the file gdb/config/djgpp/README.
The simplest way to configure and build GDB is to run `configure'
from the `gdb-VERSION-NUMBER' source directory, which in this example
is the `gdb-5.2.1' directory.
is the `gdb-6.1' directory.
First switch to the `gdb-VERSION-NUMBER' source directory if you are
not already in it; then run `configure'.
For example:
cd gdb-5.2.1
cd gdb-6.1
./configure
make
@ -236,8 +249,8 @@ you may need to run `sh' on it explicitly:
sh configure
If you run `configure' from a directory that contains source
directories for multiple libraries or programs, such as the `gdb-5.2.1'
source directory for version 5.2.1, `configure' creates configuration
directories for multiple libraries or programs, such as the `gdb-6.1'
source directory for version 6.1, `configure' creates configuration
files for every directory level underneath (unless you tell it not to,
with the `--norecursion' option).
@ -245,10 +258,10 @@ with the `--norecursion' option).
directories in the GDB distribution, if you only want to configure that
subdirectory; but be sure to specify a path to it.
For example, with version 5.2.1, type the following to configure only
For example, with version 6.1, type the following to configure only
the `bfd' subdirectory:
cd gdb-5.2.1/bfd
cd gdb-6.1/bfd
../configure
You can install `gdb' anywhere; it has no hardwired paths. However,
@ -277,13 +290,13 @@ directory. If the path to `configure' would be the same as the
argument to `--srcdir', you can leave out the `--srcdir' option; it
will be assumed.)
For example, with version 5.2.1, you can build GDB in a separate
For example, with version 6.1, you can build GDB in a separate
directory for a Sun 4 like this:
cd gdb-5.2.1
cd gdb-6.1
mkdir ../gdb-sun4
cd ../gdb-sun4
../gdb-5.2.1/configure
../gdb-6.1/configure
make
When `configure' builds a configuration using a remote source
@ -304,8 +317,8 @@ called `configure' (or one of its subdirectories).
The `Makefile' that `configure' generates in each source directory
also runs recursively. If you type `make' in a source directory such
as `gdb-5.2.1' (or in a separate configured directory configured with
`--srcdir=PATH/gdb-5.2.1'), you will build all the required libraries,
as `gdb-6.1' (or in a separate configured directory configured with
`--srcdir=PATH/gdb-6.1'), you will build all the required libraries,
and then build GDB.
When you have multiple hosts or targets configured in separate
@ -348,7 +361,7 @@ you can use it to test your guesses on abbreviations--for example:
Invalid configuration `i786v': machine `i786v' not recognized
`config.sub' is also distributed in the GDB source directory
(`gdb-5.2.1', for version 5.2.1).
(`gdb-6.1', for version 6.1).
`configure' options
@ -449,25 +462,15 @@ Linux.
There are a number of remote interfaces for talking to existing ROM
monitors and other hardware:
remote-adapt.c AMD 29000 "Adapt"
remote-array.c Array Tech RAID controller
remote-bug.c Motorola BUG monitor
remote-e7000.c Hitachi E7000 ICE
remote-eb.c AMD 29000 "EBMON"
remote-es.c Ericsson 1800 monitor
remote-e7000.c Renesas E7000 ICE
remote-est.c EST emulator
remote-hms.c Hitachi Micro Systems H8/300 monitor
remote-hms.c Renesas Micro Systems H8/300 monitor
remote-mips.c MIPS remote debugging protocol
remote-mm.c AMD 29000 "minimon"
remote-nindy.c Intel 960 "Nindy"
remote-nrom.c NetROM ROM emulator
remote-os9k.c PC running OS/9000
remote-rdi.c ARM with Angel monitor
remote-rdp.c ARM with Demon monitor
remote-sds.c PowerPC SDS monitor
remote-sim.c Generalized simulator protocol
remote-st.c Tandem ST-2000 monitor
remote-udi.c AMD 29000 using the AMD "Universal Debug Interface"
remote-vx.c VxWorks realtime kernel
Remote-vx.c and the vx-share subdirectory contain a remote
@ -475,14 +478,6 @@ interface for the VxWorks realtime kernel, which communicates over TCP
using the Sun RPC library. This would be a useful starting point for
other remote- via-ethernet back ends.
Remote-udi.c and the 29k-share subdirectory contain a remote
interface for AMD 29000 programs, which uses the AMD "Universal Debug
Interface". This allows GDB to talk to software simulators,
emulators, and/or bare hardware boards, via network or serial
interfaces. Note that GDB only provides an interface that speaks UDI,
not a complete solution. You will need something on the other end
that also speaks UDI.
Reporting Bugs in GDB
=====================
@ -496,7 +491,7 @@ As an alternative, the bug report can be submitted, via e-mail, to the
address "bug-gdb@gnu.org".
When submitting a bug, please include the GDB version number (e.g.,
gdb-5.2.1), and how you configured it (e.g., "sun4" or "mach386 host,
gdb-6.1), and how you configured it (e.g., "sun4" or "mach386 host,
i586-intel-synopsys target"). Since GDB now supports so many
different configurations, it is important that you be precise about
this. If at all possible, you should include the actual banner that
@ -513,7 +508,7 @@ Graphical interface to GDB -- X Windows, MS Windows
Several graphical interfaces to GDB are available. You should
check:
http://www.gnu.org/software/gdb/gui/
http://www.gnu.org/software/gdb/links/
for an up-to-date list.
@ -551,17 +546,17 @@ ftp://sources.redhat.com/pub/dejagnu/ will contain a recent snapshot.
Once DejaGNU is installed, you can run the tests in one of the
following ways:
(1) cd gdb-5.2.1
(1) cd gdb-6.1
make check-gdb
or
(2) cd gdb-5.2.1/gdb
(2) cd gdb-6.1/gdb
make check
or
(3) cd gdb-5.2.1/gdb/testsuite
(3) cd gdb-6.1/gdb/testsuite
make site.exp (builds the site specific file)
runtest -tool gdb GDB=../gdb (or GDB=<somepath> as appropriate)

View file

@ -114,12 +114,6 @@ The following cleanups have been identified as part of GDB 5.2.
--
Remove old code that does not use ui_out functions and all the related
"ifdef"s. This also allows the elimination of -DUI_OUT from
Makefile.in and configure.in.
--
Compiler warnings.
Eliminate warnings for all targets on at least one host for one of the
@ -177,14 +171,6 @@ Deprecate, if not delete, the following:
how it relates to rawreg and the
regnum is clear.
REGISTER_BYTES
The size of the cache can be computed
on the fly.
IS_TRAPPED_INTERNALVAR
The pseudo registers should eventually make
this redundant.
--
Obsolete the targets:
@ -247,10 +233,6 @@ New languages come onto the scene all the time.
Re: Various C++ things
value_headof/value_from_vtable_info are worthless, and should be
removed. The one place in printcmd.c that uses it should use the RTTI
functions.
RTTI for g++ should be using the typeinfo functions rather than the
vtables. The typeinfo functions are always at offset 4 from the
beginning of the vtable, and are always right. The vtables will have

View file

@ -259,6 +259,7 @@ dnl not used, don't export to save symbols
AC_SUBST(TCL_LD_FLAGS)
dnl don't export, not used outside of configure
AC_SUBST(TCL_LD_SEARCH_FLAGS)
AC_SUBST(TCL_CC_SEARCH_FLAGS)
AC_SUBST(TCL_COMPAT_OBJS)
AC_SUBST(TCL_RANLIB)
AC_SUBST(TCL_BUILD_LIB_SPEC)
@ -733,132 +734,6 @@ AC_SUBST(ITKHDIR)
#AC_SUBST(ITKLIB)
])
# check for Tix headers.
AC_DEFUN(CY_AC_PATH_TIXH, [
AC_MSG_CHECKING(for Tix private headers. srcdir=${srcdir})
if test x"${ac_cv_c_tixh}" = x ; then
for i in ${srcdir}/../tix ${srcdir}/../../tix ${srcdir}/../../../tix ; do
if test -f $i/generic/tix.h ; then
ac_cv_c_tixh=`(cd $i/generic; pwd)`
break
fi
done
fi
if test x"${ac_cv_c_tixh}" = x ; then
TIXHDIR="# no Tix private headers found"
AC_MSG_ERROR([Can't find Tix private headers])
fi
if test x"${ac_cv_c_tixh}" != x ; then
TIXHDIR="-I${ac_cv_c_tixh}"
fi
AC_SUBST(TIXHDIR)
])
AC_DEFUN(CY_AC_PATH_TIXCONFIG, [
#
# Ok, lets find the tix configuration
# First, look for one uninstalled.
# the alternative search directory is invoked by --with-itkconfig
#
if test x"${no_tix}" = x ; then
# we reset no_tix in case something fails here
no_tix=true
AC_ARG_WITH(tixconfig, [ --with-tixconfig Directory containing tix configuration (tixConfig.sh)],
with_tixconfig=${withval})
AC_MSG_CHECKING([for Tix configuration])
AC_CACHE_VAL(ac_cv_c_tixconfig,[
# First check to see if --with-tixconfig was specified.
if test x"${with_tixconfig}" != x ; then
if test -f "${with_tixconfig}/tixConfig.sh" ; then
ac_cv_c_tixconfig=`(cd ${with_tixconfig}; pwd)`
else
AC_MSG_ERROR([${with_tixconfig} directory doesn't contain tixConfig.sh])
fi
fi
# then check for a private Tix library
if test x"${ac_cv_c_tixconfig}" = x ; then
for i in \
../tix \
`ls -dr ../tix 2>/dev/null` \
../../tix \
`ls -dr ../../tix 2>/dev/null` \
../../../tix \
`ls -dr ../../../tix 2>/dev/null` ; do
echo "**** Looking at $i - with ${configdir}"
if test -f "$i/tixConfig.sh" ; then
ac_cv_c_tixconfig=`(cd $i; pwd)`
break
fi
done
fi
# check in a few common install locations
if test x"${ac_cv_c_tixconfig}" = x ; then
for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
echo "**** Looking at $i"
if test -f "$i/tixConfig.sh" ; then
ac_cv_c_tixconfig=`(cd $i; pwd)`
break
fi
done
fi
# check in a few other private locations
echo "**** Other private locations"
if test x"${ac_cv_c_tixconfig}" = x ; then
for i in \
${srcdir}/../tix \
`ls -dr ${srcdir}/../tix 2>/dev/null` ; do
echo "**** Looking at $i - with ${configdir}"
if test -f "$i/${configdir}/tixConfig.sh" ; then
ac_cv_c_tixconfig=`(cd $i/${configdir}; pwd)`
break
fi
done
fi
])
if test x"${ac_cv_c_tixconfig}" = x ; then
TIXCONFIG="# no Tix configs found"
AC_MSG_WARN(Can't find Tix configuration definitions)
else
no_tix=
TIXCONFIG=${ac_cv_c_tixconfig}/tixConfig.sh
AC_MSG_RESULT(found $TIXCONFIG)
fi
fi
])
# Defined as a separate macro so we don't have to cache the values
# from PATH_TIXCONFIG (because this can also be cached).
AC_DEFUN(CY_AC_LOAD_TIXCONFIG, [
if test -f "$TIXCONFIG" ; then
. $TIXCONFIG
fi
AC_SUBST(TIX_VERSION)
dnl not actually used, don't export to save symbols
dnl AC_SUBST(TIX_MAJOR_VERSION)
dnl AC_SUBST(TIX_MINOR_VERSION)
dnl AC_SUBST(TIX_DEFS)
dnl not used, don't export to save symbols
dnl dnl AC_SUBST(TIX_LIB_FILE)
dnl not used outside of configure
dnl AC_SUBST(TIX_LIBS)
dnl not used, don't export to save symbols
dnl AC_SUBST(TIX_PREFIX)
dnl not used, don't export to save symbols
dnl AC_SUBST(TIX_EXEC_PREFIX)
dnl AC_SUBST(TIX_BUILD_INCLUDES)
AC_SUBST(TIX_BUILD_LIB_SPEC)
dnl AC_SUBST(TIX_LIB_SPEC)
])
dnl sinclude(../gettext.m4) already included by bfd/acinclude.m4
dnl The lines below arrange for aclocal not to bring gettext.m4's
@ -976,3 +851,148 @@ case "x$am_cv_prog_cc_stdc" in
*) CC="$CC $am_cv_prog_cc_stdc" ;;
esac
])
dnl From Bruno Haible.
AC_DEFUN([AM_ICONV],
[
dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
dnl those with the standalone portable GNU libiconv installed).
AC_ARG_WITH([libiconv-prefix],
[ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [
for dir in `echo "$withval" | tr : ' '`; do
if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi
if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi
done
])
AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
am_cv_func_iconv="no, consider installing GNU libiconv"
am_cv_lib_iconv=no
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_func_iconv=yes)
if test "$am_cv_func_iconv" != yes; then
am_save_LIBS="$LIBS"
LIBS="$LIBS -liconv"
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_lib_iconv=yes
am_cv_func_iconv=yes)
LIBS="$am_save_LIBS"
fi
])
if test "$am_cv_func_iconv" = yes; then
AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
AC_MSG_CHECKING([for iconv declaration])
AC_CACHE_VAL(am_cv_proto_iconv, [
AC_TRY_COMPILE([
#include <stdlib.h>
#include <iconv.h>
extern
#ifdef __cplusplus
"C"
#endif
#if defined(__STDC__) || defined(__cplusplus)
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
#else
size_t iconv();
#endif
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
AC_MSG_RESULT([$]{ac_t:-
}[$]am_cv_proto_iconv)
AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
[Define as const if the declaration of iconv() needs const.])
fi
LIBICONV=
if test "$am_cv_lib_iconv" = yes; then
LIBICONV="-liconv"
fi
AC_SUBST(LIBICONV)
])
# AC_GNU_SOURCE
# -------------
# FIXME: Remove thise once we start using Autoconf 2.5x (x>=4).
AC_DEFUN([AC_GNU_SOURCE],
[AC_BEFORE([$0], [AC_TRY_COMPILE])dnl
AC_BEFORE([$0], [AC_TRY_RUN])dnl
AC_DEFINE([_GNU_SOURCE])
])
dnl written by Guido Draheim <guidod@gmx.de>, original by Alexandre Oliva
dnl Version 1.3 (2001/03/02)
dnl source http://www.gnu.org/software/ac-archive/Miscellaneous/ac_define_dir.html
AC_DEFUN([AC_DEFINE_DIR], [
test "x$prefix" = xNONE && prefix="$ac_default_prefix"
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
ac_define_dir=`eval echo [$]$2`
ac_define_dir=`eval echo [$]ac_define_dir`
ifelse($3, ,
AC_DEFINE_UNQUOTED($1, "$ac_define_dir"),
AC_DEFINE_UNQUOTED($1, "$ac_define_dir", $3))
])
dnl See whether we need a declaration for a function.
dnl The result is highly dependent on the INCLUDES passed in, so make sure
dnl to use a different cache variable name in this macro if it is invoked
dnl in a different context somewhere else.
dnl gcc_AC_CHECK_DECL(SYMBOL,
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]])
AC_DEFUN(gcc_AC_CHECK_DECL,
[AC_MSG_CHECKING([whether $1 is declared])
AC_CACHE_VAL(gcc_cv_have_decl_$1,
[AC_TRY_COMPILE([$4],
[#ifndef $1
char *(*pfn) = (char *(*)) $1 ;
#endif], eval "gcc_cv_have_decl_$1=yes", eval "gcc_cv_have_decl_$1=no")])
if eval "test \"`echo '$gcc_cv_have_decl_'$1`\" = yes"; then
AC_MSG_RESULT(yes) ; ifelse([$2], , :, [$2])
else
AC_MSG_RESULT(no) ; ifelse([$3], , :, [$3])
fi
])dnl
dnl Check multiple functions to see whether each needs a declaration.
dnl Arrange to define HAVE_DECL_<FUNCTION> to 0 or 1 as appropriate.
dnl gcc_AC_CHECK_DECLS(SYMBOLS,
dnl [ACTION-IF-NEEDED [, ACTION-IF-NOT-NEEDED [, INCLUDES]]])
AC_DEFUN(gcc_AC_CHECK_DECLS,
[for ac_func in $1
do
changequote(, )dnl
ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
changequote([, ])dnl
gcc_AC_CHECK_DECL($ac_func,
[AC_DEFINE_UNQUOTED($ac_tr_decl, 1) $2],
[AC_DEFINE_UNQUOTED($ac_tr_decl, 0) $3],
dnl It is possible that the include files passed in here are local headers
dnl which supply a backup declaration for the relevant prototype based on
dnl the definition of (or lack of) the HAVE_DECL_ macro. If so, this test
dnl will always return success. E.g. see libiberty.h's handling of
dnl `basename'. To avoid this, we define the relevant HAVE_DECL_ macro to
dnl 1 so that any local headers used do not provide their own prototype
dnl during this test.
#undef $ac_tr_decl
#define $ac_tr_decl 1
$4
)
done
dnl Automatically generate config.h entries via autoheader.
if test x = y ; then
patsubst(translit([$1], [a-z], [A-Z]), [\w+],
[AC_DEFINE([HAVE_DECL_\&], 1,
[Define to 1 if we found this declaration otherwise define to 0.])])dnl
fi
])

View file

@ -271,6 +271,7 @@ dnl not used, don't export to save symbols
AC_SUBST(TCL_LD_FLAGS)
dnl don't export, not used outside of configure
AC_SUBST(TCL_LD_SEARCH_FLAGS)
AC_SUBST(TCL_CC_SEARCH_FLAGS)
AC_SUBST(TCL_COMPAT_OBJS)
AC_SUBST(TCL_RANLIB)
AC_SUBST(TCL_BUILD_LIB_SPEC)
@ -745,132 +746,6 @@ AC_SUBST(ITKHDIR)
#AC_SUBST(ITKLIB)
])
# check for Tix headers.
AC_DEFUN(CY_AC_PATH_TIXH, [
AC_MSG_CHECKING(for Tix private headers. srcdir=${srcdir})
if test x"${ac_cv_c_tixh}" = x ; then
for i in ${srcdir}/../tix ${srcdir}/../../tix ${srcdir}/../../../tix ; do
if test -f $i/generic/tix.h ; then
ac_cv_c_tixh=`(cd $i/generic; pwd)`
break
fi
done
fi
if test x"${ac_cv_c_tixh}" = x ; then
TIXHDIR="# no Tix private headers found"
AC_MSG_ERROR([Can't find Tix private headers])
fi
if test x"${ac_cv_c_tixh}" != x ; then
TIXHDIR="-I${ac_cv_c_tixh}"
fi
AC_SUBST(TIXHDIR)
])
AC_DEFUN(CY_AC_PATH_TIXCONFIG, [
#
# Ok, lets find the tix configuration
# First, look for one uninstalled.
# the alternative search directory is invoked by --with-itkconfig
#
if test x"${no_tix}" = x ; then
# we reset no_tix in case something fails here
no_tix=true
AC_ARG_WITH(tixconfig, [ --with-tixconfig Directory containing tix configuration (tixConfig.sh)],
with_tixconfig=${withval})
AC_MSG_CHECKING([for Tix configuration])
AC_CACHE_VAL(ac_cv_c_tixconfig,[
# First check to see if --with-tixconfig was specified.
if test x"${with_tixconfig}" != x ; then
if test -f "${with_tixconfig}/tixConfig.sh" ; then
ac_cv_c_tixconfig=`(cd ${with_tixconfig}; pwd)`
else
AC_MSG_ERROR([${with_tixconfig} directory doesn't contain tixConfig.sh])
fi
fi
# then check for a private Tix library
if test x"${ac_cv_c_tixconfig}" = x ; then
for i in \
../tix \
`ls -dr ../tix 2>/dev/null` \
../../tix \
`ls -dr ../../tix 2>/dev/null` \
../../../tix \
`ls -dr ../../../tix 2>/dev/null` ; do
echo "**** Looking at $i - with ${configdir}"
if test -f "$i/tixConfig.sh" ; then
ac_cv_c_tixconfig=`(cd $i; pwd)`
break
fi
done
fi
# check in a few common install locations
if test x"${ac_cv_c_tixconfig}" = x ; then
for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
echo "**** Looking at $i"
if test -f "$i/tixConfig.sh" ; then
ac_cv_c_tixconfig=`(cd $i; pwd)`
break
fi
done
fi
# check in a few other private locations
echo "**** Other private locations"
if test x"${ac_cv_c_tixconfig}" = x ; then
for i in \
${srcdir}/../tix \
`ls -dr ${srcdir}/../tix 2>/dev/null` ; do
echo "**** Looking at $i - with ${configdir}"
if test -f "$i/${configdir}/tixConfig.sh" ; then
ac_cv_c_tixconfig=`(cd $i/${configdir}; pwd)`
break
fi
done
fi
])
if test x"${ac_cv_c_tixconfig}" = x ; then
TIXCONFIG="# no Tix configs found"
AC_MSG_WARN(Can't find Tix configuration definitions)
else
no_tix=
TIXCONFIG=${ac_cv_c_tixconfig}/tixConfig.sh
AC_MSG_RESULT(found $TIXCONFIG)
fi
fi
])
# Defined as a separate macro so we don't have to cache the values
# from PATH_TIXCONFIG (because this can also be cached).
AC_DEFUN(CY_AC_LOAD_TIXCONFIG, [
if test -f "$TIXCONFIG" ; then
. $TIXCONFIG
fi
AC_SUBST(TIX_VERSION)
dnl not actually used, don't export to save symbols
dnl AC_SUBST(TIX_MAJOR_VERSION)
dnl AC_SUBST(TIX_MINOR_VERSION)
dnl AC_SUBST(TIX_DEFS)
dnl not used, don't export to save symbols
dnl dnl AC_SUBST(TIX_LIB_FILE)
dnl not used outside of configure
dnl AC_SUBST(TIX_LIBS)
dnl not used, don't export to save symbols
dnl AC_SUBST(TIX_PREFIX)
dnl not used, don't export to save symbols
dnl AC_SUBST(TIX_EXEC_PREFIX)
dnl AC_SUBST(TIX_BUILD_INCLUDES)
AC_SUBST(TIX_BUILD_LIB_SPEC)
dnl AC_SUBST(TIX_LIB_SPEC)
])
dnl sinclude(../gettext.m4) already included by bfd/acinclude.m4
dnl The lines below arrange for aclocal not to bring gettext.m4's
@ -985,6 +860,151 @@ case "x$am_cv_prog_cc_stdc" in
esac
])
dnl From Bruno Haible.
AC_DEFUN([AM_ICONV],
[
dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
dnl those with the standalone portable GNU libiconv installed).
AC_ARG_WITH([libiconv-prefix],
[ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [
for dir in `echo "$withval" | tr : ' '`; do
if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi
if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi
done
])
AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
am_cv_func_iconv="no, consider installing GNU libiconv"
am_cv_lib_iconv=no
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_func_iconv=yes)
if test "$am_cv_func_iconv" != yes; then
am_save_LIBS="$LIBS"
LIBS="$LIBS -liconv"
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_lib_iconv=yes
am_cv_func_iconv=yes)
LIBS="$am_save_LIBS"
fi
])
if test "$am_cv_func_iconv" = yes; then
AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
AC_MSG_CHECKING([for iconv declaration])
AC_CACHE_VAL(am_cv_proto_iconv, [
AC_TRY_COMPILE([
#include <stdlib.h>
#include <iconv.h>
extern
#ifdef __cplusplus
"C"
#endif
#if defined(__STDC__) || defined(__cplusplus)
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
#else
size_t iconv();
#endif
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
AC_MSG_RESULT([$]{ac_t:-
}[$]am_cv_proto_iconv)
AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
[Define as const if the declaration of iconv() needs const.])
fi
LIBICONV=
if test "$am_cv_lib_iconv" = yes; then
LIBICONV="-liconv"
fi
AC_SUBST(LIBICONV)
])
# AC_GNU_SOURCE
# -------------
# FIXME: Remove thise once we start using Autoconf 2.5x (x>=4).
AC_DEFUN([AC_GNU_SOURCE],
[AC_BEFORE([$0], [AC_TRY_COMPILE])dnl
AC_BEFORE([$0], [AC_TRY_RUN])dnl
AC_DEFINE([_GNU_SOURCE])
])
dnl written by Guido Draheim <guidod@gmx.de>, original by Alexandre Oliva
dnl Version 1.3 (2001/03/02)
dnl source http://www.gnu.org/software/ac-archive/Miscellaneous/ac_define_dir.html
AC_DEFUN([AC_DEFINE_DIR], [
test "x$prefix" = xNONE && prefix="$ac_default_prefix"
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
ac_define_dir=`eval echo [$]$2`
ac_define_dir=`eval echo [$]ac_define_dir`
ifelse($3, ,
AC_DEFINE_UNQUOTED($1, "$ac_define_dir"),
AC_DEFINE_UNQUOTED($1, "$ac_define_dir", $3))
])
dnl See whether we need a declaration for a function.
dnl The result is highly dependent on the INCLUDES passed in, so make sure
dnl to use a different cache variable name in this macro if it is invoked
dnl in a different context somewhere else.
dnl gcc_AC_CHECK_DECL(SYMBOL,
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]])
AC_DEFUN(gcc_AC_CHECK_DECL,
[AC_MSG_CHECKING([whether $1 is declared])
AC_CACHE_VAL(gcc_cv_have_decl_$1,
[AC_TRY_COMPILE([$4],
[#ifndef $1
char *(*pfn) = (char *(*)) $1 ;
#endif], eval "gcc_cv_have_decl_$1=yes", eval "gcc_cv_have_decl_$1=no")])
if eval "test \"`echo '$gcc_cv_have_decl_'$1`\" = yes"; then
AC_MSG_RESULT(yes) ; ifelse([$2], , :, [$2])
else
AC_MSG_RESULT(no) ; ifelse([$3], , :, [$3])
fi
])dnl
dnl Check multiple functions to see whether each needs a declaration.
dnl Arrange to define HAVE_DECL_<FUNCTION> to 0 or 1 as appropriate.
dnl gcc_AC_CHECK_DECLS(SYMBOLS,
dnl [ACTION-IF-NEEDED [, ACTION-IF-NOT-NEEDED [, INCLUDES]]])
AC_DEFUN(gcc_AC_CHECK_DECLS,
[for ac_func in $1
do
changequote(, )dnl
ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
changequote([, ])dnl
gcc_AC_CHECK_DECL($ac_func,
[AC_DEFINE_UNQUOTED($ac_tr_decl, 1) $2],
[AC_DEFINE_UNQUOTED($ac_tr_decl, 0) $3],
dnl It is possible that the include files passed in here are local headers
dnl which supply a backup declaration for the relevant prototype based on
dnl the definition of (or lack of) the HAVE_DECL_ macro. If so, this test
dnl will always return success. E.g. see libiberty.h's handling of
dnl `basename'. To avoid this, we define the relevant HAVE_DECL_ macro to
dnl 1 so that any local headers used do not provide their own prototype
dnl during this test.
#undef $ac_tr_decl
#define $ac_tr_decl 1
$4
)
done
dnl Automatically generate config.h entries via autoheader.
if test x = y ; then
patsubst(translit([$1], [a-z], [A-Z]), [\w+],
[AC_DEFINE([HAVE_DECL_\&], 1,
[Define to 1 if we found this declaration otherwise define to 0.])])dnl
fi
])
# Add --enable-maintainer-mode option to configure.
# From Jim Meyering

2642
contrib/gdb/gdb/ada-exp.c Normal file

File diff suppressed because it is too large Load diff

969
contrib/gdb/gdb/ada-exp.y Normal file
View file

@ -0,0 +1,969 @@
/* YACC parser for Ada expressions, for GDB.
Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994, 1997, 2000, 2003
Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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. */
/* Parse an Ada expression from text in a string,
and return the result as a struct expression pointer.
That structure contains arithmetic operations in reverse polish,
with constants represented by operations that are followed by special data.
See expression.h for the details of the format.
What is important here is that it can be built up sequentially
during the process of parsing; the lower levels of the tree always
come first in the result.
malloc's and realloc's in this file are transformed to
xmalloc and xrealloc respectively by the same sed command in the
makefile that remaps any other malloc/realloc inserted by the parser
generator. Doing this with #defines and trying to control the interaction
with include files (<malloc.h> and <stdlib.h> for example) just became
too messy, particularly when such includes can be inserted at random
times by the parser generator. */
%{
#include "defs.h"
#include <string.h>
#include <ctype.h>
#include "expression.h"
#include "value.h"
#include "parser-defs.h"
#include "language.h"
#include "ada-lang.h"
#include "bfd.h" /* Required by objfiles.h. */
#include "symfile.h" /* Required by objfiles.h. */
#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
#include "frame.h"
#include "block.h"
/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
as well as gratuitiously global symbol names, so we can have multiple
yacc generated parsers in gdb. These are only the variables
produced by yacc. If other parser generators (bison, byacc, etc) produce
additional global names that conflict at link time, then those parser
generators need to be fixed instead of adding those names to this list. */
/* NOTE: This is clumsy, especially since BISON and FLEX provide --prefix
options. I presume we are maintaining it to accommodate systems
without BISON? (PNH) */
#define yymaxdepth ada_maxdepth
#define yyparse _ada_parse /* ada_parse calls this after initialization */
#define yylex ada_lex
#define yyerror ada_error
#define yylval ada_lval
#define yychar ada_char
#define yydebug ada_debug
#define yypact ada_pact
#define yyr1 ada_r1
#define yyr2 ada_r2
#define yydef ada_def
#define yychk ada_chk
#define yypgo ada_pgo
#define yyact ada_act
#define yyexca ada_exca
#define yyerrflag ada_errflag
#define yynerrs ada_nerrs
#define yyps ada_ps
#define yypv ada_pv
#define yys ada_s
#define yy_yys ada_yys
#define yystate ada_state
#define yytmp ada_tmp
#define yyv ada_v
#define yy_yyv ada_yyv
#define yyval ada_val
#define yylloc ada_lloc
#define yyreds ada_reds /* With YYDEBUG defined */
#define yytoks ada_toks /* With YYDEBUG defined */
#define yyname ada_name /* With YYDEBUG defined */
#define yyrule ada_rule /* With YYDEBUG defined */
#ifndef YYDEBUG
#define YYDEBUG 1 /* Default to yydebug support */
#endif
#define YYFPRINTF parser_fprintf
struct name_info {
struct symbol* sym;
struct minimal_symbol* msym;
struct block* block;
struct stoken stoken;
};
/* If expression is in the context of TYPE'(...), then TYPE, else
* NULL. */
static struct type* type_qualifier;
int yyparse (void);
static int yylex (void);
void yyerror (char *);
static struct stoken string_to_operator (struct stoken);
static void write_attribute_call0 (enum ada_attribute);
static void write_attribute_call1 (enum ada_attribute, LONGEST);
static void write_attribute_calln (enum ada_attribute, int);
static void write_object_renaming (struct block*, struct symbol*);
static void write_var_from_name (struct block*, struct name_info);
static LONGEST
convert_char_literal (struct type*, LONGEST);
%}
%union
{
LONGEST lval;
struct {
LONGEST val;
struct type *type;
} typed_val;
struct {
DOUBLEST dval;
struct type *type;
} typed_val_float;
struct type *tval;
struct stoken sval;
struct name_info ssym;
int voidval;
struct block *bval;
struct internalvar *ivar;
}
%type <voidval> exp exp1 simple_exp start variable
%type <tval> type
%token <typed_val> INT NULL_PTR CHARLIT
%token <typed_val_float> FLOAT
%token <tval> TYPENAME
%token <bval> BLOCKNAME
/* Both NAME and TYPENAME tokens represent symbols in the input,
and both convey their data as strings.
But a TYPENAME is a string that happens to be defined as a typedef
or builtin type name (such as int or char)
and a NAME is any other symbol.
Contexts where this distinction is not important can use the
nonterminal "name", which matches either NAME or TYPENAME. */
%token <sval> STRING
%token <ssym> NAME DOT_ID OBJECT_RENAMING
%type <bval> block
%type <lval> arglist tick_arglist
%type <tval> save_qualifier
%token DOT_ALL
/* Special type cases, put in to allow the parser to distinguish different
legal basetypes. */
%token <lval> LAST REGNAME
%token <ivar> INTERNAL_VARIABLE
%nonassoc ASSIGN
%left _AND_ OR XOR THEN ELSE
%left '=' NOTEQUAL '<' '>' LEQ GEQ IN DOTDOT
%left '@'
%left '+' '-' '&'
%left UNARY
%left '*' '/' MOD REM
%right STARSTAR ABS NOT
/* The following are right-associative only so that reductions at this
precedence have lower precedence than '.' and '('. The syntax still
forces a.b.c, e.g., to be LEFT-associated. */
%right TICK_ACCESS TICK_ADDRESS TICK_FIRST TICK_LAST TICK_LENGTH
%right TICK_MAX TICK_MIN TICK_MODULUS
%right TICK_POS TICK_RANGE TICK_SIZE TICK_TAG TICK_VAL
%right '.' '(' '[' DOT_ID DOT_ALL
%token ARROW NEW
%%
start : exp1
| type { write_exp_elt_opcode (OP_TYPE);
write_exp_elt_type ($1);
write_exp_elt_opcode (OP_TYPE); }
;
/* Expressions, including the sequencing operator. */
exp1 : exp
| exp1 ';' exp
{ write_exp_elt_opcode (BINOP_COMMA); }
;
/* Expressions, not including the sequencing operator. */
simple_exp : simple_exp DOT_ALL
{ write_exp_elt_opcode (UNOP_IND); }
;
simple_exp : simple_exp DOT_ID
{ write_exp_elt_opcode (STRUCTOP_STRUCT);
write_exp_string ($2.stoken);
write_exp_elt_opcode (STRUCTOP_STRUCT);
}
;
simple_exp : simple_exp '(' arglist ')'
{
write_exp_elt_opcode (OP_FUNCALL);
write_exp_elt_longcst ($3);
write_exp_elt_opcode (OP_FUNCALL);
}
;
simple_exp : type '(' exp ')'
{
write_exp_elt_opcode (UNOP_CAST);
write_exp_elt_type ($1);
write_exp_elt_opcode (UNOP_CAST);
}
;
simple_exp : type '\'' save_qualifier { type_qualifier = $1; } '(' exp ')'
{
/* write_exp_elt_opcode (UNOP_QUAL); */
/* FIXME: UNOP_QUAL should be defined in expression.h */
write_exp_elt_type ($1);
/* write_exp_elt_opcode (UNOP_QUAL); */
/* FIXME: UNOP_QUAL should be defined in expression.h */
type_qualifier = $3;
}
;
save_qualifier : { $$ = type_qualifier; }
;
simple_exp :
simple_exp '(' exp DOTDOT exp ')'
{ write_exp_elt_opcode (TERNOP_SLICE); }
;
simple_exp : '(' exp1 ')' { }
;
simple_exp : variable
;
simple_exp: REGNAME /* GDB extension */
{ write_exp_elt_opcode (OP_REGISTER);
write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_REGISTER);
}
;
simple_exp: INTERNAL_VARIABLE /* GDB extension */
{ write_exp_elt_opcode (OP_INTERNALVAR);
write_exp_elt_intern ($1);
write_exp_elt_opcode (OP_INTERNALVAR);
}
;
exp : simple_exp
;
simple_exp: LAST
{ write_exp_elt_opcode (OP_LAST);
write_exp_elt_longcst ((LONGEST) $1);
write_exp_elt_opcode (OP_LAST);
}
;
exp : exp ASSIGN exp /* Extension for convenience */
{ write_exp_elt_opcode (BINOP_ASSIGN); }
;
exp : '-' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_NEG); }
;
exp : '+' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_PLUS); }
;
exp : NOT exp %prec UNARY
{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
;
exp : ABS exp %prec UNARY
{ write_exp_elt_opcode (UNOP_ABS); }
;
arglist : { $$ = 0; }
;
arglist : exp
{ $$ = 1; }
| any_name ARROW exp
{ $$ = 1; }
| arglist ',' exp
{ $$ = $1 + 1; }
| arglist ',' any_name ARROW exp
{ $$ = $1 + 1; }
;
exp : '{' type '}' exp %prec '.'
/* GDB extension */
{ write_exp_elt_opcode (UNOP_MEMVAL);
write_exp_elt_type ($2);
write_exp_elt_opcode (UNOP_MEMVAL);
}
;
/* Binary operators in order of decreasing precedence. */
exp : exp STARSTAR exp
{ write_exp_elt_opcode (BINOP_EXP); }
;
exp : exp '*' exp
{ write_exp_elt_opcode (BINOP_MUL); }
;
exp : exp '/' exp
{ write_exp_elt_opcode (BINOP_DIV); }
;
exp : exp REM exp /* May need to be fixed to give correct Ada REM */
{ write_exp_elt_opcode (BINOP_REM); }
;
exp : exp MOD exp
{ write_exp_elt_opcode (BINOP_MOD); }
;
exp : exp '@' exp /* GDB extension */
{ write_exp_elt_opcode (BINOP_REPEAT); }
;
exp : exp '+' exp
{ write_exp_elt_opcode (BINOP_ADD); }
;
exp : exp '&' exp
{ write_exp_elt_opcode (BINOP_CONCAT); }
;
exp : exp '-' exp
{ write_exp_elt_opcode (BINOP_SUB); }
;
exp : exp '=' exp
{ write_exp_elt_opcode (BINOP_EQUAL); }
;
exp : exp NOTEQUAL exp
{ write_exp_elt_opcode (BINOP_NOTEQUAL); }
;
exp : exp LEQ exp
{ write_exp_elt_opcode (BINOP_LEQ); }
;
exp : exp IN exp DOTDOT exp
{ /*write_exp_elt_opcode (TERNOP_MBR); */ }
/* FIXME: TERNOP_MBR should be defined in
expression.h */
| exp IN exp TICK_RANGE tick_arglist
{ /*write_exp_elt_opcode (BINOP_MBR); */
/* FIXME: BINOP_MBR should be defined in expression.h */
write_exp_elt_longcst ((LONGEST) $5);
/*write_exp_elt_opcode (BINOP_MBR); */
}
| exp IN TYPENAME %prec TICK_ACCESS
{ /*write_exp_elt_opcode (UNOP_MBR); */
/* FIXME: UNOP_QUAL should be defined in expression.h */
write_exp_elt_type ($3);
/* write_exp_elt_opcode (UNOP_MBR); */
/* FIXME: UNOP_MBR should be defined in expression.h */
}
| exp NOT IN exp DOTDOT exp
{ /*write_exp_elt_opcode (TERNOP_MBR); */
/* FIXME: TERNOP_MBR should be defined in expression.h */
write_exp_elt_opcode (UNOP_LOGICAL_NOT);
}
| exp NOT IN exp TICK_RANGE tick_arglist
{ /* write_exp_elt_opcode (BINOP_MBR); */
/* FIXME: BINOP_MBR should be defined in expression.h */
write_exp_elt_longcst ((LONGEST) $6);
/*write_exp_elt_opcode (BINOP_MBR);*/
/* FIXME: BINOP_MBR should be defined in expression.h */
write_exp_elt_opcode (UNOP_LOGICAL_NOT);
}
| exp NOT IN TYPENAME %prec TICK_ACCESS
{ /*write_exp_elt_opcode (UNOP_MBR);*/
/* FIXME: UNOP_MBR should be defined in expression.h */
write_exp_elt_type ($4);
/* write_exp_elt_opcode (UNOP_MBR);*/
/* FIXME: UNOP_MBR should be defined in expression.h */
write_exp_elt_opcode (UNOP_LOGICAL_NOT);
}
;
exp : exp GEQ exp
{ write_exp_elt_opcode (BINOP_GEQ); }
;
exp : exp '<' exp
{ write_exp_elt_opcode (BINOP_LESS); }
;
exp : exp '>' exp
{ write_exp_elt_opcode (BINOP_GTR); }
;
exp : exp _AND_ exp /* Fix for Ada elementwise AND. */
{ write_exp_elt_opcode (BINOP_BITWISE_AND); }
;
exp : exp _AND_ THEN exp %prec _AND_
{ write_exp_elt_opcode (BINOP_LOGICAL_AND); }
;
exp : exp OR exp /* Fix for Ada elementwise OR */
{ write_exp_elt_opcode (BINOP_BITWISE_IOR); }
;
exp : exp OR ELSE exp
{ write_exp_elt_opcode (BINOP_LOGICAL_OR); }
;
exp : exp XOR exp /* Fix for Ada elementwise XOR */
{ write_exp_elt_opcode (BINOP_BITWISE_XOR); }
;
simple_exp : simple_exp TICK_ACCESS
{ write_exp_elt_opcode (UNOP_ADDR); }
| simple_exp TICK_ADDRESS
{ write_exp_elt_opcode (UNOP_ADDR);
write_exp_elt_opcode (UNOP_CAST);
write_exp_elt_type (builtin_type_ada_system_address);
write_exp_elt_opcode (UNOP_CAST);
}
| simple_exp TICK_FIRST tick_arglist
{ write_attribute_call1 (ATR_FIRST, $3); }
| simple_exp TICK_LAST tick_arglist
{ write_attribute_call1 (ATR_LAST, $3); }
| simple_exp TICK_LENGTH tick_arglist
{ write_attribute_call1 (ATR_LENGTH, $3); }
| simple_exp TICK_SIZE
{ write_attribute_call0 (ATR_SIZE); }
| simple_exp TICK_TAG
{ write_attribute_call0 (ATR_TAG); }
| opt_type_prefix TICK_MIN '(' exp ',' exp ')'
{ write_attribute_calln (ATR_MIN, 2); }
| opt_type_prefix TICK_MAX '(' exp ',' exp ')'
{ write_attribute_calln (ATR_MAX, 2); }
| opt_type_prefix TICK_POS '(' exp ')'
{ write_attribute_calln (ATR_POS, 1); }
| type_prefix TICK_FIRST tick_arglist
{ write_attribute_call1 (ATR_FIRST, $3); }
| type_prefix TICK_LAST tick_arglist
{ write_attribute_call1 (ATR_LAST, $3); }
| type_prefix TICK_LENGTH tick_arglist
{ write_attribute_call1 (ATR_LENGTH, $3); }
| type_prefix TICK_VAL '(' exp ')'
{ write_attribute_calln (ATR_VAL, 1); }
| type_prefix TICK_MODULUS
{ write_attribute_call0 (ATR_MODULUS); }
;
tick_arglist : %prec '('
{ $$ = 1; }
| '(' INT ')'
{ $$ = $2.val; }
;
type_prefix :
TYPENAME
{ write_exp_elt_opcode (OP_TYPE);
write_exp_elt_type ($1);
write_exp_elt_opcode (OP_TYPE); }
;
opt_type_prefix :
type_prefix
| /* EMPTY */
{ write_exp_elt_opcode (OP_TYPE);
write_exp_elt_type (builtin_type_void);
write_exp_elt_opcode (OP_TYPE); }
;
exp : INT
{ write_exp_elt_opcode (OP_LONG);
write_exp_elt_type ($1.type);
write_exp_elt_longcst ((LONGEST)($1.val));
write_exp_elt_opcode (OP_LONG);
}
;
exp : CHARLIT
{ write_exp_elt_opcode (OP_LONG);
if (type_qualifier == NULL)
write_exp_elt_type ($1.type);
else
write_exp_elt_type (type_qualifier);
write_exp_elt_longcst
(convert_char_literal (type_qualifier, $1.val));
write_exp_elt_opcode (OP_LONG);
}
;
exp : FLOAT
{ write_exp_elt_opcode (OP_DOUBLE);
write_exp_elt_type ($1.type);
write_exp_elt_dblcst ($1.dval);
write_exp_elt_opcode (OP_DOUBLE);
}
;
exp : NULL_PTR
{ write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_int);
write_exp_elt_longcst ((LONGEST)(0));
write_exp_elt_opcode (OP_LONG);
}
;
exp : STRING
{ /* Ada strings are converted into array constants
a lower bound of 1. Thus, the array upper bound
is the string length. */
char *sp = $1.ptr; int count;
if ($1.length == 0)
{ /* One dummy character for the type */
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_ada_char);
write_exp_elt_longcst ((LONGEST)(0));
write_exp_elt_opcode (OP_LONG);
}
for (count = $1.length; count > 0; count -= 1)
{
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_ada_char);
write_exp_elt_longcst ((LONGEST)(*sp));
sp += 1;
write_exp_elt_opcode (OP_LONG);
}
write_exp_elt_opcode (OP_ARRAY);
write_exp_elt_longcst ((LONGEST) 1);
write_exp_elt_longcst ((LONGEST) ($1.length));
write_exp_elt_opcode (OP_ARRAY);
}
;
exp : NEW TYPENAME
{ error ("NEW not implemented."); }
;
variable: NAME { write_var_from_name (NULL, $1); }
| block NAME /* GDB extension */
{ write_var_from_name ($1, $2); }
| OBJECT_RENAMING { write_object_renaming (NULL, $1.sym); }
| block OBJECT_RENAMING
{ write_object_renaming ($1, $2.sym); }
;
any_name : NAME { }
| TYPENAME { }
| OBJECT_RENAMING { }
;
block : BLOCKNAME /* GDB extension */
{ $$ = $1; }
| block BLOCKNAME /* GDB extension */
{ $$ = $2; }
;
type : TYPENAME { $$ = $1; }
| block TYPENAME { $$ = $2; }
| TYPENAME TICK_ACCESS
{ $$ = lookup_pointer_type ($1); }
| block TYPENAME TICK_ACCESS
{ $$ = lookup_pointer_type ($2); }
;
/* Some extensions borrowed from C, for the benefit of those who find they
can't get used to Ada notation in GDB. */
exp : '*' exp %prec '.'
{ write_exp_elt_opcode (UNOP_IND); }
| '&' exp %prec '.'
{ write_exp_elt_opcode (UNOP_ADDR); }
| exp '[' exp ']'
{ write_exp_elt_opcode (BINOP_SUBSCRIPT); }
;
%%
/* yylex defined in ada-lex.c: Reads one token, getting characters */
/* through lexptr. */
/* Remap normal flex interface names (yylex) as well as gratuitiously */
/* global symbol names, so we can have multiple flex-generated parsers */
/* in gdb. */
/* (See note above on previous definitions for YACC.) */
#define yy_create_buffer ada_yy_create_buffer
#define yy_delete_buffer ada_yy_delete_buffer
#define yy_init_buffer ada_yy_init_buffer
#define yy_load_buffer_state ada_yy_load_buffer_state
#define yy_switch_to_buffer ada_yy_switch_to_buffer
#define yyrestart ada_yyrestart
#define yytext ada_yytext
#define yywrap ada_yywrap
/* The following kludge was found necessary to prevent conflicts between */
/* defs.h and non-standard stdlib.h files. */
#define qsort __qsort__dummy
#include "ada-lex.c"
int
ada_parse ()
{
lexer_init (yyin); /* (Re-)initialize lexer. */
left_block_context = NULL;
type_qualifier = NULL;
return _ada_parse ();
}
void
yyerror (msg)
char *msg;
{
error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
}
/* The operator name corresponding to operator symbol STRING (adds
quotes and maps to lower-case). Destroys the previous contents of
the array pointed to by STRING.ptr. Error if STRING does not match
a valid Ada operator. Assumes that STRING.ptr points to a
null-terminated string and that, if STRING is a valid operator
symbol, the array pointed to by STRING.ptr contains at least
STRING.length+3 characters. */
static struct stoken
string_to_operator (string)
struct stoken string;
{
int i;
for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
{
if (string.length == strlen (ada_opname_table[i].demangled)-2
&& strncasecmp (string.ptr, ada_opname_table[i].demangled+1,
string.length) == 0)
{
strncpy (string.ptr, ada_opname_table[i].demangled,
string.length+2);
string.length += 2;
return string;
}
}
error ("Invalid operator symbol `%s'", string.ptr);
}
/* Emit expression to access an instance of SYM, in block BLOCK (if
* non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */
static void
write_var_from_sym (orig_left_context, block, sym)
struct block* orig_left_context;
struct block* block;
struct symbol* sym;
{
if (orig_left_context == NULL && symbol_read_needs_frame (sym))
{
if (innermost_block == 0 ||
contained_in (block, innermost_block))
innermost_block = block;
}
write_exp_elt_opcode (OP_VAR_VALUE);
/* We want to use the selected frame, not another more inner frame
which happens to be in the same block */
write_exp_elt_block (NULL);
write_exp_elt_sym (sym);
write_exp_elt_opcode (OP_VAR_VALUE);
}
/* Emit expression to access an instance of NAME. */
static void
write_var_from_name (orig_left_context, name)
struct block* orig_left_context;
struct name_info name;
{
if (name.msym != NULL)
{
write_exp_msymbol (name.msym,
lookup_function_type (builtin_type_int),
builtin_type_int);
}
else if (name.sym == NULL)
{
/* Multiple matches: record name and starting block for later
resolution by ada_resolve. */
/* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
/* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
write_exp_elt_block (name.block);
/* write_exp_elt_name (name.stoken.ptr); */
/* FIXME: write_exp_elt_name should be defined in defs.h, located in parse.c */
/* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
/* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
}
else
write_var_from_sym (orig_left_context, name.block, name.sym);
}
/* Write a call on parameterless attribute ATR. */
static void
write_attribute_call0 (atr)
enum ada_attribute atr;
{
/* write_exp_elt_opcode (OP_ATTRIBUTE); */
/* FIXME: OP_ATTRIBUTE should be defined in expression.h */
write_exp_elt_longcst ((LONGEST) 0);
write_exp_elt_longcst ((LONGEST) atr);
/* write_exp_elt_opcode (OP_ATTRIBUTE); */
/* FIXME: OP_ATTRIBUTE should be defined in expression.h */
}
/* Write a call on an attribute ATR with one constant integer
* parameter. */
static void
write_attribute_call1 (atr, arg)
enum ada_attribute atr;
LONGEST arg;
{
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_int);
write_exp_elt_longcst (arg);
write_exp_elt_opcode (OP_LONG);
/*write_exp_elt_opcode (OP_ATTRIBUTE);*/
/* FIXME: OP_ATTRIBUTE should be defined in expression.h */
write_exp_elt_longcst ((LONGEST) 1);
write_exp_elt_longcst ((LONGEST) atr);
/*write_exp_elt_opcode (OP_ATTRIBUTE);*/
/* FIXME: OP_ATTRIBUTE should be defined in expression.h */
}
/* Write a call on an attribute ATR with N parameters, whose code must have
* been generated previously. */
static void
write_attribute_calln (atr, n)
enum ada_attribute atr;
int n;
{
/*write_exp_elt_opcode (OP_ATTRIBUTE);*/
/* FIXME: OP_ATTRIBUTE should be defined in expression.h */
write_exp_elt_longcst ((LONGEST) n);
write_exp_elt_longcst ((LONGEST) atr);
/* write_exp_elt_opcode (OP_ATTRIBUTE);*/
/* FIXME: OP_ATTRIBUTE should be defined in expression.h */
}
/* Emit expression corresponding to the renamed object designated by
* the type RENAMING, which must be the referent of an object renaming
* type, in the context of ORIG_LEFT_CONTEXT (?). */
static void
write_object_renaming (orig_left_context, renaming)
struct block* orig_left_context;
struct symbol* renaming;
{
const char* qualification = DEPRECATED_SYMBOL_NAME (renaming);
const char* simple_tail;
const char* expr = TYPE_FIELD_NAME (SYMBOL_TYPE (renaming), 0);
const char* suffix;
char* name;
struct symbol* sym;
enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state;
/* if orig_left_context is null, then use the currently selected
block, otherwise we might fail our symbol lookup below */
if (orig_left_context == NULL)
orig_left_context = get_selected_block (NULL);
for (simple_tail = qualification + strlen (qualification);
simple_tail != qualification; simple_tail -= 1)
{
if (*simple_tail == '.')
{
simple_tail += 1;
break;
}
else if (DEPRECATED_STREQN (simple_tail, "__", 2))
{
simple_tail += 2;
break;
}
}
suffix = strstr (expr, "___XE");
if (suffix == NULL)
goto BadEncoding;
name = (char*) malloc (suffix - expr + 1);
/* add_name_string_cleanup (name); */
/* FIXME: add_name_string_cleanup should be defined in
parser-defs.h, implemented in parse.c */
strncpy (name, expr, suffix-expr);
name[suffix-expr] = '\000';
sym = lookup_symbol (name, orig_left_context, VAR_DOMAIN, 0, NULL);
/* if (sym == NULL)
error ("Could not find renamed variable: %s", ada_demangle (name));
*/
/* FIXME: ada_demangle should be defined in defs.h, implemented in ada-lang.c */
write_var_from_sym (orig_left_context, block_found, sym);
suffix += 5;
slice_state = SIMPLE_INDEX;
while (*suffix == 'X')
{
suffix += 1;
switch (*suffix) {
case 'L':
slice_state = LOWER_BOUND;
case 'S':
suffix += 1;
if (isdigit (*suffix))
{
char* next;
long val = strtol (suffix, &next, 10);
if (next == suffix)
goto BadEncoding;
suffix = next;
write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_ada_int);
write_exp_elt_longcst ((LONGEST) val);
write_exp_elt_opcode (OP_LONG);
}
else
{
const char* end;
char* index_name;
int index_len;
struct symbol* index_sym;
end = strchr (suffix, 'X');
if (end == NULL)
end = suffix + strlen (suffix);
index_len = simple_tail - qualification + 2 + (suffix - end) + 1;
index_name = (char*) malloc (index_len);
memset (index_name, '\000', index_len);
/* add_name_string_cleanup (index_name);*/
/* FIXME: add_name_string_cleanup should be defined in
parser-defs.h, implemented in parse.c */
strncpy (index_name, qualification, simple_tail - qualification);
index_name[simple_tail - qualification] = '\000';
strncat (index_name, suffix, suffix-end);
suffix = end;
index_sym =
lookup_symbol (index_name, NULL, VAR_DOMAIN, 0, NULL);
if (index_sym == NULL)
error ("Could not find %s", index_name);
write_var_from_sym (NULL, block_found, sym);
}
if (slice_state == SIMPLE_INDEX)
{
write_exp_elt_opcode (OP_FUNCALL);
write_exp_elt_longcst ((LONGEST) 1);
write_exp_elt_opcode (OP_FUNCALL);
}
else if (slice_state == LOWER_BOUND)
slice_state = UPPER_BOUND;
else if (slice_state == UPPER_BOUND)
{
write_exp_elt_opcode (TERNOP_SLICE);
slice_state = SIMPLE_INDEX;
}
break;
case 'R':
{
struct stoken field_name;
const char* end;
suffix += 1;
if (slice_state != SIMPLE_INDEX)
goto BadEncoding;
end = strchr (suffix, 'X');
if (end == NULL)
end = suffix + strlen (suffix);
field_name.length = end - suffix;
field_name.ptr = (char*) malloc (end - suffix + 1);
strncpy (field_name.ptr, suffix, end - suffix);
field_name.ptr[end - suffix] = '\000';
suffix = end;
write_exp_elt_opcode (STRUCTOP_STRUCT);
write_exp_string (field_name);
write_exp_elt_opcode (STRUCTOP_STRUCT);
break;
}
default:
goto BadEncoding;
}
}
if (slice_state == SIMPLE_INDEX)
return;
BadEncoding:
error ("Internal error in encoding of renaming declaration: %s",
DEPRECATED_SYMBOL_NAME (renaming));
}
/* Convert the character literal whose ASCII value would be VAL to the
appropriate value of type TYPE, if there is a translation.
Otherwise return VAL. Hence, in an enumeration type ('A', 'B'),
the literal 'A' (VAL == 65), returns 0. */
static LONGEST
convert_char_literal (struct type* type, LONGEST val)
{
char name[7];
int f;
if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM)
return val;
sprintf (name, "QU%02x", (int) val);
for (f = 0; f < TYPE_NFIELDS (type); f += 1)
{
if (DEPRECATED_STREQ (name, TYPE_FIELD_NAME (type, f)))
return TYPE_FIELD_BITPOS (type, f);
}
return val;
}

8254
contrib/gdb/gdb/ada-lang.c Normal file

File diff suppressed because it is too large Load diff

392
contrib/gdb/gdb/ada-lang.h Normal file
View file

@ -0,0 +1,392 @@
/* Ada language support definitions for GDB, the GNU debugger.
Copyright 1992, 1997 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if !defined (ADA_LANG_H)
#define ADA_LANG_H 1
struct partial_symbol;
#include "value.h"
#include "gdbtypes.h"
struct block;
/* A macro to reorder the bytes of an address depending on the
endiannes of the target. */
#define EXTRACT_ADDRESS(x) ((void *) extract_unsigned_integer (&(x), sizeof (x)))
/* A macro to reorder the bytes of an int depending on the endiannes
of the target */
#define EXTRACT_INT(x) ((int) extract_signed_integer (&(x), sizeof (x)))
/* Chain of cleanups for arguments of OP_UNRESOLVED_VALUE names. Created in
yyparse and freed in ada_resolve. */
extern struct cleanup *unresolved_names;
/* Corresponding mangled/demangled names and opcodes for Ada user-definable
operators. */
struct ada_opname_map
{
const char *mangled;
const char *demangled;
enum exp_opcode op;
};
/* Table of Ada operators in mangled and demangled forms. */
/* Defined in ada-lang.c */
extern const struct ada_opname_map ada_opname_table[];
/* The maximum number of tasks known to the Ada runtime */
extern const int MAX_NUMBER_OF_KNOWN_TASKS;
/* Identifiers for Ada attributes that need special processing. Be sure
to update the table attribute_names in ada-lang.c whenever you change this.
*/
enum ada_attribute
{
/* Invalid attribute for error checking. */
ATR_INVALID,
ATR_FIRST,
ATR_LAST,
ATR_LENGTH,
ATR_IMAGE,
ATR_IMG,
ATR_MAX,
ATR_MIN,
ATR_MODULUS,
ATR_POS,
ATR_SIZE,
ATR_TAG,
ATR_VAL,
/* Dummy last attribute. */
ATR_END
};
enum task_states
{
Unactivated,
Runnable,
Terminated,
Activator_Sleep,
Acceptor_Sleep,
Entry_Caller_Sleep,
Async_Select_Sleep,
Delay_Sleep,
Master_Completion_Sleep,
Master_Phase_2_Sleep
};
extern char *ada_task_states[];
typedef struct
{
char *P_ARRAY;
int *P_BOUNDS;
}
fat_string;
typedef struct entry_call
{
void *self;
}
*entry_call_link;
struct task_fields
{
int entry_num;
#if (defined (VXWORKS_TARGET) || !defined (i386)) \
&& !(defined (VXWORKS_TARGET) && defined (M68K_TARGET))
int pad1;
#endif
char state;
#if (defined (VXWORKS_TARGET) && defined (M68K_TARGET))
char pad_8bits;
#endif
void *parent;
int priority;
int current_priority;
fat_string image;
entry_call_link call;
#if (defined (sun) && defined (__SVR4)) && !defined (VXWORKS_TARGET)
int pad2;
unsigned thread;
unsigned lwp;
#else
void *thread;
void *lwp;
#endif
}
#if (defined (VXWORKS_TARGET) && defined (M68K_TARGET))
__attribute__ ((packed))
#endif
;
struct task_entry
{
void *task_id;
int task_num;
int known_tasks_index;
struct task_entry *next_task;
void *thread;
void *lwp;
int stack_per;
};
extern struct type *builtin_type_ada_int;
extern struct type *builtin_type_ada_short;
extern struct type *builtin_type_ada_long;
extern struct type *builtin_type_ada_long_long;
extern struct type *builtin_type_ada_char;
extern struct type *builtin_type_ada_float;
extern struct type *builtin_type_ada_double;
extern struct type *builtin_type_ada_long_double;
extern struct type *builtin_type_ada_natural;
extern struct type *builtin_type_ada_positive;
extern struct type *builtin_type_ada_system_address;
/* Assuming V points to an array of S objects, make sure that it contains at
least M objects, updating V and S as necessary. */
#define GROW_VECT(v, s, m) \
if ((s) < (m)) grow_vect ((void**) &(v), &(s), (m), sizeof(*(v)));
extern void grow_vect (void **, size_t *, size_t, int);
extern int ada_parse (void); /* Defined in ada-exp.y */
extern void ada_error (char *); /* Defined in ada-exp.y */
/* Defined in ada-typeprint.c */
extern void ada_print_type (struct type *, char *, struct ui_file *, int,
int);
extern int ada_val_print (struct type *, char *, int, CORE_ADDR,
struct ui_file *, int, int, int,
enum val_prettyprint);
extern int ada_value_print (struct value *, struct ui_file *, int,
enum val_prettyprint);
/* Defined in ada-lang.c */
extern struct value *value_from_contents_and_address (struct type *, char *,
CORE_ADDR);
extern void ada_emit_char (int, struct ui_file *, int, int);
extern void ada_printchar (int, struct ui_file *);
extern void ada_printstr (struct ui_file *, char *, unsigned int, int, int);
extern void ada_convert_actuals (struct value *, int, struct value **,
CORE_ADDR *);
extern struct value *ada_value_subscript (struct value *, int,
struct value **);
extern struct type *ada_array_element_type (struct type *, int);
extern int ada_array_arity (struct type *);
struct type *ada_type_of_array (struct value *, int);
extern struct value *ada_coerce_to_simple_array (struct value *);
extern struct value *ada_coerce_to_simple_array_ptr (struct value *);
extern int ada_is_simple_array (struct type *);
extern int ada_is_array_descriptor (struct type *);
extern int ada_is_bogus_array_descriptor (struct type *);
extern struct type *ada_index_type (struct type *, int);
extern struct value *ada_array_bound (struct value *, int, int);
extern int ada_lookup_symbol_list (const char *, struct block *,
domain_enum, struct symbol ***,
struct block ***);
extern char *ada_fold_name (const char *);
extern struct symbol *ada_lookup_symbol (const char *, struct block *,
domain_enum);
extern struct minimal_symbol *ada_lookup_minimal_symbol (const char *);
extern void ada_resolve (struct expression **, struct type *);
extern int ada_resolve_function (struct symbol **, struct block **, int,
struct value **, int, const char *,
struct type *);
extern void ada_fill_in_ada_prototype (struct symbol *);
extern int user_select_syms (struct symbol **, struct block **, int, int);
extern int get_selections (int *, int, int, int, char *);
extern char *ada_start_decode_line_1 (char *);
extern struct symtabs_and_lines ada_finish_decode_line_1 (char **,
struct symtab *,
int, char ***);
extern int ada_scan_number (const char *, int, LONGEST *, int *);
extern struct type *ada_parent_type (struct type *);
extern int ada_is_ignored_field (struct type *, int);
extern int ada_is_packed_array_type (struct type *);
extern struct value *ada_value_primitive_packed_val (struct value *, char *,
long, int, int,
struct type *);
extern struct type *ada_coerce_to_simple_array_type (struct type *);
extern int ada_is_character_type (struct type *);
extern int ada_is_string_type (struct type *);
extern int ada_is_tagged_type (struct type *);
extern struct type *ada_tag_type (struct value *);
extern struct value *ada_value_tag (struct value *);
extern int ada_is_parent_field (struct type *, int);
extern int ada_is_wrapper_field (struct type *, int);
extern int ada_is_variant_part (struct type *, int);
extern struct type *ada_variant_discrim_type (struct type *, struct type *);
extern int ada_is_others_clause (struct type *, int);
extern int ada_in_variant (LONGEST, struct type *, int);
extern char *ada_variant_discrim_name (struct type *);
extern struct type *ada_lookup_struct_elt_type (struct type *, char *, int,
int *);
extern struct value *ada_value_struct_elt (struct value *, char *, char *);
extern struct value *ada_search_struct_field (char *, struct value *, int,
struct type *);
extern int ada_is_aligner_type (struct type *);
extern struct type *ada_aligned_type (struct type *);
extern char *ada_aligned_value_addr (struct type *, char *);
extern const char *ada_attribute_name (int);
extern int ada_is_fixed_point_type (struct type *);
extern DOUBLEST ada_delta (struct type *);
extern DOUBLEST ada_fixed_to_float (struct type *, LONGEST);
extern LONGEST ada_float_to_fixed (struct type *, DOUBLEST);
extern int ada_is_vax_floating_type (struct type *);
extern int ada_vax_float_type_suffix (struct type *);
extern struct value *ada_vax_float_print_function (struct type *);
extern struct type *ada_system_address_type (void);
extern int ada_which_variant_applies (struct type *, struct type *, char *);
extern struct value *ada_to_fixed_value (struct type *, char *, CORE_ADDR,
struct value *);
extern struct type *ada_to_fixed_type (struct type *, char *, CORE_ADDR,
struct value *);
extern int ada_name_prefix_len (const char *);
extern char *ada_type_name (struct type *);
extern struct type *ada_find_parallel_type (struct type *,
const char *suffix);
extern LONGEST get_int_var_value (char *, char *, int *);
extern struct type *ada_find_any_type (const char *name);
extern int ada_prefer_type (struct type *, struct type *);
extern struct type *ada_get_base_type (struct type *);
extern struct type *ada_completed_type (struct type *);
extern char *ada_mangle (const char *);
extern const char *ada_enum_name (const char *);
extern int ada_is_modular_type (struct type *);
extern LONGEST ada_modulus (struct type *);
extern struct value *ada_value_ind (struct value *);
extern void ada_print_scalar (struct type *, LONGEST, struct ui_file *);
extern int ada_is_range_type_name (const char *);
extern const char *ada_renaming_type (struct type *);
extern int ada_is_object_renaming (struct symbol *);
extern const char *ada_simple_renamed_entity (struct symbol *);
extern char *ada_breakpoint_rewrite (char *, int *);
/* Tasking-related: ada-tasks.c */
extern int valid_task_id (int);
extern int get_current_task (void);
extern void init_task_list (void);
extern void *get_self_id (void);
extern int get_current_task (void);
extern int get_entry_number (void *);
extern void ada_report_exception_break (struct breakpoint *);
extern int ada_maybe_exception_partial_symbol (struct partial_symbol *sym);
extern int ada_is_exception_sym (struct symbol *sym);
#endif

928
contrib/gdb/gdb/ada-lex.l Normal file
View file

@ -0,0 +1,928 @@
/* FLEX lexer for Ada expressions, for GDB.
Copyright (C) 1994, 1997, 2000
Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/*----------------------------------------------------------------------*/
/* The converted version of this file is to be included in ada-exp.y, */
/* the Ada parser for gdb. The function yylex obtains characters from */
/* the global pointer lexptr. It returns a syntactic category for */
/* each successive token and places a semantic value into yylval */
/* (ada-lval), defined by the parser. */
/* Run flex with (at least) the -i option (case-insensitive), and the -I */
/* option (interactive---no unnecessary lookahead). */
DIG [0-9]
NUM10 ({DIG}({DIG}|_)*)
HEXDIG [0-9a-f]
NUM16 ({HEXDIG}({HEXDIG}|_)*)
OCTDIG [0-7]
LETTER [a-z_]
ID ({LETTER}({LETTER}|{DIG})*|"<"{LETTER}({LETTER}|{DIG})*">")
WHITE [ \t\n]
TICK ("'"{WHITE}*)
GRAPHIC [a-z0-9 #&'()*+,-./:;<>=_|!$%?@\[\]\\^`{}~]
OPER ([-+*/=<>&]|"<="|">="|"**"|"/="|"and"|"or"|"xor"|"not"|"mod"|"rem"|"abs")
EXP (e[+-]{NUM10})
POSEXP (e"+"?{NUM10})
%{
#define NUMERAL_WIDTH 256
#define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
/* Temporary staging for numeric literals. */
static char numbuf[NUMERAL_WIDTH];
static void canonicalizeNumeral (char* s1, const char*);
static int processInt (const char*, const char*, const char*);
static int processReal (const char*);
static int processId (const char*, int);
static int processAttribute (const char*);
static int find_dot_all (const char*);
#undef YY_DECL
#define YY_DECL static int yylex ( void )
#undef YY_INPUT
#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
if ( *lexptr == '\000' ) \
(RESULT) = YY_NULL; \
else \
{ \
*(BUF) = *lexptr; \
(RESULT) = 1; \
lexptr += 1; \
}
static char *tempbuf = NULL;
static int tempbufsize = 0;
static int tempbuf_len;
static struct block* left_block_context;
static void resize_tempbuf (unsigned int);
static void block_lookup (char*, char*);
static int name_lookup (char*, char*, int*);
static int find_dot_all (const char*);
%}
%s IN_STRING BEFORE_QUAL_QUOTE
%%
{WHITE} { }
"--".* { yyterminate(); }
{NUM10}{POSEXP} {
canonicalizeNumeral (numbuf, yytext);
return processInt (NULL, numbuf, strrchr(numbuf, 'e')+1);
}
{NUM10} {
canonicalizeNumeral (numbuf, yytext);
return processInt (NULL, numbuf, NULL);
}
{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} {
canonicalizeNumeral (numbuf, yytext);
return processInt (numbuf,
strchr (numbuf, '#') + 1,
strrchr(numbuf, '#') + 1);
}
{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#" {
canonicalizeNumeral (numbuf, yytext);
return processInt (numbuf, strchr (numbuf, '#') + 1, NULL);
}
"0x"{HEXDIG}+ {
canonicalizeNumeral (numbuf, yytext+2);
return processInt ("16#", numbuf, NULL);
}
{NUM10}"."{NUM10}{EXP} {
canonicalizeNumeral (numbuf, yytext);
return processReal (numbuf);
}
{NUM10}"."{NUM10} {
canonicalizeNumeral (numbuf, yytext);
return processReal (numbuf);
}
{NUM10}"#"{NUM16}"."{NUM16}"#"{EXP} {
error ("Based real literals not implemented yet.");
}
{NUM10}"#"{NUM16}"."{NUM16}"#" {
error ("Based real literals not implemented yet.");
}
<INITIAL>"'"({GRAPHIC}|\")"'" {
yylval.typed_val.type = builtin_type_ada_char;
yylval.typed_val.val = yytext[1];
return CHARLIT;
}
<INITIAL>"'[\""{HEXDIG}{2}"\"]'" {
int v;
yylval.typed_val.type = builtin_type_ada_char;
sscanf (yytext+3, "%2x", &v);
yylval.typed_val.val = v;
return CHARLIT;
}
\"{OPER}\"/{WHITE}*"(" { return processId (yytext, yyleng); }
<INITIAL>\" {
tempbuf_len = 0;
BEGIN IN_STRING;
}
<IN_STRING>{GRAPHIC}*\" {
resize_tempbuf (yyleng+tempbuf_len);
strncpy (tempbuf+tempbuf_len, yytext, yyleng-1);
tempbuf_len += yyleng-1;
yylval.sval.ptr = tempbuf;
yylval.sval.length = tempbuf_len;
BEGIN INITIAL;
return STRING;
}
<IN_STRING>{GRAPHIC}*"[\""{HEXDIG}{2}"\"]" {
int n;
resize_tempbuf (yyleng-5+tempbuf_len+1);
strncpy (tempbuf+tempbuf_len, yytext, yyleng-6);
sscanf(yytext+yyleng-4, "%2x", &n);
tempbuf[yyleng-6+tempbuf_len] = (char) n;
tempbuf_len += yyleng-5;
}
<IN_STRING>{GRAPHIC}*"[\"\"\"]" {
int n;
resize_tempbuf (yyleng-4+tempbuf_len+1);
strncpy (tempbuf+tempbuf_len, yytext, yyleng-6);
tempbuf[yyleng-5+tempbuf_len] = '"';
tempbuf_len += yyleng-4;
}
if {
while (*lexptr != 'i' && *lexptr != 'I')
lexptr -= 1;
yyrestart(NULL);
return 0;
}
/* ADA KEYWORDS */
abs { return ABS; }
and { return _AND_; }
else { return ELSE; }
in { return IN; }
mod { return MOD; }
new { return NEW; }
not { return NOT; }
null { return NULL_PTR; }
or { return OR; }
rem { return REM; }
then { return THEN; }
xor { return XOR; }
/* ATTRIBUTES */
{TICK}[a-zA-Z][a-zA-Z]+ { return processAttribute (yytext+1); }
/* PUNCTUATION */
"=>" { return ARROW; }
".." { return DOTDOT; }
"**" { return STARSTAR; }
":=" { return ASSIGN; }
"/=" { return NOTEQUAL; }
"<=" { return LEQ; }
">=" { return GEQ; }
<BEFORE_QUAL_QUOTE>"'" { BEGIN INITIAL; return '\''; }
[-&*+./:<>=|;\[\]] { return yytext[0]; }
"," { if (paren_depth == 0 && comma_terminates)
{
lexptr -= 1;
yyrestart(NULL);
return 0;
}
else
return ',';
}
"(" { paren_depth += 1; return '('; }
")" { if (paren_depth == 0)
{
lexptr -= 1;
yyrestart(NULL);
return 0;
}
else
{
paren_depth -= 1;
return ')';
}
}
"."{WHITE}*all { return DOT_ALL; }
"."{WHITE}*{ID} {
processId (yytext+1, yyleng-1);
return DOT_ID;
}
{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'")? {
int all_posn = find_dot_all (yytext);
int token_type, segments, k;
int quote_follows;
if (all_posn == -1 && yytext[yyleng-1] == '\'')
{
quote_follows = 1;
do {
yyless (yyleng-1);
} while (yytext[yyleng-1] == ' ');
}
else
quote_follows = 0;
if (all_posn >= 0)
yyless (all_posn);
processId(yytext, yyleng);
segments = name_lookup (ada_mangle (yylval.ssym.stoken.ptr),
yylval.ssym.stoken.ptr, &token_type);
left_block_context = NULL;
for (k = yyleng; segments > 0 && k > 0; k -= 1)
{
if (yytext[k-1] == '.')
segments -= 1;
quote_follows = 0;
}
if (k <= 0)
error ("confused by name %s", yytext);
yyless (k);
if (quote_follows)
BEGIN BEFORE_QUAL_QUOTE;
return token_type;
}
/* GDB EXPRESSION CONSTRUCTS */
"'"[^']+"'"{WHITE}*:: {
processId(yytext, yyleng-2);
block_lookup (yylval.ssym.stoken.ptr, yylval.ssym.stoken.ptr);
return BLOCKNAME;
}
{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*{WHITE}*:: {
processId(yytext, yyleng-2);
block_lookup (ada_mangle (yylval.ssym.stoken.ptr),
yylval.ssym.stoken.ptr);
return BLOCKNAME;
}
[{}@] { return yytext[0]; }
"$$" { yylval.lval = -1; return LAST; }
"$$"{DIG}+ { yylval.lval = -atoi(yytext+2); return LAST; }
"$" { yylval.lval = 0; return LAST; }
"$"{DIG}+ { yylval.lval = atoi(yytext+1); return LAST; }
/* REGISTERS AND GDB CONVENIENCE VARIABLES */
"$"({LETTER}|{DIG}|"$")+ {
int c;
for (c = 0; c < NUM_REGS; c++)
if (REGISTER_NAME (c) &&
strcmp (yytext + 1, REGISTER_NAME (c)) == 0)
{
yylval.lval = c;
return REGNAME;
}
yylval.sval.ptr = yytext;
yylval.sval.length = yyleng;
yylval.ivar =
lookup_internalvar (copy_name (yylval.sval) + 1);
return INTERNAL_VARIABLE;
}
/* CATCH-ALL ERROR CASE */
. { error ("Invalid character '%s' in expression.", yytext); }
%%
#include <ctype.h>
#include <string.h>
/* Initialize the lexer for processing new expression */
void
lexer_init (FILE* inp)
{
BEGIN INITIAL;
yyrestart (inp);
}
/* Make sure that tempbuf points at an array at least N characters long. */
static void
resize_tempbuf (n)
unsigned int n;
{
if (tempbufsize < n)
{
tempbufsize = (n+63) & ~63;
tempbuf = (char*) xrealloc (tempbuf, tempbufsize);
}
}
/* Copy S2 to S1, removing all underscores, and downcasing all letters. */
static void
canonicalizeNumeral (s1,s2)
char* s1;
const char* s2;
{
for (; *s2 != '\000'; s2 += 1)
{
if (*s2 != '_')
{
*s1 = tolower(*s2);
s1 += 1;
}
}
s1[0] = '\000';
}
#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
where 2 <= BASE <= 16. */
static int
is_digit_in_base (digit, base)
unsigned char digit;
int base;
{
if (!isxdigit (digit))
return 0;
if (base <= 10)
return (isdigit (digit) && digit < base + '0');
else
return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
}
static int
digit_to_int (c)
unsigned char c;
{
if (isdigit (c))
return c - '0';
else
return tolower (c) - 'a' + 10;
}
/* As for strtoul, but for ULONGEST results. */
ULONGEST
strtoulst (num, trailer, base)
const char *num;
const char **trailer;
int base;
{
unsigned int high_part;
ULONGEST result;
int i;
unsigned char lim;
if (base < 2 || base > 16)
{
errno = EINVAL;
return 0;
}
lim = base - 1 + '0';
result = high_part = 0;
for (i = 0; is_digit_in_base (num[i], base); i += 1)
{
result = result*base + digit_to_int (num[i]);
high_part = high_part*base + (unsigned int) (result >> HIGH_BYTE_POSN);
result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
if (high_part > 0xff)
{
errno = ERANGE;
result = high_part = 0;
break;
}
}
if (trailer != NULL)
*trailer = &num[i];
return result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
}
/* Interprets the prefix of NUM that consists of digits of the given BASE
as an integer of that BASE, with the string EXP as an exponent.
Puts value in yylval, and returns INT, if the string is valid. Causes
an error if the number is improperly formated. BASE, if NULL, defaults
to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'. */
static int
processInt (base0, num0, exp0)
const char* num0;
const char* base0;
const char* exp0;
{
ULONGEST result;
long exp;
int base;
char* trailer;
if (base0 == NULL)
base = 10;
else
{
base = strtol (base0, (char**) NULL, 10);
if (base < 2 || base > 16)
error ("Invalid base: %d.", base);
}
if (exp0 == NULL)
exp = 0;
else
exp = strtol(exp0, (char**) NULL, 10);
errno = 0;
result = strtoulst (num0, &trailer, base);
if (errno == ERANGE)
error ("Integer literal out of range");
if (isxdigit(*trailer))
error ("Invalid digit `%c' in based literal", *trailer);
while (exp > 0)
{
if (result > (ULONG_MAX / base))
error ("Integer literal out of range");
result *= base;
exp -= 1;
}
if ((result >> (TARGET_INT_BIT-1)) == 0)
yylval.typed_val.type = builtin_type_ada_int;
else if ((result >> (TARGET_LONG_BIT-1)) == 0)
yylval.typed_val.type = builtin_type_ada_long;
else if (((result >> (TARGET_LONG_BIT-1)) >> 1) == 0)
{
/* We have a number representable as an unsigned integer quantity.
For consistency with the C treatment, we will treat it as an
anonymous modular (unsigned) quantity. Alas, the types are such
that we need to store .val as a signed quantity. Sorry
for the mess, but C doesn't officially guarantee that a simple
assignment does the trick (no, it doesn't; read the reference manual).
*/
yylval.typed_val.type = builtin_type_unsigned_long;
if (result & LONGEST_SIGN)
yylval.typed_val.val =
(LONGEST) (result & ~LONGEST_SIGN)
- (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1);
else
yylval.typed_val.val = (LONGEST) result;
return INT;
}
else
yylval.typed_val.type = builtin_type_ada_long_long;
yylval.typed_val.val = (LONGEST) result;
return INT;
}
static int
processReal (num0)
const char* num0;
{
if (sizeof (DOUBLEST) <= sizeof (float))
sscanf (num0, "%g", &yylval.typed_val_float.dval);
else if (sizeof (DOUBLEST) <= sizeof (double))
sscanf (num0, "%lg", &yylval.typed_val_float.dval);
else
{
#ifdef PRINTF_HAS_LONG_DOUBLE
sscanf (num0, "%Lg", &yylval.typed_val_float.dval);
#else
/* Scan it into a double, then convert and assign it to the
long double. This at least wins with values representable
in the range of doubles. */
double temp;
sscanf (num0, "%lg", &temp);
yylval.typed_val_float.dval = temp;
#endif
}
yylval.typed_val_float.type = builtin_type_ada_float;
if (sizeof(DOUBLEST) >= TARGET_DOUBLE_BIT / TARGET_CHAR_BIT)
yylval.typed_val_float.type = builtin_type_ada_double;
if (sizeof(DOUBLEST) >= TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT)
yylval.typed_val_float.type = builtin_type_ada_long_double;
return FLOAT;
}
static int
processId (name0, len)
const char *name0;
int len;
{
char* name = xmalloc (len + 11);
int i0, i;
/* add_name_string_cleanup (name); */
/* FIXME: add_name_string_cleanup should be defined in parse.c */
while (len > 0 && isspace (name0[len-1]))
len -= 1;
i = i0 = 0;
while (i0 < len)
{
if (isalnum (name0[i0]))
{
name[i] = tolower (name0[i0]);
i += 1; i0 += 1;
}
else switch (name0[i0])
{
default:
name[i] = name0[i0];
i += 1; i0 += 1;
break;
case ' ': case '\t':
i0 += 1;
break;
case '\'':
i0 += 1;
while (i0 < len && name0[i0] != '\'')
{
name[i] = name0[i0];
i += 1; i0 += 1;
}
i0 += 1;
break;
case '<':
i0 += 1;
while (i0 < len && name0[i0] != '>')
{
name[i] = name0[i0];
i += 1; i0 += 1;
}
i0 += 1;
break;
}
}
name[i] = '\000';
yylval.ssym.sym = NULL;
yylval.ssym.stoken.ptr = name;
yylval.ssym.stoken.length = i;
return NAME;
}
static void
block_lookup (name, err_name)
char* name;
char* err_name;
{
struct symbol** syms;
struct block** blocks;
int nsyms;
struct symtab *symtab;
nsyms = ada_lookup_symbol_list (name, left_block_context,
VAR_DOMAIN, &syms, &blocks);
if (left_block_context == NULL &&
(nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK))
symtab = lookup_symtab (name);
else
symtab = NULL;
if (symtab != NULL)
left_block_context = yylval.bval =
BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
else if (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK)
{
if (left_block_context == NULL)
error ("No file or function \"%s\".", err_name);
else
error ("No function \"%s\" in specified context.", err_name);
}
else
{
left_block_context = yylval.bval = SYMBOL_BLOCK_VALUE (syms[0]);
if (nsyms > 1)
warning ("Function name \"%s\" ambiguous here", err_name);
}
}
/* Look up NAME0 (assumed to be mangled) as a name in VAR_DOMAIN,
setting *TOKEN_TYPE to NAME or TYPENAME, depending on what is
found. Try first the entire name, then the name without the last
segment (i.e., after the last .id), etc., and return the number of
segments that had to be removed to get a match. Calls error if no
matches are found, using ERR_NAME in any error message. When
exactly one symbol match is found, it is placed in yylval. */
static int
name_lookup (name0, err_name, token_type)
char* name0;
char* err_name;
int* token_type;
{
struct symbol** syms;
struct block** blocks;
struct type* type;
int len0 = strlen (name0);
char* name = savestring (name0, len0);
int nsyms;
int segments;
/* add_name_string_cleanup (name);*/
/* FIXME: add_name_string_cleanup should be defined in parse.c */
yylval.ssym.stoken.ptr = name;
yylval.ssym.stoken.length = strlen (name);
for (segments = 0; ; segments += 1)
{
struct type* preferred_type;
int i, preferred_index;
if (left_block_context == NULL)
nsyms = ada_lookup_symbol_list (name, expression_context_block,
VAR_DOMAIN, &syms, &blocks);
else
nsyms = ada_lookup_symbol_list (name, left_block_context,
VAR_DOMAIN, &syms, &blocks);
/* Check for a type definition. */
/* Look for a symbol that doesn't denote void. This is (I think) a */
/* temporary kludge to get around problems in GNAT output. */
preferred_index = -1; preferred_type = NULL;
for (i = 0; i < nsyms; i += 1)
switch (SYMBOL_CLASS (syms[i]))
{
case LOC_TYPEDEF:
if (ada_prefer_type (SYMBOL_TYPE (syms[i]), preferred_type))
{
preferred_index = i;
preferred_type = SYMBOL_TYPE (syms[i]);
}
break;
case LOC_REGISTER:
case LOC_ARG:
case LOC_REF_ARG:
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_LOCAL:
case LOC_LOCAL_ARG:
case LOC_BASEREG:
case LOC_BASEREG_ARG:
goto NotType;
default:
break;
}
if (preferred_type != NULL)
{
/* if (TYPE_CODE (preferred_type) == TYPE_CODE_VOID)
error ("`%s' matches only void type name(s)",
ada_demangle (name));
*/
/* FIXME: ada_demangle should be defined in defs.h, and is located in ada-lang.c */
/* else*/ if (ada_is_object_renaming (syms[preferred_index]))
{
yylval.ssym.sym = syms[preferred_index];
*token_type = OBJECT_RENAMING;
return segments;
}
else if (ada_renaming_type (SYMBOL_TYPE (syms[preferred_index]))
!= NULL)
{
int result;
const char* renaming =
ada_simple_renamed_entity (syms[preferred_index]);
char* new_name = xmalloc (strlen (renaming) + len0
- yylval.ssym.stoken.length + 1);
/* add_name_string_cleanup (new_name);*/
/* FIXME: add_name_string_cleanup should be defined in parse.c */
strcpy (new_name, renaming);
strcat (new_name, name0 + yylval.ssym.stoken.length);
result = name_lookup (new_name, err_name, token_type);
if (result > segments)
error ("Confused by renamed symbol.");
return result;
}
else if (segments == 0)
{
yylval.tval = preferred_type;
*token_type = TYPENAME;
return 0;
}
}
if (segments == 0)
{
type = lookup_primitive_typename (name);
if (type == NULL && DEPRECATED_STREQ ("system__address", name))
type = builtin_type_ada_system_address;
if (type != NULL)
{
yylval.tval = type;
*token_type = TYPENAME;
return 0;
}
}
NotType:
if (nsyms == 1)
{
*token_type = NAME;
yylval.ssym.sym = syms[0];
yylval.ssym.msym = NULL;
yylval.ssym.block = blocks[0];
return segments;
}
else if (nsyms == 0) {
int i;
yylval.ssym.msym = ada_lookup_minimal_symbol (name);
if (yylval.ssym.msym != NULL)
{
yylval.ssym.sym = NULL;
yylval.ssym.block = NULL;
*token_type = NAME;
return segments;
}
for (i = yylval.ssym.stoken.length - 1; i > 0; i -= 1)
{
if (name[i] == '.')
{
name[i] = '\0';
yylval.ssym.stoken.length = i;
break;
}
else if (name[i] == '_' && name[i-1] == '_')
{
i -= 1;
name[i] = '\0';
yylval.ssym.stoken.length = i;
break;
}
}
if (i <= 0)
{
if (!have_full_symbols () && !have_partial_symbols ()
&& left_block_context == NULL)
error ("No symbol table is loaded. Use the \"file\" command.");
if (left_block_context == NULL)
error ("No definition of \"%s\" in current context.",
err_name);
else
error ("No definition of \"%s\" in specified context.",
err_name);
}
}
else
{
*token_type = NAME;
yylval.ssym.sym = NULL;
yylval.ssym.msym = NULL;
if (left_block_context == NULL)
yylval.ssym.block = expression_context_block;
else
yylval.ssym.block = left_block_context;
return segments;
}
}
}
/* Returns the position within STR of the '.' in a
'.{WHITE}*all' component of a dotted name, or -1 if there is none. */
static int
find_dot_all (str)
const char* str;
{
int i;
for (i = 0; str[i] != '\000'; i += 1)
{
if (str[i] == '.')
{
int i0 = i;
do
i += 1;
while (isspace (str[i]));
if (strcmp (str+i, "all") == 0
&& ! isalnum (str[i+3]) && str[i+3] != '_')
return i0;
}
}
return -1;
}
/* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
case. */
static int
subseqMatch (subseq, str)
const char* subseq;
const char* str;
{
if (subseq[0] == '\0')
return 1;
else if (str[0] == '\0')
return 0;
else if (tolower (subseq[0]) == tolower (str[0]))
return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
else
return subseqMatch (subseq, str+1);
}
static struct { const char* name; int code; }
attributes[] = {
{ "address", TICK_ADDRESS },
{ "unchecked_access", TICK_ACCESS },
{ "unrestricted_access", TICK_ACCESS },
{ "access", TICK_ACCESS },
{ "first", TICK_FIRST },
{ "last", TICK_LAST },
{ "length", TICK_LENGTH },
{ "max", TICK_MAX },
{ "min", TICK_MIN },
{ "modulus", TICK_MODULUS },
{ "pos", TICK_POS },
{ "range", TICK_RANGE },
{ "size", TICK_SIZE },
{ "tag", TICK_TAG },
{ "val", TICK_VAL },
{ NULL, -1 }
};
/* Return the syntactic code corresponding to the attribute name or
abbreviation STR. */
static int
processAttribute (str)
const char* str;
{
int i, k;
for (i = 0; attributes[i].code != -1; i += 1)
if (strcasecmp (str, attributes[i].name) == 0)
return attributes[i].code;
for (i = 0, k = -1; attributes[i].code != -1; i += 1)
if (subseqMatch (str, attributes[i].name))
{
if (k == -1)
k = i;
else
error ("ambiguous attribute name: `%s'", str);
}
if (k == -1)
error ("unrecognized attribute: `%s'", str);
return attributes[k].code;
}
int
yywrap()
{
return 1;
}

819
contrib/gdb/gdb/ada-tasks.c Normal file
View file

@ -0,0 +1,819 @@
/* file ada-tasks.c: Ada tasking control for GDB
Copyright 1997 Free Software Foundation, Inc.
Contributed by Ada Core Technologies, Inc
.
This file is part of GDB.
[$Id: ada-tasks.c,v 1.7 2003/06/17 20:58:32 ciceron Exp $]
Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.com>
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 2 of the License, or
(at your option) any later version.
*/
#include <ctype.h>
#include "defs.h"
#include "command.h"
#include "value.h"
#include "language.h"
#include "inferior.h"
#include "symtab.h"
#include "target.h"
#include "regcache.h"
#include "gdbcore.h"
#if (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks))
#include <sys/procfs.h>
#endif
#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
#include "gregset.h"
#endif
#include "ada-lang.h"
/* FIXME: move all this conditional compilation in description
files or in configure.in */
#if defined (VXWORKS_TARGET)
#define THREAD_TO_PID(tid,lwpid) (tid)
#elif defined (linux)
#define THREAD_TO_PID(tid,lwpid) (0)
#elif (defined (sun) && defined (__SVR4))
#define THREAD_TO_PID thread_to_pid
#elif defined (sgi) || defined (__WIN32__) || defined (hpux)
#define THREAD_TO_PID(tid,lwpid) ((int)lwpid)
#else
#define THREAD_TO_PID(tid,lwpid) (0)
#endif
#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
#define THREAD_FETCH_REGISTERS dec_thread_fetch_registers
#define GET_CURRENT_THREAD dec_thread_get_current_thread
extern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *);
#endif
#if defined (_AIX)
#define THREAD_FETCH_REGISTERS aix_thread_fetch_registers
#define GET_CURRENT_THREAD aix_thread_get_current_thread
#endif
#if defined(VXWORKS_TARGET)
#define GET_CURRENT_THREAD() ((void*)inferior_pid)
#define THREAD_FETCH_REGISTERS() (-1)
#elif defined (sun) && defined (__SVR4)
#define GET_CURRENT_THREAD solaris_thread_get_current_thread
#define THREAD_FETCH_REGISTERS() (-1)
extern void *GET_CURRENT_THREAD ();
#elif defined (_AIX) || (defined(__alpha__) && defined(__osf__))
extern void *GET_CURRENT_THREAD ();
#elif defined (__WIN32__) || defined (hpux)
#define GET_CURRENT_THREAD() (inferior_pid)
#define THREAD_FETCH_REGISTERS() (-1)
#else
#define GET_CURRENT_THREAD() (NULL)
#define THREAD_FETCH_REGISTERS() (-1)
#endif
#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks"
#define READ_MEMORY(addr, var) read_memory (addr, (char*) &var, sizeof (var))
/* external declarations */
/* Global visible variables */
struct task_entry *task_list = NULL;
int ada__tasks_check_symbol_table = 1;
void *pthread_kern_addr = NULL;
#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
gdb_gregset_t gregset_saved;
gdb_fpregset_t fpregset_saved;
#endif
/* The maximum number of tasks known to the Ada runtime */
const int MAX_NUMBER_OF_KNOWN_TASKS = 1000;
/* the current task */
int current_task = -1, current_task_id = -1, current_task_index;
void *current_thread, *current_lwp;
char *ada_task_states[] = {
"Unactivated",
"Runnable",
"Terminated",
"Child Activation Wait",
"Accept Statement",
"Waiting on entry call",
"Async Select Wait",
"Delay Sleep",
"Child Termination Wait",
"Wait Child in Term Alt",
"",
"",
"",
"",
"Asynchronous Hold"
};
/* Global internal types */
static char *ada_long_task_states[] = {
"Unactivated",
"Runnable",
"Terminated",
"Waiting for child activation",
"Blocked in accept statement",
"Waiting on entry call",
"Asynchronous Selective Wait",
"Delay Sleep",
"Waiting for children termination",
"Waiting for children in terminate alternative",
"",
"",
"",
"",
"Asynchronous Hold"
};
/* Global internal variables */
static int highest_task_num = 0;
int thread_support = 0; /* 1 if the thread library in use is supported */
static int gdbtk_task_initialization = 0;
static int
add_task_entry (void *p_task_id, int index)
{
struct task_entry *new_task_entry = NULL;
struct task_entry *pt;
highest_task_num++;
new_task_entry = xmalloc (sizeof (struct task_entry));
new_task_entry->task_num = highest_task_num;
new_task_entry->task_id = p_task_id;
new_task_entry->known_tasks_index = index;
new_task_entry->next_task = NULL;
pt = task_list;
if (pt)
{
while (pt->next_task)
pt = pt->next_task;
pt->next_task = new_task_entry;
pt->stack_per = 0;
}
else
task_list = new_task_entry;
return new_task_entry->task_num;
}
int
get_entry_number (void *p_task_id)
{
struct task_entry *pt;
pt = task_list;
while (pt != NULL)
{
if (pt->task_id == p_task_id)
return pt->task_num;
pt = pt->next_task;
}
return 0;
}
static struct task_entry *
get_thread_entry_vptr (void *thread)
{
struct task_entry *pt;
pt = task_list;
while (pt != NULL)
{
if (pt->thread == thread)
return pt;
pt = pt->next_task;
}
return 0;
}
static struct task_entry *
get_entry_vptr (int p_task_num)
{
struct task_entry *pt;
pt = task_list;
while (pt)
{
if (pt->task_num == p_task_num)
return pt;
pt = pt->next_task;
}
return NULL;
}
void
init_task_list (void)
{
struct task_entry *pt, *old_pt;
pt = task_list;
while (pt)
{
old_pt = pt;
pt = pt->next_task;
xfree (old_pt);
};
task_list = NULL;
highest_task_num = 0;
}
int
valid_task_id (int task)
{
return get_entry_vptr (task) != NULL;
}
void *
get_self_id (void)
{
struct value *val;
void *self_id;
int result;
struct task_entry *ent;
extern int do_not_insert_breakpoints;
#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__))
if (thread_support)
#endif
{
ent = get_thread_entry_vptr (GET_CURRENT_THREAD ());
return ent ? ent->task_id : 0;
}
/* FIXME: calling a function in the inferior with a multithreaded application
is not reliable, so return NULL if there is no safe way to get the current
task */
return NULL;
}
int
get_current_task (void)
{
int result;
/* FIXME: language_ada should be defined in defs.h */
/* if (current_language->la_language != language_ada) return -1; */
result = get_entry_number (get_self_id ());
/* return -1 if not found */
return result == 0 ? -1 : result;
}
/* Print detailed information about specified task */
static void
info_task (char *arg, int from_tty)
{
void *temp_task;
struct task_entry *pt, *pt2;
void *self_id, *caller;
struct task_fields atcb, atcb2;
struct entry_call call;
int bounds[2];
char image[256];
int num;
/* FIXME: language_ada should be defined in defs.h */
/* if (current_language->la_language != language_ada)
{
printf_filtered ("The current language does not support tasks.\n");
return;
}
*/
pt = get_entry_vptr (atoi (arg));
if (pt == NULL)
{
printf_filtered ("Task %s not found.\n", arg);
return;
}
temp_task = pt->task_id;
/* read the atcb in the inferior */
READ_MEMORY ((CORE_ADDR) temp_task, atcb);
/* print the Ada task id */
printf_filtered ("Ada Task: %p\n", temp_task);
/* print the name of the task */
if (atcb.image.P_ARRAY != NULL)
{
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
bounds[1] = EXTRACT_INT (bounds[1]);
read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
(char *) &image, bounds[1]);
printf_filtered ("Name: %.*s\n", bounds[1], image);
}
else
printf_filtered ("<no name>\n");
/* print the thread id */
if ((long) pt->thread < 65536)
printf_filtered ("Thread: %ld\n", (long int) pt->thread);
else
printf_filtered ("Thread: %p\n", pt->thread);
if ((long) pt->lwp != 0)
{
if ((long) pt->lwp < 65536)
printf_filtered ("LWP: %ld\n", (long int) pt->lwp);
else
printf_filtered ("LWP: %p\n", pt->lwp);
}
/* print the parent gdb task id */
num = get_entry_number (EXTRACT_ADDRESS (atcb.parent));
if (num != 0)
{
printf_filtered ("Parent: %d", num);
pt2 = get_entry_vptr (num);
READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
/* print the name of the task */
if (atcb2.image.P_ARRAY != NULL)
{
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
bounds);
bounds[1] = EXTRACT_INT (bounds[1]);
read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
(char *) &image, bounds[1]);
printf_filtered (" (%.*s)\n", bounds[1], image);
}
else
printf_filtered ("\n");
}
else
printf_filtered ("No parent\n");
/* print the base priority of the task */
printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority));
/* print the current state of the task */
/* check if this task is accepting a rendezvous */
if (atcb.call == NULL)
caller = NULL;
else
{
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
caller = EXTRACT_ADDRESS (call.self);
}
if (caller != NULL)
{
num = get_entry_number (caller);
printf_filtered ("Accepting rendezvous with %d", num);
if (num != 0)
{
pt2 = get_entry_vptr (num);
READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
/* print the name of the task */
if (atcb2.image.P_ARRAY != NULL)
{
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
bounds);
bounds[1] = EXTRACT_INT (bounds[1]);
read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
(char *) &image, bounds[1]);
printf_filtered (" (%.*s)\n", bounds[1], image);
}
else
printf_filtered ("\n");
}
else
printf_filtered ("\n");
}
else
printf_filtered ("State: %s\n", ada_long_task_states[atcb.state]);
}
#if 0
/* A useful function that shows the alignment of all the fields in the
tasks_fields structure
*/
print_align (void)
{
struct task_fields tf;
void *tf_base = &(tf);
void *tf_state = &(tf.state);
void *tf_entry_num = &(tf.entry_num);
void *tf_parent = &(tf.parent);
void *tf_priority = &(tf.priority);
void *tf_current_priority = &(tf.current_priority);
void *tf_image = &(tf.image);
void *tf_call = &(tf.call);
void *tf_thread = &(tf.thread);
void *tf_lwp = &(tf.lwp);
printf_filtered ("\n");
printf_filtered ("(tf_base = 0x%x)\n", tf_base);
printf_filtered ("task_fields.entry_num at %3d (0x%x)\n",
tf_entry_num - tf_base, tf_entry_num);
printf_filtered ("task_fields.state at %3d (0x%x)\n",
tf_state - tf_base, tf_state);
printf_filtered ("task_fields.parent at %3d (0x%x)\n",
tf_parent - tf_base, tf_parent);
printf_filtered ("task_fields.priority at %3d (0x%x)\n",
tf_priority - tf_base, tf_priority);
printf_filtered ("task_fields.current_priority at %3d (0x%x)\n",
tf_current_priority - tf_base, tf_current_priority);
printf_filtered ("task_fields.image at %3d (0x%x)\n",
tf_image - tf_base, tf_image);
printf_filtered ("task_fields.call at %3d (0x%x)\n",
tf_call - tf_base, tf_call);
printf_filtered ("task_fields.thread at %3d (0x%x)\n",
tf_thread - tf_base, tf_thread);
printf_filtered ("task_fields.lwp at %3d (0x%x)\n",
tf_lwp - tf_base, tf_lwp);
printf_filtered ("\n");
}
#endif
/* Print information about currently known tasks */
static void
info_tasks (char *arg, int from_tty)
{
struct value *val;
int i, task_number, state;
void *temp_task, *temp_tasks[MAX_NUMBER_OF_KNOWN_TASKS];
struct task_entry *pt;
void *self_id, *caller, *thread_id = NULL;
struct task_fields atcb;
struct entry_call call;
int bounds[2];
char image[256];
int size;
char car;
#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
pthreadTeb_t thr;
gdb_gregset_t regs;
#endif
static struct symbol *sym;
static struct minimal_symbol *msym;
static void *known_tasks_addr = NULL;
int init_only = gdbtk_task_initialization;
gdbtk_task_initialization = 0;
task_number = 0;
if (PIDGET (inferior_ptid) == 0)
{
printf_filtered ("The program is not being run under gdb. ");
printf_filtered ("Use 'run' or 'attach' first.\n");
return;
}
if (ada__tasks_check_symbol_table)
{
thread_support = 0;
#if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \
defined (_AIX)
thread_support = 1;
#endif
msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
if (msym != NULL)
known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym);
else
#ifndef VXWORKS_TARGET
return;
#else
{
if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0)
return;
}
#endif
ada__tasks_check_symbol_table = 0;
}
if (known_tasks_addr == NULL)
return;
#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux))
if (thread_support)
#endif
thread_id = GET_CURRENT_THREAD ();
/* then we get a list of tasks created */
init_task_list ();
READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks);
for (i = 0; i < MAX_NUMBER_OF_KNOWN_TASKS; i++)
{
temp_task = EXTRACT_ADDRESS (temp_tasks[i]);
if (temp_task != NULL)
{
task_number = get_entry_number (temp_task);
if (task_number == 0)
task_number = add_task_entry (temp_task, i);
}
}
/* Return without printing anything if this function was called in
order to init GDBTK tasking. */
if (init_only)
return;
/* print the header */
#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
printf_filtered
(" ID TID P-ID Pri Stack %% State Name\n");
#else
printf_filtered (" ID TID P-ID Pri State Name\n");
#endif
/* Now that we have a list of task id's, we can print them */
pt = task_list;
while (pt)
{
temp_task = pt->task_id;
/* read the atcb in the inferior */
READ_MEMORY ((CORE_ADDR) temp_task, atcb);
/* store the thread id for future use */
pt->thread = EXTRACT_ADDRESS (atcb.thread);
#if defined (linux)
pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0);
#else
pt->lwp = EXTRACT_ADDRESS (atcb.lwp);
#endif
/* print a star if this task is the current one */
if (thread_id)
#if defined (__WIN32__) || defined (SGI) || defined (hpux)
printf_filtered (pt->lwp == thread_id ? "*" : " ");
#else
printf_filtered (pt->thread == thread_id ? "*" : " ");
#endif
/* print the gdb task id */
printf_filtered ("%3d", pt->task_num);
/* print the Ada task id */
#ifndef VXWORKS_TARGET
printf_filtered (" %9lx", (long) temp_task);
#else
#ifdef TARGET_64
printf_filtered (" %#9lx", (unsigned long) pt->thread & 0x3ffffffffff);
#else
printf_filtered (" %#9lx", (long) pt->thread);
#endif
#endif
/* print the parent gdb task id */
printf_filtered
(" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent)));
/* print the base priority of the task */
printf_filtered (" %3d", EXTRACT_INT (atcb.priority));
#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
if (pt->task_num == 1 || atcb.state == Terminated)
{
printf_filtered (" Unknown");
goto next;
}
read_memory ((CORE_ADDR) atcb.thread, &thr, sizeof (thr));
current_thread = atcb.thread;
regs.regs[SP_REGNUM] = 0;
if (dec_thread_get_registers (&regs, NULL) == 0)
{
pt->stack_per = (100 * ((long) thr.__stack_base -
regs.regs[SP_REGNUM])) / thr.__stack_size;
/* if the thread is terminated but still there, the
stack_base/size values are erroneous. Try to patch it */
if (pt->stack_per < 0 || pt->stack_per > 100)
pt->stack_per = 0;
}
/* print information about stack space used in the thread */
if (thr.__stack_size < 1024 * 1024)
{
size = thr.__stack_size / 1024;
car = 'K';
}
else if (thr.__stack_size < 1024 * 1024 * 1024)
{
size = thr.__stack_size / 1024 / 1024;
car = 'M';
}
else /* Who knows... */
{
size = thr.__stack_size / 1024 / 1024 / 1024;
car = 'G';
}
printf_filtered (" %4d%c %2d", size, car, pt->stack_per);
next:
#endif
/* print the current state of the task */
/* check if this task is accepting a rendezvous */
if (atcb.call == NULL)
caller = NULL;
else
{
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
caller = EXTRACT_ADDRESS (call.self);
}
if (caller != NULL)
printf_filtered (" Accepting RV with %-4d",
get_entry_number (caller));
else
{
state = atcb.state;
#if defined (__WIN32__) || defined (SGI) || defined (hpux)
if (state == Runnable && (thread_id && pt->lwp == thread_id))
#else
if (state == Runnable && (thread_id && pt->thread == thread_id))
#endif
/* Replace "Runnable" by "Running" if this is the current task */
printf_filtered (" %-22s", "Running");
else
printf_filtered (" %-22s", ada_task_states[state]);
}
/* finally, print the name of the task */
if (atcb.image.P_ARRAY != NULL)
{
READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS),
bounds);
bounds[1] = EXTRACT_INT (bounds[1]);
read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
(char *) &image, bounds[1]);
printf_filtered (" %.*s\n", bounds[1], image);
}
else
printf_filtered (" <no name>\n");
pt = pt->next_task;
}
}
/* Task list initialization for GDB-Tk. We basically use info_tasks()
to initialize our variables, but abort that function before we
actually print anything. */
int
gdbtk_tcl_tasks_initialize (void)
{
gdbtk_task_initialization = 1;
info_tasks ("", gdb_stdout);
return (task_list != NULL);
}
static void
info_tasks_command (char *arg, int from_tty)
{
if (arg == NULL || *arg == '\000')
info_tasks (arg, from_tty);
else
info_task (arg, from_tty);
}
/* Switch from one thread to another. */
static void
switch_to_thread (ptid_t ptid)
{
if (ptid_equal (ptid, inferior_ptid))
return;
inferior_ptid = ptid;
flush_cached_frames ();
registers_changed ();
stop_pc = read_pc ();
select_frame (get_current_frame ());
}
/* Switch to a specified task. */
static int
task_switch (void *tid, void *lwpid)
{
int res = 0, pid;
if (thread_support)
{
flush_cached_frames ();
if (current_task != current_task_id)
{
res = THREAD_FETCH_REGISTERS ();
}
else
{
#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
supply_gregset (&gregset_saved);
supply_fpregset (&fpregset_saved);
#endif
}
if (res == 0)
stop_pc = read_pc ();
select_frame (get_current_frame ());
return res;
}
return -1;
}
static void
task_command (char *tidstr, int from_tty)
{
int num;
struct task_entry *e;
if (!tidstr)
error ("Please specify a task ID. Use the \"info tasks\" command to\n"
"see the IDs of currently known tasks.");
num = atoi (tidstr);
e = get_entry_vptr (num);
if (e == NULL)
error ("Task ID %d not known. Use the \"info tasks\" command to\n"
"see the IDs of currently known tasks.", num);
if (current_task_id == -1)
{
#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
fill_gregset (&gregset_saved, -1);
fill_fpregset (&fpregset_saved, -1);
#endif
current_task_id = get_current_task ();
}
current_task = num;
current_task_index = e->known_tasks_index;
current_thread = e->thread;
current_lwp = e->lwp;
if (task_switch (e->thread, e->lwp) == 0)
{
/* FIXME: find_printable_frame should be defined in frame.h, and
implemented in ada-lang.c */
/* find_printable_frame (deprecated_selected_frame, frame_relative_level (deprecated_selected_frame)); */
printf_filtered ("[Switching to task %d]\n", num);
print_stack_frame (deprecated_selected_frame,
frame_relative_level (deprecated_selected_frame), 1);
}
else
printf_filtered ("Unable to switch to task %d\n", num);
}
void
_initialize_tasks (void)
{
static struct cmd_list_element *task_cmd_list = NULL;
extern struct cmd_list_element *cmdlist;
add_info ("tasks", info_tasks_command,
"Without argument: list all known Ada tasks, with status information.\n"
"info tasks n: print detailed information of task n.\n");
add_prefix_cmd ("task", class_run, task_command,
"Use this command to switch between tasks.\n\
The new task ID must be currently known.", &task_cmd_list, "task ", 1, &cmdlist);
}

View file

@ -0,0 +1,852 @@
/* Support for printing Ada types for GDB, the GNU debugger.
Copyright 1986, 1988, 1989, 1991, 1997, 2003 Free Software
Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "gdb_obstack.h"
#include "bfd.h" /* Binary File Description */
#include "symtab.h"
#include "gdbtypes.h"
#include "expression.h"
#include "value.h"
#include "gdbcore.h"
#include "target.h"
#include "command.h"
#include "gdbcmd.h"
#include "language.h"
#include "demangle.h"
#include "c-lang.h"
#include "typeprint.h"
#include "ada-lang.h"
#include <ctype.h>
#include "gdb_string.h"
#include <errno.h>
static int print_record_field_types (struct type *, struct type *,
struct ui_file *, int, int);
static void print_array_type (struct type *, struct ui_file *, int, int);
static void print_choices (struct type *, int, struct ui_file *,
struct type *);
static void print_range (struct type *, struct ui_file *);
static void print_range_bound (struct type *, char *, int *,
struct ui_file *);
static void
print_dynamic_range_bound (struct type *, const char *, int,
const char *, struct ui_file *);
static void print_range_type_named (char *, struct ui_file *);
static char *name_buffer;
static int name_buffer_len;
/* The (demangled) Ada name of TYPE. This value persists until the
next call. */
static char *
demangled_type_name (struct type *type)
{
if (ada_type_name (type) == NULL)
return NULL;
else
{
char *raw_name = ada_type_name (type);
char *s, *q;
if (name_buffer == NULL || name_buffer_len <= strlen (raw_name))
{
name_buffer_len = 16 + 2 * strlen (raw_name);
name_buffer = xrealloc (name_buffer, name_buffer_len);
}
strcpy (name_buffer, raw_name);
s = (char *) strstr (name_buffer, "___");
if (s != NULL)
*s = '\0';
s = name_buffer + strlen (name_buffer) - 1;
while (s > name_buffer && (s[0] != '_' || s[-1] != '_'))
s -= 1;
if (s == name_buffer)
return name_buffer;
if (!islower (s[1]))
return NULL;
for (s = q = name_buffer; *s != '\0'; q += 1)
{
if (s[0] == '_' && s[1] == '_')
{
*q = '.';
s += 2;
}
else
{
*q = *s;
s += 1;
}
}
*q = '\0';
return name_buffer;
}
}
/* Print a description of a type in the format of a
typedef for the current language.
NEW is the new name for a type TYPE. */
void
ada_typedef_print (struct type *type, struct symbol *new,
struct ui_file *stream)
{
fprintf_filtered (stream, "type %.*s is ",
ada_name_prefix_len (SYMBOL_PRINT_NAME (new)),
SYMBOL_PRINT_NAME (new));
type_print (type, "", stream, 1);
}
/* Print range type TYPE on STREAM. */
static void
print_range (struct type *type, struct ui_file *stream)
{
struct type *target_type;
target_type = TYPE_TARGET_TYPE (type);
if (target_type == NULL)
target_type = type;
switch (TYPE_CODE (target_type))
{
case TYPE_CODE_RANGE:
case TYPE_CODE_INT:
case TYPE_CODE_BOOL:
case TYPE_CODE_CHAR:
case TYPE_CODE_ENUM:
break;
default:
target_type = builtin_type_ada_int;
break;
}
if (TYPE_NFIELDS (type) < 2)
{
/* A range needs at least 2 bounds to be printed. If there are less
than 2, just print the type name instead of the range itself.
This check handles cases such as characters, for example.
Note that if the name is not defined, then we don't print anything.
*/
fprintf_filtered (stream, "%.*s",
ada_name_prefix_len (TYPE_NAME (type)),
TYPE_NAME (type));
}
else
{
/* We extract the range type bounds respectively from the first element
and the last element of the type->fields array */
const LONGEST lower_bound = (LONGEST) TYPE_LOW_BOUND (type);
const LONGEST upper_bound =
(LONGEST) TYPE_FIELD_BITPOS (type, TYPE_NFIELDS (type) - 1);
ada_print_scalar (target_type, lower_bound, stream);
fprintf_filtered (stream, " .. ");
ada_print_scalar (target_type, upper_bound, stream);
}
}
/* Print the number or discriminant bound at BOUNDS+*N on STREAM, and
set *N past the bound and its delimiter, if any. */
static void
print_range_bound (struct type *type, char *bounds, int *n,
struct ui_file *stream)
{
LONGEST B;
if (ada_scan_number (bounds, *n, &B, n))
{
ada_print_scalar (type, B, stream);
if (bounds[*n] == '_')
*n += 2;
}
else
{
int bound_len;
char *bound = bounds + *n;
char *pend;
pend = strstr (bound, "__");
if (pend == NULL)
*n += bound_len = strlen (bound);
else
{
bound_len = pend - bound;
*n += bound_len + 2;
}
fprintf_filtered (stream, "%.*s", bound_len, bound);
}
}
/* Assuming NAME[0 .. NAME_LEN-1] is the name of a range type, print
the value (if found) of the bound indicated by SUFFIX ("___L" or
"___U") according to the ___XD conventions. */
static void
print_dynamic_range_bound (struct type *type, const char *name, int name_len,
const char *suffix, struct ui_file *stream)
{
static char *name_buf = NULL;
static size_t name_buf_len = 0;
LONGEST B;
int OK;
GROW_VECT (name_buf, name_buf_len, name_len + strlen (suffix) + 1);
strncpy (name_buf, name, name_len);
strcpy (name_buf + name_len, suffix);
B = get_int_var_value (name_buf, 0, &OK);
if (OK)
ada_print_scalar (type, B, stream);
else
fprintf_filtered (stream, "?");
}
/* Print the range type named NAME. */
static void
print_range_type_named (char *name, struct ui_file *stream)
{
struct type *raw_type = ada_find_any_type (name);
struct type *base_type;
LONGEST low, high;
char *subtype_info;
if (raw_type == NULL)
base_type = builtin_type_int;
else if (TYPE_CODE (raw_type) == TYPE_CODE_RANGE)
base_type = TYPE_TARGET_TYPE (raw_type);
else
base_type = raw_type;
subtype_info = strstr (name, "___XD");
if (subtype_info == NULL && raw_type == NULL)
fprintf_filtered (stream, "? .. ?");
else if (subtype_info == NULL)
print_range (raw_type, stream);
else
{
int prefix_len = subtype_info - name;
char *bounds_str;
int n;
subtype_info += 5;
bounds_str = strchr (subtype_info, '_');
n = 1;
if (*subtype_info == 'L')
{
print_range_bound (raw_type, bounds_str, &n, stream);
subtype_info += 1;
}
else
print_dynamic_range_bound (raw_type, name, prefix_len, "___L",
stream);
fprintf_filtered (stream, " .. ");
if (*subtype_info == 'U')
print_range_bound (raw_type, bounds_str, &n, stream);
else
print_dynamic_range_bound (raw_type, name, prefix_len, "___U",
stream);
}
}
/* Print enumerated type TYPE on STREAM. */
static void
print_enum_type (struct type *type, struct ui_file *stream)
{
int len = TYPE_NFIELDS (type);
int i, lastval;
fprintf_filtered (stream, "(");
wrap_here (" ");
lastval = 0;
for (i = 0; i < len; i++)
{
QUIT;
if (i)
fprintf_filtered (stream, ", ");
wrap_here (" ");
fputs_filtered (ada_enum_name (TYPE_FIELD_NAME (type, i)), stream);
if (lastval != TYPE_FIELD_BITPOS (type, i))
{
fprintf_filtered (stream, " => %d", TYPE_FIELD_BITPOS (type, i));
lastval = TYPE_FIELD_BITPOS (type, i);
}
lastval += 1;
}
fprintf_filtered (stream, ")");
}
/* Print representation of Ada fixed-point type TYPE on STREAM. */
static void
print_fixed_point_type (struct type *type, struct ui_file *stream)
{
DOUBLEST delta = ada_delta (type);
DOUBLEST small = ada_fixed_to_float (type, 1.0);
if (delta < 0.0)
fprintf_filtered (stream, "delta ??");
else
{
fprintf_filtered (stream, "delta %g", (double) delta);
if (delta != small)
fprintf_filtered (stream, " <'small = %g>", (double) small);
}
}
/* Print representation of special VAX floating-point type TYPE on STREAM. */
static void
print_vax_floating_point_type (struct type *type, struct ui_file *stream)
{
fprintf_filtered (stream, "<float format %c>",
ada_vax_float_type_suffix (type));
}
/* Print simple (constrained) array type TYPE on STREAM. LEVEL is the
recursion (indentation) level, in case the element type itself has
nested structure, and SHOW is the number of levels of internal
structure to show (see ada_print_type). */
static void
print_array_type (struct type *type, struct ui_file *stream, int show,
int level)
{
int bitsize;
int n_indices;
bitsize = 0;
fprintf_filtered (stream, "array (");
n_indices = -1;
if (show < 0)
fprintf_filtered (stream, "...");
else
{
if (ada_is_packed_array_type (type))
type = ada_coerce_to_simple_array_type (type);
if (ada_is_simple_array (type))
{
struct type *range_desc_type =
ada_find_parallel_type (type, "___XA");
struct type *arr_type;
bitsize = 0;
if (range_desc_type == NULL)
{
for (arr_type = type; TYPE_CODE (arr_type) == TYPE_CODE_ARRAY;
arr_type = TYPE_TARGET_TYPE (arr_type))
{
if (arr_type != type)
fprintf_filtered (stream, ", ");
print_range (TYPE_INDEX_TYPE (arr_type), stream);
if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0)
bitsize = TYPE_FIELD_BITSIZE (arr_type, 0);
}
}
else
{
int k;
n_indices = TYPE_NFIELDS (range_desc_type);
for (k = 0, arr_type = type;
k < n_indices;
k += 1, arr_type = TYPE_TARGET_TYPE (arr_type))
{
if (k > 0)
fprintf_filtered (stream, ", ");
print_range_type_named (TYPE_FIELD_NAME
(range_desc_type, k), stream);
if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0)
bitsize = TYPE_FIELD_BITSIZE (arr_type, 0);
}
}
}
else
{
int i, i0;
for (i = i0 = ada_array_arity (type); i > 0; i -= 1)
fprintf_filtered (stream, "%s<>", i == i0 ? "" : ", ");
}
}
fprintf_filtered (stream, ") of ");
wrap_here ("");
ada_print_type (ada_array_element_type (type, n_indices), "", stream,
show == 0 ? 0 : show - 1, level + 1);
if (bitsize > 0)
fprintf_filtered (stream, " <packed: %d-bit elements>", bitsize);
}
/* Print the choices encoded by field FIELD_NUM of variant-part TYPE on
STREAM, assuming the VAL_TYPE is the type of the values. */
static void
print_choices (struct type *type, int field_num, struct ui_file *stream,
struct type *val_type)
{
int have_output;
int p;
const char *name = TYPE_FIELD_NAME (type, field_num);
have_output = 0;
/* Skip over leading 'V': NOTE soon to be obsolete. */
if (name[0] == 'V')
{
if (!ada_scan_number (name, 1, NULL, &p))
goto Huh;
}
else
p = 0;
while (1)
{
switch (name[p])
{
default:
return;
case 'S':
case 'R':
case 'O':
if (have_output)
fprintf_filtered (stream, " | ");
have_output = 1;
break;
}
switch (name[p])
{
case 'S':
{
LONGEST W;
if (!ada_scan_number (name, p + 1, &W, &p))
goto Huh;
ada_print_scalar (val_type, W, stream);
break;
}
case 'R':
{
LONGEST L, U;
if (!ada_scan_number (name, p + 1, &L, &p)
|| name[p] != 'T' || !ada_scan_number (name, p + 1, &U, &p))
goto Huh;
ada_print_scalar (val_type, L, stream);
fprintf_filtered (stream, " .. ");
ada_print_scalar (val_type, U, stream);
break;
}
case 'O':
fprintf_filtered (stream, "others");
p += 1;
break;
}
}
Huh:
fprintf_filtered (stream, "??");
}
/* Assuming that field FIELD_NUM of TYPE is a VARIANTS field whose
discriminant is contained in OUTER_TYPE, print its variants on STREAM.
LEVEL is the recursion
(indentation) level, in case any of the fields themselves have
nested structure, and SHOW is the number of levels of internal structure
to show (see ada_print_type). For this purpose, fields nested in a
variant part are taken to be at the same level as the fields
immediately outside the variant part. */
static void
print_variant_clauses (struct type *type, int field_num,
struct type *outer_type, struct ui_file *stream,
int show, int level)
{
int i;
struct type *var_type;
struct type *discr_type;
var_type = TYPE_FIELD_TYPE (type, field_num);
discr_type = ada_variant_discrim_type (var_type, outer_type);
if (TYPE_CODE (var_type) == TYPE_CODE_PTR)
{
var_type = TYPE_TARGET_TYPE (var_type);
if (TYPE_FLAGS (var_type) & TYPE_FLAG_STUB)
{
var_type = ada_find_parallel_type (var_type, "___XVU");
if (var_type == NULL)
return;
}
}
for (i = 0; i < TYPE_NFIELDS (var_type); i += 1)
{
fprintf_filtered (stream, "\n%*swhen ", level + 4, "");
print_choices (var_type, i, stream, discr_type);
fprintf_filtered (stream, " =>");
if (print_record_field_types (TYPE_FIELD_TYPE (var_type, i),
outer_type, stream, show, level + 4) <= 0)
fprintf_filtered (stream, " null;");
}
}
/* Assuming that field FIELD_NUM of TYPE is a variant part whose
discriminants are contained in OUTER_TYPE, print a description of it
on STREAM. LEVEL is the recursion (indentation) level, in case any of
the fields themselves have nested structure, and SHOW is the number of
levels of internal structure to show (see ada_print_type). For this
purpose, fields nested in a variant part are taken to be at the same
level as the fields immediately outside the variant part. */
static void
print_variant_part (struct type *type, int field_num, struct type *outer_type,
struct ui_file *stream, int show, int level)
{
fprintf_filtered (stream, "\n%*scase %s is", level + 4, "",
ada_variant_discrim_name
(TYPE_FIELD_TYPE (type, field_num)));
print_variant_clauses (type, field_num, outer_type, stream, show,
level + 4);
fprintf_filtered (stream, "\n%*send case;", level + 4, "");
}
/* Print a description on STREAM of the fields in record type TYPE, whose
discriminants are in OUTER_TYPE. LEVEL is the recursion (indentation)
level, in case any of the fields themselves have nested structure,
and SHOW is the number of levels of internal structure to show
(see ada_print_type). Does not print parent type information of TYPE.
Returns 0 if no fields printed, -1 for an incomplete type, else > 0.
Prints each field beginning on a new line, but does not put a new line at
end. */
static int
print_record_field_types (struct type *type, struct type *outer_type,
struct ui_file *stream, int show, int level)
{
int len, i, flds;
flds = 0;
len = TYPE_NFIELDS (type);
if (len == 0 && (TYPE_FLAGS (type) & TYPE_FLAG_STUB) != 0)
return -1;
for (i = 0; i < len; i += 1)
{
QUIT;
if (ada_is_parent_field (type, i) || ada_is_ignored_field (type, i))
;
else if (ada_is_wrapper_field (type, i))
flds += print_record_field_types (TYPE_FIELD_TYPE (type, i), type,
stream, show, level);
else if (ada_is_variant_part (type, i))
{
print_variant_part (type, i, outer_type, stream, show, level);
flds = 1;
}
else
{
flds += 1;
fprintf_filtered (stream, "\n%*s", level + 4, "");
ada_print_type (TYPE_FIELD_TYPE (type, i),
TYPE_FIELD_NAME (type, i),
stream, show - 1, level + 4);
fprintf_filtered (stream, ";");
}
}
return flds;
}
/* Print record type TYPE on STREAM. LEVEL is the recursion (indentation)
level, in case the element type itself has nested structure, and SHOW is
the number of levels of internal structure to show (see ada_print_type). */
static void
print_record_type (struct type *type0, struct ui_file *stream, int show,
int level)
{
struct type *parent_type;
struct type *type;
type = type0;
if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
{
struct type *type1 = ada_find_parallel_type (type, "___XVE");
if (type1 != NULL)
type = type1;
}
parent_type = ada_parent_type (type);
if (ada_type_name (parent_type) != NULL)
fprintf_filtered (stream, "new %s with ",
demangled_type_name (parent_type));
else if (parent_type == NULL && ada_is_tagged_type (type))
fprintf_filtered (stream, "tagged ");
fprintf_filtered (stream, "record");
if (show < 0)
fprintf_filtered (stream, " ... end record");
else
{
int flds;
flds = 0;
if (parent_type != NULL && ada_type_name (parent_type) == NULL)
flds += print_record_field_types (parent_type, parent_type,
stream, show, level);
flds += print_record_field_types (type, type, stream, show, level);
if (flds > 0)
fprintf_filtered (stream, "\n%*send record", level, "");
else if (flds < 0)
fprintf_filtered (stream, " <incomplete type> end record");
else
fprintf_filtered (stream, " null; end record");
}
}
/* Print the unchecked union type TYPE in something resembling Ada
format on STREAM. LEVEL is the recursion (indentation) level
in case the element type itself has nested structure, and SHOW is the
number of levels of internal structure to show (see ada_print_type). */
static void
print_unchecked_union_type (struct type *type, struct ui_file *stream,
int show, int level)
{
fprintf_filtered (stream, "record (?) is");
if (show < 0)
fprintf_filtered (stream, " ... end record");
else if (TYPE_NFIELDS (type) == 0)
fprintf_filtered (stream, " null; end record");
else
{
int i;
fprintf_filtered (stream, "\n%*scase ? is", level + 4, "");
for (i = 0; i < TYPE_NFIELDS (type); i += 1)
{
fprintf_filtered (stream, "\n%*swhen ? =>\n%*s", level + 8, "",
level + 12, "");
ada_print_type (TYPE_FIELD_TYPE (type, i),
TYPE_FIELD_NAME (type, i),
stream, show - 1, level + 12);
fprintf_filtered (stream, ";");
}
fprintf_filtered (stream, "\n%*send case;\n%*send record",
level + 4, "", level, "");
}
}
/* Print function or procedure type TYPE on STREAM. Make it a header
for function or procedure NAME if NAME is not null. */
static void
print_func_type (struct type *type, struct ui_file *stream, char *name)
{
int i, len = TYPE_NFIELDS (type);
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
fprintf_filtered (stream, "procedure");
else
fprintf_filtered (stream, "function");
if (name != NULL && name[0] != '\0')
fprintf_filtered (stream, " %s", name);
if (len > 0)
{
fprintf_filtered (stream, " (");
for (i = 0; i < len; i += 1)
{
if (i > 0)
{
fputs_filtered ("; ", stream);
wrap_here (" ");
}
fprintf_filtered (stream, "a%d: ", i + 1);
ada_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0);
}
fprintf_filtered (stream, ")");
}
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
{
fprintf_filtered (stream, " return ");
ada_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0);
}
}
/* Print a description of a type TYPE0.
Output goes to STREAM (via stdio).
If VARSTRING is a non-empty string, print as an Ada variable/field
declaration.
SHOW+1 is the maximum number of levels of internal type structure
to show (this applies to record types, enumerated types, and
array types).
SHOW is the number of levels of internal type structure to show
when there is a type name for the SHOWth deepest level (0th is
outer level).
When SHOW<0, no inner structure is shown.
LEVEL indicates level of recursion (for nested definitions). */
void
ada_print_type (struct type *type0, char *varstring, struct ui_file *stream,
int show, int level)
{
enum type_code code;
int demangled_args;
struct type *type = ada_completed_type (ada_get_base_type (type0));
char *type_name = demangled_type_name (type);
int is_var_decl = (varstring != NULL && varstring[0] != '\0');
if (type == NULL)
{
if (is_var_decl)
fprintf_filtered (stream, "%.*s: ",
ada_name_prefix_len (varstring), varstring);
fprintf_filtered (stream, "<null type?>");
return;
}
if (show > 0)
CHECK_TYPEDEF (type);
if (is_var_decl && TYPE_CODE (type) != TYPE_CODE_FUNC)
fprintf_filtered (stream, "%.*s: ",
ada_name_prefix_len (varstring), varstring);
if (type_name != NULL && show <= 0)
{
fprintf_filtered (stream, "%.*s",
ada_name_prefix_len (type_name), type_name);
return;
}
if (ada_is_aligner_type (type))
ada_print_type (ada_aligned_type (type), "", stream, show, level);
else if (ada_is_packed_array_type (type))
print_array_type (type, stream, show, level);
else
switch (TYPE_CODE (type))
{
default:
fprintf_filtered (stream, "<");
c_print_type (type, "", stream, show, level);
fprintf_filtered (stream, ">");
break;
case TYPE_CODE_PTR:
fprintf_filtered (stream, "access ");
ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level);
break;
case TYPE_CODE_REF:
fprintf_filtered (stream, "<ref> ");
ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level);
break;
case TYPE_CODE_ARRAY:
print_array_type (type, stream, show, level);
break;
case TYPE_CODE_INT:
if (ada_is_fixed_point_type (type))
print_fixed_point_type (type, stream);
else if (ada_is_vax_floating_type (type))
print_vax_floating_point_type (type, stream);
else
{
char *name = ada_type_name (type);
if (!ada_is_range_type_name (name))
fprintf_filtered (stream, "<%d-byte integer>",
TYPE_LENGTH (type));
else
{
fprintf_filtered (stream, "range ");
print_range_type_named (name, stream);
}
}
break;
case TYPE_CODE_RANGE:
if (ada_is_fixed_point_type (type))
print_fixed_point_type (type, stream);
else if (ada_is_vax_floating_type (type))
print_vax_floating_point_type (type, stream);
else if (ada_is_modular_type (type))
fprintf_filtered (stream, "mod %ld", (long) ada_modulus (type));
else
{
fprintf_filtered (stream, "range ");
print_range (type, stream);
}
break;
case TYPE_CODE_FLT:
fprintf_filtered (stream, "<%d-byte float>", TYPE_LENGTH (type));
break;
case TYPE_CODE_ENUM:
if (show < 0)
fprintf_filtered (stream, "(...)");
else
print_enum_type (type, stream);
break;
case TYPE_CODE_STRUCT:
if (ada_is_array_descriptor (type))
print_array_type (type, stream, show, level);
else if (ada_is_bogus_array_descriptor (type))
fprintf_filtered (stream,
"array (?) of ? (<mal-formed descriptor>)");
else
print_record_type (type, stream, show, level);
break;
case TYPE_CODE_UNION:
print_unchecked_union_type (type, stream, show, level);
break;
case TYPE_CODE_FUNC:
print_func_type (type, stream, varstring);
break;
}
}

View file

@ -0,0 +1,987 @@
/* Support for printing Ada values for GDB, the GNU debugger.
Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1997, 2001
Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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 <ctype.h>
#include "defs.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "expression.h"
#include "value.h"
#include "demangle.h"
#include "valprint.h"
#include "language.h"
#include "annotate.h"
#include "ada-lang.h"
#include "c-lang.h"
#include "infcall.h"
/* Encapsulates arguments to ada_val_print. */
struct ada_val_print_args
{
struct type *type;
char *valaddr0;
int embedded_offset;
CORE_ADDR address;
struct ui_file *stream;
int format;
int deref_ref;
int recurse;
enum val_prettyprint pretty;
};
static void print_record (struct type *, char *, struct ui_file *, int,
int, enum val_prettyprint);
static int print_field_values (struct type *, char *, struct ui_file *,
int, int, enum val_prettyprint,
int, struct type *, char *);
static int print_variant_part (struct type *, int, char *,
struct ui_file *, int, int,
enum val_prettyprint, int, struct type *,
char *);
static void val_print_packed_array_elements (struct type *, char *valaddr,
int, struct ui_file *, int, int,
enum val_prettyprint);
static void adjust_type_signedness (struct type *);
static int ada_val_print_stub (void *args0);
static int ada_val_print_1 (struct type *, char *, int, CORE_ADDR,
struct ui_file *, int, int, int,
enum val_prettyprint);
/* Make TYPE unsigned if its range of values includes no negatives. */
static void
adjust_type_signedness (struct type *type)
{
if (type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE
&& TYPE_LOW_BOUND (type) >= 0)
TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
}
/* Assuming TYPE is a simple array type, prints its lower bound on STREAM,
if non-standard (i.e., other than 1 for numbers, other than lower bound
of index type for enumerated type). Returns 1 if something printed,
otherwise 0. */
static int
print_optional_low_bound (struct ui_file *stream, struct type *type)
{
struct type *index_type;
long low_bound;
index_type = TYPE_INDEX_TYPE (type);
low_bound = 0;
if (index_type == NULL)
return 0;
if (TYPE_CODE (index_type) == TYPE_CODE_RANGE)
{
low_bound = TYPE_LOW_BOUND (index_type);
index_type = TYPE_TARGET_TYPE (index_type);
}
else
return 0;
switch (TYPE_CODE (index_type))
{
case TYPE_CODE_ENUM:
if (low_bound == TYPE_FIELD_BITPOS (index_type, 0))
return 0;
break;
case TYPE_CODE_UNDEF:
index_type = builtin_type_long;
/* FALL THROUGH */
default:
if (low_bound == 1)
return 0;
break;
}
ada_print_scalar (index_type, (LONGEST) low_bound, stream);
fprintf_filtered (stream, " => ");
return 1;
}
/* Version of val_print_array_elements for GNAT-style packed arrays.
Prints elements of packed array of type TYPE at bit offset
BITOFFSET from VALADDR on STREAM. Formats according to FORMAT and
separates with commas. RECURSE is the recursion (nesting) level.
If PRETTY, uses "prettier" format. TYPE must have been decoded (as
by ada_coerce_to_simple_array). */
static void
val_print_packed_array_elements (struct type *type, char *valaddr,
int bitoffset, struct ui_file *stream,
int format, int recurse,
enum val_prettyprint pretty)
{
unsigned int i;
unsigned int things_printed = 0;
unsigned len;
struct type *elttype;
unsigned eltlen;
/* Position of the array element we are examining to see
whether it is repeated. */
unsigned int rep1;
/* Number of repetitions we have detected so far. */
unsigned int reps;
unsigned long bitsize = TYPE_FIELD_BITSIZE (type, 0);
struct value *mark = value_mark ();
elttype = TYPE_TARGET_TYPE (type);
eltlen = TYPE_LENGTH (check_typedef (elttype));
{
LONGEST low, high;
if (get_discrete_bounds (TYPE_FIELD_TYPE (type, 0), &low, &high) < 0)
len = 1;
else
len = high - low + 1;
}
i = 0;
annotate_array_section_begin (i, elttype);
while (i < len && things_printed < print_max)
{
struct value *v0, *v1;
int i0;
if (i != 0)
{
if (prettyprint_arrays)
{
fprintf_filtered (stream, ",\n");
print_spaces_filtered (2 + 2 * recurse, stream);
}
else
{
fprintf_filtered (stream, ", ");
}
}
wrap_here (n_spaces (2 + 2 * recurse));
i0 = i;
v0 = ada_value_primitive_packed_val (NULL, valaddr,
(i0 * bitsize) / HOST_CHAR_BIT,
(i0 * bitsize) % HOST_CHAR_BIT,
bitsize, elttype);
while (1)
{
i += 1;
if (i >= len)
break;
v1 = ada_value_primitive_packed_val (NULL, valaddr,
(i * bitsize) / HOST_CHAR_BIT,
(i * bitsize) % HOST_CHAR_BIT,
bitsize, elttype);
if (memcmp (VALUE_CONTENTS (v0), VALUE_CONTENTS (v1), eltlen) != 0)
break;
}
if (i - i0 > repeat_count_threshold)
{
val_print (elttype, VALUE_CONTENTS (v0), 0, 0, stream, format,
0, recurse + 1, pretty);
annotate_elt_rep (i - i0);
fprintf_filtered (stream, " <repeats %u times>", i - i0);
annotate_elt_rep_end ();
}
else
{
int j;
for (j = i0; j < i; j += 1)
{
if (j > i0)
{
if (prettyprint_arrays)
{
fprintf_filtered (stream, ",\n");
print_spaces_filtered (2 + 2 * recurse, stream);
}
else
{
fprintf_filtered (stream, ", ");
}
wrap_here (n_spaces (2 + 2 * recurse));
}
val_print (elttype, VALUE_CONTENTS (v0), 0, 0, stream, format,
0, recurse + 1, pretty);
annotate_elt ();
}
}
things_printed += i - i0;
}
annotate_array_section_end ();
if (i < len)
{
fprintf_filtered (stream, "...");
}
value_free_to_mark (mark);
}
static struct type *
printable_val_type (struct type *type, char *valaddr)
{
return ada_to_fixed_type (ada_aligned_type (type), valaddr, 0, NULL);
}
/* Print the character C on STREAM as part of the contents of a literal
string whose delimiter is QUOTER. TYPE_LEN is the length in bytes
(1 or 2) of the character. */
void
ada_emit_char (int c, struct ui_file *stream, int quoter, int type_len)
{
if (type_len != 2)
type_len = 1;
c &= (1 << (type_len * TARGET_CHAR_BIT)) - 1;
if (isascii (c) && isprint (c))
{
if (c == quoter && c == '"')
fprintf_filtered (stream, "[\"%c\"]", quoter);
else
fprintf_filtered (stream, "%c", c);
}
else
fprintf_filtered (stream, "[\"%0*x\"]", type_len * 2, c);
}
/* Character #I of STRING, given that TYPE_LEN is the size in bytes (1
or 2) of a character. */
static int
char_at (char *string, int i, int type_len)
{
if (type_len == 1)
return string[i];
else
return (int) extract_unsigned_integer (string + 2 * i, 2);
}
void
ada_printchar (int c, struct ui_file *stream)
{
fputs_filtered ("'", stream);
ada_emit_char (c, stream, '\'', 1);
fputs_filtered ("'", stream);
}
/* [From print_type_scalar in typeprint.c]. Print VAL on STREAM in a
form appropriate for TYPE. */
void
ada_print_scalar (struct type *type, LONGEST val, struct ui_file *stream)
{
unsigned int i;
unsigned len;
CHECK_TYPEDEF (type);
switch (TYPE_CODE (type))
{
case TYPE_CODE_ENUM:
len = TYPE_NFIELDS (type);
for (i = 0; i < len; i++)
{
if (TYPE_FIELD_BITPOS (type, i) == val)
{
break;
}
}
if (i < len)
{
fputs_filtered (ada_enum_name (TYPE_FIELD_NAME (type, i)), stream);
}
else
{
print_longest (stream, 'd', 0, val);
}
break;
case TYPE_CODE_INT:
print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, val);
break;
case TYPE_CODE_CHAR:
LA_PRINT_CHAR ((unsigned char) val, stream);
break;
case TYPE_CODE_BOOL:
fprintf_filtered (stream, val ? "true" : "false");
break;
case TYPE_CODE_RANGE:
ada_print_scalar (TYPE_TARGET_TYPE (type), val, stream);
return;
case TYPE_CODE_UNDEF:
case TYPE_CODE_PTR:
case TYPE_CODE_ARRAY:
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
case TYPE_CODE_FUNC:
case TYPE_CODE_FLT:
case TYPE_CODE_VOID:
case TYPE_CODE_SET:
case TYPE_CODE_STRING:
case TYPE_CODE_ERROR:
case TYPE_CODE_MEMBER:
case TYPE_CODE_METHOD:
case TYPE_CODE_REF:
warning ("internal error: unhandled type in ada_print_scalar");
break;
default:
error ("Invalid type code in symbol table.");
}
gdb_flush (stream);
}
/* Print the character string STRING, printing at most LENGTH characters.
Printing stops early if the number hits print_max; repeat counts
are printed as appropriate. Print ellipses at the end if we
had to stop before printing LENGTH characters, or if
FORCE_ELLIPSES. TYPE_LEN is the length (1 or 2) of the character type.
*/
static void
printstr (struct ui_file *stream, char *string, unsigned int length,
int force_ellipses, int type_len)
{
unsigned int i;
unsigned int things_printed = 0;
int in_quotes = 0;
int need_comma = 0;
if (length == 0)
{
fputs_filtered ("\"\"", stream);
return;
}
for (i = 0; i < length && things_printed < print_max; i += 1)
{
/* Position of the character we are examining
to see whether it is repeated. */
unsigned int rep1;
/* Number of repetitions we have detected so far. */
unsigned int reps;
QUIT;
if (need_comma)
{
fputs_filtered (", ", stream);
need_comma = 0;
}
rep1 = i + 1;
reps = 1;
while (rep1 < length &&
char_at (string, rep1, type_len) == char_at (string, i,
type_len))
{
rep1 += 1;
reps += 1;
}
if (reps > repeat_count_threshold)
{
if (in_quotes)
{
if (inspect_it)
fputs_filtered ("\\\", ", stream);
else
fputs_filtered ("\", ", stream);
in_quotes = 0;
}
fputs_filtered ("'", stream);
ada_emit_char (char_at (string, i, type_len), stream, '\'',
type_len);
fputs_filtered ("'", stream);
fprintf_filtered (stream, " <repeats %u times>", reps);
i = rep1 - 1;
things_printed += repeat_count_threshold;
need_comma = 1;
}
else
{
if (!in_quotes)
{
if (inspect_it)
fputs_filtered ("\\\"", stream);
else
fputs_filtered ("\"", stream);
in_quotes = 1;
}
ada_emit_char (char_at (string, i, type_len), stream, '"',
type_len);
things_printed += 1;
}
}
/* Terminate the quotes if necessary. */
if (in_quotes)
{
if (inspect_it)
fputs_filtered ("\\\"", stream);
else
fputs_filtered ("\"", stream);
}
if (force_ellipses || i < length)
fputs_filtered ("...", stream);
}
void
ada_printstr (struct ui_file *stream, char *string, unsigned int length,
int force_ellipses, int width)
{
printstr (stream, string, length, force_ellipses, width);
}
/* Print data of type TYPE located at VALADDR (within GDB), which came from
the inferior at address ADDRESS, onto stdio stream STREAM according to
FORMAT (a letter as for the printf % codes or 0 for natural format).
The data at VALADDR is in target byte order.
If the data is printed as a string, returns the number of string characters
printed.
If DEREF_REF is nonzero, then dereference references, otherwise just print
them like pointers.
RECURSE indicates the amount of indentation to supply before
continuation lines; this amount is roughly twice the value of RECURSE.
When PRETTY is non-zero, prints record fields on separate lines.
(For some reason, the current version of gdb instead uses a global
variable---prettyprint_arrays--- to causes a similar effect on
arrays.) */
int
ada_val_print (struct type *type, char *valaddr0, int embedded_offset,
CORE_ADDR address, struct ui_file *stream, int format,
int deref_ref, int recurse, enum val_prettyprint pretty)
{
struct ada_val_print_args args;
args.type = type;
args.valaddr0 = valaddr0;
args.embedded_offset = embedded_offset;
args.address = address;
args.stream = stream;
args.format = format;
args.deref_ref = deref_ref;
args.recurse = recurse;
args.pretty = pretty;
return catch_errors (ada_val_print_stub, &args, NULL, RETURN_MASK_ALL);
}
/* Helper for ada_val_print; used as argument to catch_errors to
unmarshal the arguments to ada_val_print_1, which does the work. */
static int
ada_val_print_stub (void * args0)
{
struct ada_val_print_args *argsp = (struct ada_val_print_args *) args0;
return ada_val_print_1 (argsp->type, argsp->valaddr0,
argsp->embedded_offset, argsp->address,
argsp->stream, argsp->format, argsp->deref_ref,
argsp->recurse, argsp->pretty);
}
/* See the comment on ada_val_print. This function differs in that it
* does not catch evaluation errors (leaving that to ada_val_print). */
static int
ada_val_print_1 (struct type *type, char *valaddr0, int embedded_offset,
CORE_ADDR address, struct ui_file *stream, int format,
int deref_ref, int recurse, enum val_prettyprint pretty)
{
unsigned int len;
int i;
struct type *elttype;
unsigned int eltlen;
LONGEST val;
CORE_ADDR addr;
char *valaddr = valaddr0 + embedded_offset;
CHECK_TYPEDEF (type);
if (ada_is_array_descriptor (type) || ada_is_packed_array_type (type))
{
int retn;
struct value *mark = value_mark ();
struct value *val;
val = value_from_contents_and_address (type, valaddr, address);
val = ada_coerce_to_simple_array_ptr (val);
if (val == NULL)
{
fprintf_filtered (stream, "(null)");
retn = 0;
}
else
retn = ada_val_print_1 (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
VALUE_ADDRESS (val), stream, format,
deref_ref, recurse, pretty);
value_free_to_mark (mark);
return retn;
}
valaddr = ada_aligned_value_addr (type, valaddr);
embedded_offset -= valaddr - valaddr0 - embedded_offset;
type = printable_val_type (type, valaddr);
switch (TYPE_CODE (type))
{
default:
return c_val_print (type, valaddr0, embedded_offset, address, stream,
format, deref_ref, recurse, pretty);
case TYPE_CODE_INT:
case TYPE_CODE_RANGE:
if (ada_is_fixed_point_type (type))
{
LONGEST v = unpack_long (type, valaddr);
int len = TYPE_LENGTH (type);
fprintf_filtered (stream, len < 4 ? "%.11g" : "%.17g",
(double) ada_fixed_to_float (type, v));
return 0;
}
else if (ada_is_vax_floating_type (type))
{
struct value *val =
value_from_contents_and_address (type, valaddr, address);
struct value *func = ada_vax_float_print_function (type);
if (func != 0)
{
static struct type *parray_of_char = NULL;
struct value *printable_val;
if (parray_of_char == NULL)
parray_of_char =
make_pointer_type
(create_array_type
(NULL, builtin_type_char,
create_range_type (NULL, builtin_type_int, 0, 32)), NULL);
printable_val =
value_ind (value_cast (parray_of_char,
call_function_by_hand (func, 1,
&val)));
fprintf_filtered (stream, "%s", VALUE_CONTENTS (printable_val));
return 0;
}
/* No special printing function. Do as best we can. */
}
else if (TYPE_CODE (type) == TYPE_CODE_RANGE)
{
struct type *target_type = TYPE_TARGET_TYPE (type);
if (TYPE_LENGTH (type) != TYPE_LENGTH (target_type))
{
/* Obscure case of range type that has different length from
its base type. Perform a conversion, or we will get a
nonsense value. Actually, we could use the same
code regardless of lengths; I'm just avoiding a cast. */
struct value *v = value_cast (target_type,
value_from_contents_and_address
(type, valaddr, 0));
return ada_val_print_1 (target_type, VALUE_CONTENTS (v), 0, 0,
stream, format, 0, recurse + 1, pretty);
}
else
return ada_val_print_1 (TYPE_TARGET_TYPE (type),
valaddr0, embedded_offset,
address, stream, format, deref_ref,
recurse, pretty);
}
else
{
format = format ? format : output_format;
if (format)
{
print_scalar_formatted (valaddr, type, format, 0, stream);
}
else
{
val_print_type_code_int (type, valaddr, stream);
if (ada_is_character_type (type))
{
fputs_filtered (" ", stream);
ada_printchar ((unsigned char) unpack_long (type, valaddr),
stream);
}
}
return 0;
}
case TYPE_CODE_ENUM:
if (format)
{
print_scalar_formatted (valaddr, type, format, 0, stream);
break;
}
len = TYPE_NFIELDS (type);
val = unpack_long (type, valaddr);
for (i = 0; i < len; i++)
{
QUIT;
if (val == TYPE_FIELD_BITPOS (type, i))
{
break;
}
}
if (i < len)
{
const char *name = ada_enum_name (TYPE_FIELD_NAME (type, i));
if (name[0] == '\'')
fprintf_filtered (stream, "%ld %s", (long) val, name);
else
fputs_filtered (name, stream);
}
else
{
print_longest (stream, 'd', 0, val);
}
break;
case TYPE_CODE_UNION:
case TYPE_CODE_STRUCT:
if (ada_is_bogus_array_descriptor (type))
{
fprintf_filtered (stream, "(...?)");
return 0;
}
else
{
print_record (type, valaddr, stream, format, recurse, pretty);
return 0;
}
case TYPE_CODE_ARRAY:
if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
{
elttype = TYPE_TARGET_TYPE (type);
eltlen = TYPE_LENGTH (elttype);
len = TYPE_LENGTH (type) / eltlen;
/* For an array of chars, print with string syntax. */
if (ada_is_string_type (type) && (format == 0 || format == 's'))
{
if (prettyprint_arrays)
{
print_spaces_filtered (2 + 2 * recurse, stream);
}
/* If requested, look for the first null char and only print
elements up to it. */
if (stop_print_at_null)
{
int temp_len;
/* Look for a NULL char. */
for (temp_len = 0;
temp_len < len && temp_len < print_max
&& char_at (valaddr, temp_len, eltlen) != 0;
temp_len += 1);
len = temp_len;
}
printstr (stream, valaddr, len, 0, eltlen);
}
else
{
len = 0;
fprintf_filtered (stream, "(");
print_optional_low_bound (stream, type);
if (TYPE_FIELD_BITSIZE (type, 0) > 0)
val_print_packed_array_elements (type, valaddr, 0, stream,
format, recurse, pretty);
else
val_print_array_elements (type, valaddr, address, stream,
format, deref_ref, recurse,
pretty, 0);
fprintf_filtered (stream, ")");
}
gdb_flush (stream);
return len;
}
case TYPE_CODE_REF:
elttype = check_typedef (TYPE_TARGET_TYPE (type));
if (addressprint)
{
fprintf_filtered (stream, "@");
/* Extract an address, assume that the address is unsigned. */
print_address_numeric
(extract_unsigned_integer (valaddr,
TARGET_PTR_BIT / HOST_CHAR_BIT),
1, stream);
if (deref_ref)
fputs_filtered (": ", stream);
}
/* De-reference the reference */
if (deref_ref)
{
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
{
LONGEST deref_val_int = (LONGEST)
unpack_pointer (lookup_pointer_type (builtin_type_void),
valaddr);
if (deref_val_int != 0)
{
struct value *deref_val =
ada_value_ind (value_from_longest
(lookup_pointer_type (elttype),
deref_val_int));
val_print (VALUE_TYPE (deref_val),
VALUE_CONTENTS (deref_val), 0,
VALUE_ADDRESS (deref_val), stream, format,
deref_ref, recurse + 1, pretty);
}
else
fputs_filtered ("(null)", stream);
}
else
fputs_filtered ("???", stream);
}
break;
}
return 0;
}
static int
print_variant_part (struct type *type, int field_num, char *valaddr,
struct ui_file *stream, int format, int recurse,
enum val_prettyprint pretty, int comma_needed,
struct type *outer_type, char *outer_valaddr)
{
struct type *var_type = TYPE_FIELD_TYPE (type, field_num);
int which = ada_which_variant_applies (var_type, outer_type, outer_valaddr);
if (which < 0)
return 0;
else
return print_field_values
(TYPE_FIELD_TYPE (var_type, which),
valaddr + TYPE_FIELD_BITPOS (type, field_num) / HOST_CHAR_BIT
+ TYPE_FIELD_BITPOS (var_type, which) / HOST_CHAR_BIT,
stream, format, recurse, pretty,
comma_needed, outer_type, outer_valaddr);
}
int
ada_value_print (struct value *val0, struct ui_file *stream, int format,
enum val_prettyprint pretty)
{
char *valaddr = VALUE_CONTENTS (val0);
CORE_ADDR address = VALUE_ADDRESS (val0) + VALUE_OFFSET (val0);
struct type *type =
ada_to_fixed_type (VALUE_TYPE (val0), valaddr, address, NULL);
struct value *val =
value_from_contents_and_address (type, valaddr, address);
/* If it is a pointer, indicate what it points to. */
if (TYPE_CODE (type) == TYPE_CODE_PTR || TYPE_CODE (type) == TYPE_CODE_REF)
{
/* Hack: remove (char *) for char strings. Their
type is indicated by the quoted string anyway. */
if (TYPE_CODE (type) == TYPE_CODE_PTR &&
TYPE_LENGTH (TYPE_TARGET_TYPE (type)) == sizeof (char) &&
TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_INT &&
!TYPE_UNSIGNED (TYPE_TARGET_TYPE (type)))
{
/* Print nothing */
}
else
{
fprintf_filtered (stream, "(");
type_print (type, "", stream, -1);
fprintf_filtered (stream, ") ");
}
}
else if (ada_is_array_descriptor (type))
{
fprintf_filtered (stream, "(");
type_print (type, "", stream, -1);
fprintf_filtered (stream, ") ");
}
else if (ada_is_bogus_array_descriptor (type))
{
fprintf_filtered (stream, "(");
type_print (type, "", stream, -1);
fprintf_filtered (stream, ") (...?)");
return 0;
}
return (val_print (type, VALUE_CONTENTS (val), 0, address,
stream, format, 1, 0, pretty));
}
static void
print_record (struct type *type, char *valaddr, struct ui_file *stream,
int format, int recurse, enum val_prettyprint pretty)
{
CHECK_TYPEDEF (type);
fprintf_filtered (stream, "(");
if (print_field_values (type, valaddr, stream, format, recurse, pretty,
0, type, valaddr) != 0 && pretty)
{
fprintf_filtered (stream, "\n");
print_spaces_filtered (2 * recurse, stream);
}
fprintf_filtered (stream, ")");
}
/* Print out fields of value at VALADDR having structure type TYPE.
TYPE, VALADDR, STREAM, FORMAT, RECURSE, and PRETTY have the
same meanings as in ada_print_value and ada_val_print.
OUTER_TYPE and OUTER_VALADDR give type and address of enclosing record
(used to get discriminant values when printing variant parts).
COMMA_NEEDED is 1 if fields have been printed at the current recursion
level, so that a comma is needed before any field printed by this
call.
Returns 1 if COMMA_NEEDED or any fields were printed. */
static int
print_field_values (struct type *type, char *valaddr, struct ui_file *stream,
int format, int recurse, enum val_prettyprint pretty,
int comma_needed, struct type *outer_type,
char *outer_valaddr)
{
int i, len;
len = TYPE_NFIELDS (type);
for (i = 0; i < len; i += 1)
{
if (ada_is_ignored_field (type, i))
continue;
if (ada_is_wrapper_field (type, i))
{
comma_needed =
print_field_values (TYPE_FIELD_TYPE (type, i),
valaddr
+ TYPE_FIELD_BITPOS (type, i) / HOST_CHAR_BIT,
stream, format, recurse, pretty,
comma_needed, type, valaddr);
continue;
}
else if (ada_is_variant_part (type, i))
{
comma_needed =
print_variant_part (type, i, valaddr,
stream, format, recurse, pretty, comma_needed,
outer_type, outer_valaddr);
continue;
}
if (comma_needed)
fprintf_filtered (stream, ", ");
comma_needed = 1;
if (pretty)
{
fprintf_filtered (stream, "\n");
print_spaces_filtered (2 + 2 * recurse, stream);
}
else
{
wrap_here (n_spaces (2 + 2 * recurse));
}
if (inspect_it)
{
if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR)
fputs_filtered ("\"( ptr \"", stream);
else
fputs_filtered ("\"( nodef \"", stream);
fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
language_cplus, DMGL_NO_OPTS);
fputs_filtered ("\" \"", stream);
fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
language_cplus, DMGL_NO_OPTS);
fputs_filtered ("\") \"", stream);
}
else
{
annotate_field_begin (TYPE_FIELD_TYPE (type, i));
fprintf_filtered (stream, "%.*s",
ada_name_prefix_len (TYPE_FIELD_NAME (type, i)),
TYPE_FIELD_NAME (type, i));
annotate_field_name_end ();
fputs_filtered (" => ", stream);
annotate_field_value ();
}
if (TYPE_FIELD_PACKED (type, i))
{
struct value *v;
/* Bitfields require special handling, especially due to byte
order problems. */
if (TYPE_CPLUS_SPECIFIC (type) != NULL
&& TYPE_FIELD_IGNORE (type, i))
{
fputs_filtered ("<optimized out or zero length>", stream);
}
else
{
int bit_pos = TYPE_FIELD_BITPOS (type, i);
int bit_size = TYPE_FIELD_BITSIZE (type, i);
adjust_type_signedness (TYPE_FIELD_TYPE (type, i));
v = ada_value_primitive_packed_val (NULL, valaddr,
bit_pos / HOST_CHAR_BIT,
bit_pos % HOST_CHAR_BIT,
bit_size,
TYPE_FIELD_TYPE (type, i));
val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0, 0,
stream, format, 0, recurse + 1, pretty);
}
}
else
ada_val_print (TYPE_FIELD_TYPE (type, i),
valaddr + TYPE_FIELD_BITPOS (type, i) / HOST_CHAR_BIT,
0, 0, stream, format, 0, recurse + 1, pretty);
annotate_field_end ();
}
return comma_needed;
}

View file

@ -0,0 +1,386 @@
/* Target-dependent mdebug code for the ALPHA architecture.
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "symtab.h"
#include "gdbcore.h"
#include "block.h"
#include "gdb_assert.h"
#include "alpha-tdep.h"
/* FIXME: Some of this code should perhaps be merged with mips. */
/* *INDENT-OFF* */
/* Layout of a stack frame on the alpha:
| |
pdr members: | 7th ... nth arg, |
| `pushed' by caller. |
| |
----------------|-------------------------------|<-- old_sp == vfp
^ ^ ^ ^ | |
| | | | | |
| |localoff | Copies of 1st .. 6th |
| | | | | argument if necessary. |
| | | v | |
| | | --- |-------------------------------|<-- LOCALS_ADDRESS
| | | | |
| | | | Locals and temporaries. |
| | | | |
| | | |-------------------------------|
| | | | |
|-fregoffset | Saved float registers. |
| | | | F9 |
| | | | . |
| | | | . |
| | | | F2 |
| | v | |
| | -------|-------------------------------|
| | | |
| | | Saved registers. |
| | | S6 |
|-regoffset | . |
| | | . |
| | | S0 |
| | | pdr.pcreg |
| v | |
| ----------|-------------------------------|
| | |
frameoffset | Argument build area, gets |
| | 7th ... nth arg for any |
| | called procedure. |
v | |
-------------|-------------------------------|<-- sp
| |
*/
/* *INDENT-ON* */
#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr)
#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset)
#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg)
#define PROC_REG_MASK(proc) ((proc)->pdr.regmask)
#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask)
#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
#define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff)
/* Locate the mdebug PDR for the given PC. Return null if one can't
be found; you'll have to fall back to other methods in that case. */
static alpha_extra_func_info_t
find_proc_desc (CORE_ADDR pc)
{
struct block *b = block_for_pc (pc);
alpha_extra_func_info_t proc_desc = NULL;
struct symbol *sym = NULL;
if (b)
{
CORE_ADDR startaddr;
find_pc_partial_function (pc, NULL, &startaddr, NULL);
if (startaddr > BLOCK_START (b))
/* This is the "pathological" case referred to in a comment in
print_frame_info. It might be better to move this check into
symbol reading. */
sym = NULL;
else
sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0, NULL);
}
if (sym)
{
proc_desc = (alpha_extra_func_info_t) SYMBOL_VALUE (sym);
/* If we never found a PDR for this function in symbol reading,
then examine prologues to find the information. */
if (proc_desc->pdr.framereg == -1)
proc_desc = NULL;
}
return proc_desc;
}
/* This returns the PC of the first inst after the prologue. If we can't
find the prologue, then return 0. */
static CORE_ADDR
alpha_mdebug_after_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
{
if (proc_desc)
{
/* If function is frameless, then we need to do it the hard way. I
strongly suspect that frameless always means prologueless... */
if (PROC_FRAME_REG (proc_desc) == ALPHA_SP_REGNUM
&& PROC_FRAME_OFFSET (proc_desc) == 0)
return 0;
}
return alpha_after_prologue (pc);
}
/* Return non-zero if we *might* be in a function prologue. Return zero
if we are definitively *not* in a function prologue. */
static int
alpha_mdebug_in_prologue (CORE_ADDR pc, alpha_extra_func_info_t proc_desc)
{
CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc);
return (after_prologue_pc == 0 || pc < after_prologue_pc);
}
/* Frame unwinder that reads mdebug PDRs. */
struct alpha_mdebug_unwind_cache
{
alpha_extra_func_info_t proc_desc;
CORE_ADDR vfp;
CORE_ADDR *saved_regs;
};
/* Extract all of the information about the frame from PROC_DESC
and store the resulting register save locations in the structure. */
static struct alpha_mdebug_unwind_cache *
alpha_mdebug_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache)
{
struct alpha_mdebug_unwind_cache *info;
alpha_extra_func_info_t proc_desc;
ULONGEST vfp;
CORE_ADDR pc, reg_position;
unsigned long mask;
int ireg, returnreg;
if (*this_prologue_cache)
return *this_prologue_cache;
info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache);
*this_prologue_cache = info;
pc = frame_pc_unwind (next_frame);
/* ??? We don't seem to be able to cache the lookup of the PDR
from alpha_mdebug_frame_p. It'd be nice if we could change
the arguments to that function. Oh well. */
proc_desc = find_proc_desc (pc);
info->proc_desc = proc_desc;
gdb_assert (proc_desc != NULL);
info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
/* The VFP of the frame is at FRAME_REG+FRAME_OFFSET. */
frame_unwind_unsigned_register (next_frame, PROC_FRAME_REG (proc_desc), &vfp);
vfp += PROC_FRAME_OFFSET (info->proc_desc);
info->vfp = vfp;
/* Fill in the offsets for the registers which gen_mask says were saved. */
reg_position = vfp + PROC_REG_OFFSET (proc_desc);
mask = PROC_REG_MASK (proc_desc);
returnreg = PROC_PC_REG (proc_desc);
/* Note that RA is always saved first, regardless of its actual
register number. */
if (mask & (1 << returnreg))
{
/* Clear bit for RA so we don't save it again later. */
mask &= ~(1 << returnreg);
info->saved_regs[returnreg] = reg_position;
reg_position += 8;
}
for (ireg = 0; ireg <= 31; ++ireg)
if (mask & (1 << ireg))
{
info->saved_regs[ireg] = reg_position;
reg_position += 8;
}
reg_position = vfp + PROC_FREG_OFFSET (proc_desc);
mask = PROC_FREG_MASK (proc_desc);
for (ireg = 0; ireg <= 31; ++ireg)
if (mask & (1 << ireg))
{
info->saved_regs[ALPHA_FP0_REGNUM + ireg] = reg_position;
reg_position += 8;
}
return info;
}
/* Given a GDB frame, determine the address of the calling function's
frame. This will be used to create a new GDB frame struct. */
static void
alpha_mdebug_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct alpha_mdebug_unwind_cache *info
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
*this_id = frame_id_build (info->vfp, frame_func_unwind (next_frame));
}
/* Retrieve the value of REGNUM in FRAME. Don't give up! */
static void
alpha_mdebug_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
struct alpha_mdebug_unwind_cache *info
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
/* The PC of the previous frame is stored in the link register of
the current frame. Frob regnum so that we pull the value from
the correct place. */
if (regnum == ALPHA_PC_REGNUM)
regnum = PROC_PC_REG (info->proc_desc);
/* For all registers known to be saved in the current frame,
do the obvious and pull the value out. */
if (info->saved_regs[regnum])
{
*optimizedp = 0;
*lvalp = lval_memory;
*addrp = info->saved_regs[regnum];
*realnump = -1;
if (bufferp != NULL)
get_frame_memory (next_frame, *addrp, bufferp, ALPHA_REGISTER_SIZE);
return;
}
/* The stack pointer of the previous frame is computed by popping
the current stack frame. */
if (regnum == ALPHA_SP_REGNUM)
{
*optimizedp = 0;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (bufferp != NULL)
store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp);
return;
}
/* Otherwise assume the next frame has the same register value. */
frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
realnump, bufferp);
}
static const struct frame_unwind alpha_mdebug_frame_unwind = {
NORMAL_FRAME,
alpha_mdebug_frame_this_id,
alpha_mdebug_frame_prev_register
};
const struct frame_unwind *
alpha_mdebug_frame_sniffer (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
alpha_extra_func_info_t proc_desc;
/* If this PC does not map to a PDR, then clearly this isn't an
mdebug frame. */
proc_desc = find_proc_desc (pc);
if (proc_desc == NULL)
return NULL;
/* If we're in the prologue, the PDR for this frame is not yet valid.
Say no here and we'll fall back on the heuristic unwinder. */
if (alpha_mdebug_in_prologue (pc, proc_desc))
return NULL;
return &alpha_mdebug_frame_unwind;
}
static CORE_ADDR
alpha_mdebug_frame_base_address (struct frame_info *next_frame,
void **this_prologue_cache)
{
struct alpha_mdebug_unwind_cache *info
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
return info->vfp;
}
static CORE_ADDR
alpha_mdebug_frame_locals_address (struct frame_info *next_frame,
void **this_prologue_cache)
{
struct alpha_mdebug_unwind_cache *info
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
return info->vfp - PROC_LOCALOFF (info->proc_desc);
}
static CORE_ADDR
alpha_mdebug_frame_args_address (struct frame_info *next_frame,
void **this_prologue_cache)
{
struct alpha_mdebug_unwind_cache *info
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
return info->vfp - ALPHA_NUM_ARG_REGS * 8;
}
static const struct frame_base alpha_mdebug_frame_base = {
&alpha_mdebug_frame_unwind,
alpha_mdebug_frame_base_address,
alpha_mdebug_frame_locals_address,
alpha_mdebug_frame_args_address
};
static const struct frame_base *
alpha_mdebug_frame_base_sniffer (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
alpha_extra_func_info_t proc_desc;
/* If this PC does not map to a PDR, then clearly this isn't an
mdebug frame. */
proc_desc = find_proc_desc (pc);
if (proc_desc == NULL)
return NULL;
return &alpha_mdebug_frame_base;
}
void
alpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
frame_unwind_append_sniffer (gdbarch, alpha_mdebug_frame_sniffer);
frame_base_append_sniffer (gdbarch, alpha_mdebug_frame_base_sniffer);
}

View file

@ -0,0 +1,110 @@
/* Common target dependent code for GDB on Alpha systems.
Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002, 2003 Free
Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef ALPHA_TDEP_H
#define ALPHA_TDEP_H
/* Say how long (ordinary) registers are. This is a piece of bogosity
used in push_word and a few other places;
DEPRECATED_REGISTER_RAW_SIZE is the real way to know how big a
register is. */
#define ALPHA_REGISTER_SIZE 8
/* Number of machine registers. */
#define ALPHA_NUM_REGS 67
/* Total amount of space needed to store our copies of the machine's
register state. */
#define ALPHA_REGISTER_BYTES (ALPHA_NUM_REGS * 8)
/* Register numbers of various important registers. Note that most of
these values are "real" register numbers, and correspond to the
general registers of the machine. */
#define ALPHA_V0_REGNUM 0 /* Function integer return value */
#define ALPHA_T7_REGNUM 8 /* Return address register for OSF/1 __add* */
#define ALPHA_GCC_FP_REGNUM 15 /* Used by gcc as frame register */
#define ALPHA_A0_REGNUM 16 /* Loc of first arg during a subr call */
#define ALPHA_T9_REGNUM 23 /* Return address register for OSF/1 __div* */
#define ALPHA_RA_REGNUM 26 /* Contains return address value */
#define ALPHA_T12_REGNUM 27 /* Contains start addr of current proc */
#define ALPHA_GP_REGNUM 29 /* Contains the global pointer */
#define ALPHA_SP_REGNUM 30 /* Contains address of top of stack */
#define ALPHA_ZERO_REGNUM 31 /* Read-only register, always 0 */
#define ALPHA_FP0_REGNUM 32 /* Floating point register 0 */
#define ALPHA_FPA0_REGNUM 48 /* First float arg during a subr call */
#define ALPHA_FPCR_REGNUM 63 /* Floating point control register */
#define ALPHA_PC_REGNUM 64 /* Contains program counter */
#define ALPHA_UNIQUE_REGNUM 66 /* PAL_rduniq value */
/* The alpha has two different virtual pointers for arguments and locals.
The virtual argument pointer is pointing to the bottom of the argument
transfer area, which is located immediately below the virtual frame
pointer. Its size is fixed for the native compiler, it is either zero
(for the no arguments case) or large enough to hold all argument registers.
gcc uses a variable sized argument transfer area. As it has
to stay compatible with the native debugging tools it has to use the same
virtual argument pointer and adjust the argument offsets accordingly.
The virtual local pointer is localoff bytes below the virtual frame
pointer, the value of localoff is obtained from the PDR. */
#define ALPHA_NUM_ARG_REGS 6
/* Target-dependent structure in gdbarch. */
struct gdbarch_tdep
{
CORE_ADDR vm_min_address; /* Used by alpha_heuristic_proc_start. */
/* If PC is inside a dynamically-generated signal trampoline function
(i.e. one copied onto the user stack at run-time), return how many
bytes PC is beyond the start of that function. Otherwise, return -1. */
LONGEST (*dynamic_sigtramp_offset) (CORE_ADDR);
/* Translate a signal handler stack base address into the address of
the sigcontext structure for that signal handler. */
CORE_ADDR (*sigcontext_addr) (struct frame_info *);
/* Offset of registers in `struct sigcontext'. */
int sc_pc_offset;
int sc_regs_offset;
int sc_fpregs_offset;
int jb_pc; /* Offset to PC value in jump buffer.
If htis is negative, longjmp support
will be disabled. */
size_t jb_elt_size; /* And the size of each entry in the buf. */
};
extern unsigned int alpha_read_insn (CORE_ADDR pc);
extern void alpha_software_single_step (enum target_signal, int);
extern CORE_ADDR alpha_after_prologue (CORE_ADDR pc);
extern void alpha_mdebug_init_abi (struct gdbarch_info, struct gdbarch *);
extern void alpha_dwarf2_init_abi (struct gdbarch_info, struct gdbarch *);
extern void alpha_supply_int_regs (int, const void *, const void *,
const void *);
extern void alpha_fill_int_regs (int, void *, void *, void *);
extern void alpha_supply_fp_regs (int, const void *, const void *);
extern void alpha_fill_fp_regs (int, void *, void *);
#endif /* ALPHA_TDEP_H */

View file

@ -22,6 +22,9 @@
#include "inferior.h"
#include "regcache.h"
#include "alpha-tdep.h"
#include "alphabsd-tdep.h"
#include <sys/types.h>
#include <sys/ptrace.h>
#include <machine/reg.h>
@ -34,103 +37,45 @@
typedef struct reg gregset_t;
#endif
#ifndef HAVE_FPREGSET_T
typedef struct fpreg fpregset_t;
#endif
#ifndef HAVE_FPREGSET_T
typedef struct fpreg fpregset_t;
#endif
#include "gregset.h"
/* Number of general-purpose registers. */
#define NUM_GREGS 32
/* Number of floating point registers. */
#define NUM_FPREGS 31
/* Transfering the registers between GDB, inferiors and core files. */
/* Fill GDB's register array with the general-purpose register values
in *GREGSETP. */
/* Provide *regset() wrappers around the generic Alpha BSD register
supply/fill routines. */
void
supply_gregset (gregset_t *gregsetp)
{
int i;
for (i = 0; i < NUM_GREGS; i++)
{
if (CANNOT_FETCH_REGISTER (i))
supply_register (i, NULL);
else
supply_register (i, (char *) &gregsetp->r_regs[i]);
}
/* The PC travels in the R_ZERO slot. */
supply_register (PC_REGNUM, (char *) &gregsetp->r_regs[R_ZERO]);
alphabsd_supply_reg ((char *) gregsetp, -1);
}
/* Fill register REGNO (if it is a general-purpose register) in
*GREGSETPS with the value in GDB's register array. If REGNO is -1,
do this for all registers. */
void
fill_gregset (gregset_t *gregsetp, int regno)
{
int i;
for (i = 0; i < NUM_GREGS; i++)
if ((regno == -1 || regno == i) && ! CANNOT_STORE_REGISTER (i))
regcache_collect (i, (char *) &gregsetp->r_regs[i]);
/* The PC travels in the R_ZERO slot. */
if (regno == -1 || regno == PC_REGNUM)
regcache_collect (PC_REGNUM, (char *) &gregsetp->r_regs[R_ZERO]);
alphabsd_fill_reg ((char *) gregsetp, regno);
}
/* Fill GDB's register array with the floating-point register values
in *FPREGSETP. */
void
supply_fpregset (fpregset_t *fpregsetp)
{
int i;
for (i = FP0_REGNUM; i < FP0_REGNUM + NUM_FPREGS; i++)
{
if (CANNOT_FETCH_REGISTER (i))
supply_register (i, NULL);
else
supply_register (i, (char *) &fpregsetp->fpr_regs[i - FP0_REGNUM]);
}
supply_register (FPCR_REGNUM, (char *) &fpregsetp->fpr_cr);
alphabsd_supply_fpreg ((char *) fpregsetp, -1);
}
/* Fill register REGNO (if it is a floating-point register) in
*FPREGSETP with the value in GDB's register array. If REGNO is -1,
do this for all registers. */
void
fill_fpregset (fpregset_t *fpregsetp, int regno)
{
int i;
for (i = FP0_REGNUM; i < FP0_REGNUM + NUM_FPREGS; i++)
if ((regno == -1 || regno == i) && ! CANNOT_STORE_REGISTER (i))
regcache_collect (i, (char *) &fpregsetp->fpr_regs[i - FP0_REGNUM]);
if (regno == -1 || regno == FPCR_REGNUM)
regcache_collect (FPCR_REGNUM, (char *) &fpregsetp->fpr_cr);
alphabsd_fill_fpreg ((char *) fpregsetp, regno);
}
/* Determine if PT_GETREGS fetches this register. */
static int
getregs_supplies (int regno)
{
return ((regno >= V0_REGNUM && regno <= ZERO_REGNUM)
return ((regno >= ALPHA_V0_REGNUM && regno <= ALPHA_ZERO_REGNUM)
|| regno >= PC_REGNUM);
}
@ -141,33 +86,29 @@ getregs_supplies (int regno)
void
fetch_inferior_registers (int regno)
{
if (regno == -1 || getregs_supplies (regno))
{
gregset_t gregs;
struct reg gregs;
if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &gregs, 0) == -1)
perror_with_name ("Couldn't get registers");
supply_gregset (&gregs);
alphabsd_supply_reg ((char *) &gregs, regno);
if (regno != -1)
return;
}
if (regno == -1 || regno >= FP0_REGNUM)
{
fpregset_t fpregs;
struct fpreg fpregs;
if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
perror_with_name ("Couldn't get floating point status");
supply_fpregset (&fpregs);
alphabsd_supply_fpreg ((char *) &fpregs, regno);
}
/* Reset virtual frame pointer. */
supply_register (FP_REGNUM, NULL);
}
/* Store register REGNO back into the inferior. If REGNO is -1, do
@ -176,15 +117,14 @@ fetch_inferior_registers (int regno)
void
store_inferior_registers (int regno)
{
if (regno == -1 || getregs_supplies (regno))
{
gregset_t gregs;
struct reg gregs;
if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &gregs, 0) == -1)
perror_with_name ("Couldn't get registers");
fill_gregset (&gregs, regno);
alphabsd_fill_reg ((char *) &gregs, regno);
if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &gregs, 0) == -1)
@ -196,13 +136,13 @@ store_inferior_registers (int regno)
if (regno == -1 || regno >= FP0_REGNUM)
{
fpregset_t fpregs;
struct fpreg fpregs;
if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
perror_with_name ("Couldn't get floating point status");
fill_fpregset (&fpregs, regno);
alphabsd_fill_fpreg ((char *) &fpregs, regno);
if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &fpregs, 0) == -1)

View file

@ -0,0 +1,55 @@
/* Common target dependent code for GDB on Alpha systems running BSD.
Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "alpha-tdep.h"
#include "alphabsd-tdep.h"
/* Conviently, GDB uses the same register numbering as the
ptrace register structure used by BSD on Alpha. */
void
alphabsd_supply_reg (char *regs, int regno)
{
/* PC is at slot 32; UNIQUE not present. */
alpha_supply_int_regs (regno, regs, regs + 31*8, NULL);
}
void
alphabsd_fill_reg (char *regs, int regno)
{
/* PC is at slot 32; UNIQUE not present. */
alpha_fill_int_regs (regno, regs, regs + 31*8, NULL);
}
void
alphabsd_supply_fpreg (char *fpregs, int regno)
{
/* FPCR is at slot 33; slot 32 unused. */
alpha_supply_fp_regs (regno, fpregs, fpregs + 32*8);
}
void
alphabsd_fill_fpreg (char *fpregs, int regno)
{
/* FPCR is at slot 33; slot 32 unused. */
alpha_fill_fp_regs (regno, fpregs, fpregs + 32*8);
}

View file

@ -0,0 +1,33 @@
/* Common target dependent code for GDB on Alpha systems running BSD.
Copyright 2002 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef ALPHABSD_TDEP_H
#define ALPHABSD_TDEP_H
void alphabsd_supply_reg (char *, int);
void alphabsd_fill_reg (char *, int);
void alphabsd_supply_fpreg (char *, int);
void alphabsd_fill_fpreg (char *, int);
#define SIZEOF_STRUCT_REG (32 * 8)
#define SIZEOF_STRUCT_FPREG (33 * 8)
#endif /* ALPHABSD_TDEP_H */

View file

@ -1,5 +1,5 @@
/* Target-dependent code for FreeBSD/Alpha.
Copyright 2001 Free Software Foundation, Inc.
Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
@ -20,8 +20,11 @@
#include "defs.h"
#include "value.h"
#include "osabi.h"
int
#include "alpha-tdep.h"
static int
alphafbsd_use_struct_convention (int gcc_p, struct type *type)
{
enum type_code code;
@ -29,7 +32,7 @@ alphafbsd_use_struct_convention (int gcc_p, struct type *type)
/* All aggregate types that won't fit in a register must be returned
in memory. */
if (TYPE_LENGTH (type) > REGISTER_SIZE)
if (TYPE_LENGTH (type) > ALPHA_REGISTER_SIZE)
return 1;
/* The only aggregate types that can be returned in a register are
@ -51,3 +54,71 @@ alphafbsd_use_struct_convention (int gcc_p, struct type *type)
return 0;
}
/* Support for signal handlers. */
/* Return whether PC is in a BSD sigtramp routine. */
CORE_ADDR alphafbsd_sigtramp_start = 0x11ffff68;
CORE_ADDR alphafbsd_sigtramp_end = 0x11ffffe0;
static int
alphafbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
{
return (pc >= alphafbsd_sigtramp_start && pc < alphafbsd_sigtramp_end);
}
static LONGEST
alphafbsd_sigtramp_offset (CORE_ADDR pc)
{
return pc - alphafbsd_sigtramp_start;
}
/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
routine, return the address of the associated sigcontext structure. */
static CORE_ADDR
alphafbsd_sigcontext_addr (struct frame_info *next_frame)
{
return frame_unwind_register_unsigned (next_frame, ALPHA_SP_REGNUM) + 24;
}
/* FreeBSD 5.0-RELEASE or later. */
static void
alphafbsd_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* Hook into the DWARF CFI frame unwinder. */
alpha_dwarf2_init_abi (info, gdbarch);
/* Hook into the MDEBUG frame unwinder. */
alpha_mdebug_init_abi (info, gdbarch);
set_gdbarch_use_struct_convention (gdbarch, alphafbsd_use_struct_convention);
set_gdbarch_pc_in_sigtramp (gdbarch, alphafbsd_pc_in_sigtramp);
tdep->dynamic_sigtramp_offset = alphafbsd_sigtramp_offset;
tdep->sigcontext_addr = alphafbsd_sigcontext_addr;
tdep->sc_pc_offset = 288;
tdep->sc_regs_offset = 24;
tdep->sc_fpregs_offset = 320;
tdep->jb_pc = 2;
tdep->jb_elt_size = 8;
}
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_alphafbsd_tdep (void);
void
_initialize_alphafbsd_tdep (void)
{
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_FREEBSD_ELF,
alphafbsd_init_abi);
}

View file

@ -0,0 +1,234 @@
/* Target-dependent code for NetBSD/Alpha.
Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
Contributed by Wasabi Systems, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdbcore.h"
#include "frame.h"
#include "regcache.h"
#include "value.h"
#include "osabi.h"
#include "solib-svr4.h"
#include "alpha-tdep.h"
#include "alphabsd-tdep.h"
#include "nbsd-tdep.h"
static void
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
CORE_ADDR ignore)
{
char *regs, *fpregs;
int regno;
/* Table to map a gdb register number to a trapframe register index. */
static const int regmap[] =
{
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
30, 31, 32, 16,
17, 18, 19, 20,
21, 22, 23, 24,
25, 29, 26
};
#define SIZEOF_TRAPFRAME (33 * 8)
/* We get everything from one section. */
if (which != 0)
return;
regs = core_reg_sect;
fpregs = core_reg_sect + SIZEOF_TRAPFRAME;
if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG))
{
warning ("Wrong size register set in core file.");
return;
}
/* Integer registers. */
for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++)
supply_register (regno, regs + (regmap[regno] * 8));
supply_register (ALPHA_ZERO_REGNUM, NULL);
supply_register (PC_REGNUM, regs + (28 * 8));
/* Floating point registers. */
alphabsd_supply_fpreg (fpregs, -1);
}
static void
fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
CORE_ADDR ignore)
{
switch (which)
{
case 0: /* Integer registers. */
if (core_reg_size != SIZEOF_STRUCT_REG)
warning ("Wrong size register set in core file.");
else
alphabsd_supply_reg (core_reg_sect, -1);
break;
case 2: /* Floating point registers. */
if (core_reg_size != SIZEOF_STRUCT_FPREG)
warning ("Wrong size FP register set in core file.");
else
alphabsd_supply_fpreg (core_reg_sect, -1);
break;
default:
/* Don't know what kind of register request this is; just ignore it. */
break;
}
}
static struct core_fns alphanbsd_core_fns =
{
bfd_target_unknown_flavour, /* core_flavour */
default_check_format, /* check_format */
default_core_sniffer, /* core_sniffer */
fetch_core_registers, /* core_read_registers */
NULL /* next */
};
static struct core_fns alphanbsd_elfcore_fns =
{
bfd_target_elf_flavour, /* core_flavour */
default_check_format, /* check_format */
default_core_sniffer, /* core_sniffer */
fetch_elfcore_registers, /* core_read_registers */
NULL /* next */
};
/* Under NetBSD/alpha, signal handler invocations can be identified by the
designated code sequence that is used to return from a signal handler.
In particular, the return address of a signal handler points to the
following code sequence:
ldq a0, 0(sp)
lda sp, 16(sp)
lda v0, 295(zero) # __sigreturn14
call_pal callsys
Each instruction has a unique encoding, so we simply attempt to match
the instruction the PC is pointing to with any of the above instructions.
If there is a hit, we know the offset to the start of the designated
sequence and can then check whether we really are executing in the
signal trampoline. If not, -1 is returned, otherwise the offset from the
start of the return sequence is returned. */
static const unsigned char sigtramp_retcode[] =
{
0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */
0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */
0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */
0x83, 0x00, 0x00, 0x00, /* call_pal callsys */
};
#define RETCODE_NWORDS 4
#define RETCODE_SIZE (RETCODE_NWORDS * 4)
LONGEST
alphanbsd_sigtramp_offset (CORE_ADDR pc)
{
unsigned char ret[RETCODE_SIZE], w[4];
LONGEST off;
int i;
if (read_memory_nobpt (pc, (char *) w, 4) != 0)
return -1;
for (i = 0; i < RETCODE_NWORDS; i++)
{
if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
break;
}
if (i == RETCODE_NWORDS)
return (-1);
off = i * 4;
pc -= off;
if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
return -1;
if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
return off;
return -1;
}
static int
alphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
{
return (nbsd_pc_in_sigtramp (pc, func_name)
|| alphanbsd_sigtramp_offset (pc) >= 0);
}
static CORE_ADDR
alphanbsd_sigcontext_addr (struct frame_info *frame)
{
/* FIXME: This is not correct for all versions of NetBSD/alpha.
We will probably need to disassemble the trampoline to figure
out which trampoline frame type we have. */
return get_frame_base (frame);
}
static void
alphanbsd_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* Hook into the DWARF CFI frame unwinder. */
alpha_dwarf2_init_abi (info, gdbarch);
/* Hook into the MDEBUG frame unwinder. */
alpha_mdebug_init_abi (info, gdbarch);
set_gdbarch_pc_in_sigtramp (gdbarch, alphanbsd_pc_in_sigtramp);
/* NetBSD/alpha does not provide single step support via ptrace(2); we
must use software single-stepping. */
set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
set_solib_svr4_fetch_link_map_offsets (gdbarch,
nbsd_lp64_solib_svr4_fetch_link_map_offsets);
tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
tdep->jb_pc = 2;
tdep->jb_elt_size = 8;
}
void
_initialize_alphanbsd_tdep (void)
{
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
alphanbsd_init_abi);
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF,
alphanbsd_init_abi);
add_core_fns (&alphanbsd_core_fns);
add_core_fns (&alphanbsd_elfcore_fns);
}

163
contrib/gdb/gdb/amd64-nat.c Normal file
View file

@ -0,0 +1,163 @@
/* Native-dependent code for AMD64.
Copyright 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdbarch.h"
#include "regcache.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "i386-tdep.h"
#include "amd64-tdep.h"
/* The following bits of code help with implementing debugging 32-bit
code natively on AMD64. The idea is to define two mappings between
the register number as used by GDB and the register set used by the
host to represent the general-purpose registers; one for 32-bit
code and one for 64-bit code. The mappings are specified by the
follwing variables and consist of an array of offsets within the
register set indexed by register number, and the number of
registers supported by the mapping. We don't need mappings for the
floating-point and SSE registers, since the difference between
64-bit and 32-bit variants are negligable. The difference in the
number of SSE registers is already handled by the target code. */
/* General-purpose register mapping for native 32-bit code. */
int *amd64_native_gregset32_reg_offset;
int amd64_native_gregset32_num_regs = I386_NUM_GREGS;
/* General-purpose register mapping for native 64-bit code. */
int *amd64_native_gregset64_reg_offset;
int amd64_native_gregset64_num_regs = AMD64_NUM_GREGS;
/* Return the offset of REGNUM within the appropriate native
general-purpose register set. */
static int
amd64_native_gregset_reg_offset (int regnum)
{
int *reg_offset = amd64_native_gregset64_reg_offset;
int num_regs = amd64_native_gregset64_num_regs;
gdb_assert (regnum >= 0);
if (gdbarch_ptr_bit (current_gdbarch) == 32)
{
reg_offset = amd64_native_gregset32_reg_offset;
num_regs = amd64_native_gregset32_num_regs;
}
if (num_regs > NUM_REGS)
num_regs = NUM_REGS;
if (regnum < num_regs && regnum < NUM_REGS)
return reg_offset[regnum];
return -1;
}
/* Return whether the native general-purpose register set supplies
register REGNUM. */
int
amd64_native_gregset_supplies_p (int regnum)
{
return (amd64_native_gregset_reg_offset (regnum) != -1);
}
/* Supply register REGNUM, whose contents are store in BUF, to
REGCACHE. If REGNUM is -1, supply all appropriate registers. */
void
amd64_supply_native_gregset (struct regcache *regcache,
const void *gregs, int regnum)
{
const char *regs = gregs;
struct gdbarch *gdbarch = get_regcache_arch (regcache);
int num_regs = amd64_native_gregset64_num_regs;
int i;
if (gdbarch_ptr_bit (gdbarch) == 32)
num_regs = amd64_native_gregset32_num_regs;
if (num_regs > NUM_REGS)
num_regs = NUM_REGS;
for (i = 0; i < num_regs; i++)
{
if (regnum == -1 || regnum == i)
{
int offset = amd64_native_gregset_reg_offset (i);
if (offset != -1)
regcache_raw_supply (regcache, i, regs + offset);
}
}
}
/* Collect register REGNUM from REGCACHE and store its contents in
GREGS. If REGNUM is -1, collect and store all appropriate
registers. */
void
amd64_collect_native_gregset (const struct regcache *regcache,
void *gregs, int regnum)
{
char *regs = gregs;
struct gdbarch *gdbarch = get_regcache_arch (regcache);
int num_regs = amd64_native_gregset64_num_regs;
int i;
if (gdbarch_ptr_bit (gdbarch) == 32)
{
num_regs = amd64_native_gregset32_num_regs;
/* Make sure %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and
%eip get zero-extended to 64 bits. */
for (i = 0; i <= I386_EIP_REGNUM; i++)
{
if (regnum == -1 || regnum == i)
memset (regs + amd64_native_gregset_reg_offset (i), 0, 8);
}
/* Ditto for %cs, %ss, %ds, %es, %fs, and %gs. */
for (i = I386_CS_REGNUM; i <= I386_GS_REGNUM; i++)
{
if (regnum == -1 || regnum == i)
memset (regs + amd64_native_gregset_reg_offset (i), 0, 8);
}
}
if (num_regs > NUM_REGS)
num_regs = NUM_REGS;
for (i = 0; i < num_regs; i++)
{
if (regnum == -1 || regnum == i)
{
int offset = amd64_native_gregset_reg_offset (i);
if (offset != -1)
regcache_raw_collect (regcache, i, regs + offset);
}
}
}

View file

@ -0,0 +1,53 @@
/* Native-dependent code for AMD64.
Copyright 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef AMD64_NAT_H
#define AMD64_NAT_H 1
struct regcache;
/* General-purpose register set description for native 32-bit code. */
extern int *amd64_native_gregset32_reg_offset;
extern int amd64_native_gregset32_num_regs;
/* General-purpose register set description for native 64-bit code. */
extern int *amd64_native_gregset64_reg_offset;
extern int amd64_native_gregset64_num_regs;
/* Return whether the native general-purpose register set supplies
register REGNUM. */
extern int amd64_native_gregset_supplies_p (int regnum);
/* Supply register REGNUM, whose contents are store in BUF, to
REGCACHE. If REGNUM is -1, supply all appropriate registers. */
extern void amd64_supply_native_gregset (struct regcache *regcache,
const void *gregs, int regnum);
/* Collect register REGNUM from REGCACHE and store its contents in
GREGS. If REGNUM is -1, collect and store all appropriate
registers. */
extern void amd64_collect_native_gregset (const struct regcache *regcache,
void *gregs, int regnum);
#endif /* amd64-nat.h */

1199
contrib/gdb/gdb/amd64-tdep.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,93 @@
/* Target-dependent definitions for AMD64.
Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
Contributed by Jiri Smid, SuSE Labs.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef AMD64_TDEP_H
#define AMD64_TDEP_H
struct gdbarch;
struct frame_info;
struct regcache;
#include "i386-tdep.h"
/* Register numbers of various important registers. */
enum amd64_regnum
{
AMD64_RAX_REGNUM, /* %rax */
AMD64_RBX_REGNUM, /* %rbx */
AMD64_RCX_REGNUM, /* %rcx */
AMD64_RDX_REGNUM, /* %rdx */
AMD64_RSI_REGNUM, /* %rsi */
AMD64_RDI_REGNUM, /* %rdi */
AMD64_RBP_REGNUM, /* %rbp */
AMD64_RSP_REGNUM, /* %rsp */
AMD64_R8_REGNUM = 8, /* %r8 */
AMD64_R15_REGNUM = 15, /* %r15 */
AMD64_RIP_REGNUM, /* %rip */
AMD64_EFLAGS_REGNUM, /* %eflags */
AMD64_ST0_REGNUM = 24, /* %st0 */
AMD64_XMM0_REGNUM = 40, /* %xmm0 */
AMD64_XMM1_REGNUM /* %xmm1 */
};
/* Number of general purpose registers. */
#define AMD64_NUM_GREGS 24
extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
/* Fill register REGNUM in REGCACHE with the appropriate
floating-point or SSE register value from *FXSAVE. If REGNUM is
-1, do this for all registers. This function masks off any of the
reserved bits in *FXSAVE. */
extern void amd64_supply_fxsave (struct regcache *regcache, int regnum,
const void *fxsave);
/* Fill register REGNUM (if it is a floating-point or SSE register) in
*FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for
all registers. This function doesn't touch any of the reserved
bits in *FXSAVE. */
extern void amd64_collect_fxsave (const struct regcache *regcache, int regnum,
void *fxsave);
/* Fill register REGNUM (if it is a floating-point or SSE register) in
*FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
this for all registers. This function doesn't touch any of the
reserved bits in *FXSAVE. */
extern void amd64_fill_fxsave (char *fxsave, int regnum);
/* Variables exported from amd64nbsd-tdep.c. */
extern int amd64nbsd_r_reg_offset[];
/* Variables exported from amd64obsd-tdep.c. */
extern int amd64obsd_r_reg_offset[];
/* Variables exported from amd64fbsd-tdep.c. */
extern CORE_ADDR amd64fbsd_sigtramp_start_addr;
extern CORE_ADDR amd64fbsd_sigtramp_end_addr;
extern int amd64fbsd_sc_reg_offset[];
#endif /* amd64-tdep.h */

View file

@ -0,0 +1,107 @@
/* Native-dependent code for AMD64 BSD's.
Copyright 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "inferior.h"
#include "regcache.h"
/* We include <signal.h> to make sure `struct fxsave64' is defined on
NetBSD, since NetBSD's <machine/reg.h> needs it. */
#include "gdb_assert.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <machine/reg.h>
#include "amd64-tdep.h"
#include "amd64-nat.h"
/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
for all registers (including the floating-point registers). */
void
fetch_inferior_registers (int regnum)
{
if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
{
struct reg regs;
if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &regs, 0) == -1)
perror_with_name ("Couldn't get registers");
amd64_supply_native_gregset (current_regcache, &regs, -1);
if (regnum != -1)
return;
}
if (regnum == -1 || regnum >= AMD64_ST0_REGNUM)
{
struct fpreg fpregs;
if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
perror_with_name ("Couldn't get floating point status");
amd64_supply_fxsave (current_regcache, -1, &fpregs);
}
}
/* Store register REGNUM back into the inferior. If REGNUM is -1, do
this for all registers (including the floating-point registers). */
void
store_inferior_registers (int regnum)
{
if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
{
struct reg regs;
if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &regs, 0) == -1)
perror_with_name ("Couldn't get registers");
amd64_collect_native_gregset (current_regcache, &regs, regnum);
if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &regs, 0) == -1)
perror_with_name ("Couldn't write registers");
if (regnum != -1)
return;
}
if (regnum == -1 || regnum >= AMD64_ST0_REGNUM)
{
struct fpreg fpregs;
if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
perror_with_name ("Couldn't get floating point status");
amd64_fill_fxsave ((char *) &fpregs, regnum);
if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
perror_with_name ("Couldn't write floating point status");
}
}

View file

@ -0,0 +1,235 @@
/* Native-dependent code for FreeBSD/amd64.
Copyright 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "inferior.h"
#include "regcache.h"
#include "gdb_assert.h"
#include <signal.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/sysctl.h>
#include <machine/reg.h>
#ifdef HAVE_SYS_PROCFS_H
#include <sys/procfs.h>
#endif
#ifndef HAVE_GREGSET_T
typedef struct reg gregset_t;
#endif
#ifndef HAVE_FPREGSET_T
typedef struct fpreg fpregset_t;
#endif
#include "gregset.h"
#include "amd64-tdep.h"
#include "amd64-nat.h"
/* Offset to the gregset_t location where REG is stored. */
#define REG_OFFSET(reg) offsetof (gregset_t, reg)
/* At reg_offset[REGNUM] you'll find the offset to the gregset_t
location where the GDB register REGNUM is stored. Unsupported
registers are marked with `-1'. */
static int reg_offset[] =
{
REG_OFFSET (r_rax),
REG_OFFSET (r_rbx),
REG_OFFSET (r_rcx),
REG_OFFSET (r_rdx),
REG_OFFSET (r_rsi),
REG_OFFSET (r_rdi),
REG_OFFSET (r_rbp),
REG_OFFSET (r_rsp),
REG_OFFSET (r_r8),
REG_OFFSET (r_r9),
REG_OFFSET (r_r10),
REG_OFFSET (r_r11),
REG_OFFSET (r_r12),
REG_OFFSET (r_r13),
REG_OFFSET (r_r14),
REG_OFFSET (r_r15),
REG_OFFSET (r_rip),
REG_OFFSET (r_rflags),
REG_OFFSET (r_cs),
REG_OFFSET (r_ss),
-1,
-1,
-1,
-1
};
/* Mapping between the general-purpose registers in FreeBSD/amd64
`struct reg' format and GDB's register cache layout for
FreeBSD/i386.
Note that most FreeBSD/amd64 registers are 64-bit, while the
FreeBSD/i386 registers are all 32-bit, but since we're
little-endian we get away with that. */
/* From <machine/reg.h>. */
static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] =
{
14 * 8, 13 * 8, /* %eax, %ecx */
12 * 8, 11 * 8, /* %edx, %ebx */
20 * 8, 10 * 8, /* %esp, %ebp */
9 * 8, 8 * 8, /* %esi, %edi */
17 * 8, 19 * 8, /* %eip, %eflags */
18 * 8, 21 * 8, /* %cs, %ss */
-1, -1, -1, -1 /* %ds, %es, %fs, %gs */
};
/* Transfering the registers between GDB, inferiors and core files. */
/* Fill GDB's register array with the general-purpose register values
in *GREGSETP. */
void
supply_gregset (gregset_t *gregsetp)
{
amd64_supply_native_gregset (current_regcache, gregsetp, -1);
}
/* Fill register REGNUM (if it is a general-purpose register) in
*GREGSETPS with the value in GDB's register array. If REGNUM is -1,
do this for all registers. */
void
fill_gregset (gregset_t *gregsetp, int regnum)
{
amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
}
/* Fill GDB's register array with the floating-point register values
in *FPREGSETP. */
void
supply_fpregset (fpregset_t *fpregsetp)
{
amd64_supply_fxsave (current_regcache, -1, fpregsetp);
}
/* Fill register REGNUM (if it is a floating-point register) in
*FPREGSETP with the value in GDB's register array. If REGNUM is -1,
do this for all registers. */
void
fill_fpregset (fpregset_t *fpregsetp, int regnum)
{
amd64_fill_fxsave ((char *) fpregsetp, regnum);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64fbsd_nat (void);
void
_initialize_amd64fbsd_nat (void)
{
int offset;
amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset;
amd64_native_gregset64_reg_offset = reg_offset;
/* To support the recognition of signal handlers, i386bsd-tdep.c
hardcodes some constants. Inclusion of this file means that we
are compiling a native debugger, which means that we can use the
system header files and sysctl(3) to get at the relevant
information. */
#define SC_REG_OFFSET amd64fbsd_sc_reg_offset
/* We only check the program counter, stack pointer and frame
pointer since these members of `struct sigcontext' are essential
for providing backtraces. */
#define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
#define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
#define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
/* Override the default value for the offset of the program counter
in the sigcontext structure. */
offset = offsetof (struct sigcontext, sc_rip);
if (SC_RIP_OFFSET != offset)
{
warning ("\
offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
Please report this to <bug-gdb@gnu.org>.",
offset, SC_RIP_OFFSET);
}
SC_RIP_OFFSET = offset;
/* Likewise for the stack pointer. */
offset = offsetof (struct sigcontext, sc_rsp);
if (SC_RSP_OFFSET != offset)
{
warning ("\
offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
Please report this to <bug-gdb@gnu.org>.",
offset, SC_RSP_OFFSET);
}
SC_RSP_OFFSET = offset;
/* And the frame pointer. */
offset = offsetof (struct sigcontext, sc_rbp);
if (SC_RBP_OFFSET != offset)
{
warning ("\
offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
Please report this to <bug-gdb@gnu.org>.",
offset, SC_RBP_OFFSET);
}
SC_RBP_OFFSET = offset;
/* FreeBSD provides a kern.ps_strings sysctl that we can use to
locate the sigtramp. That way we can still recognize a sigtramp
if its location is changed in a new kernel. Of course this is
still based on the assumption that the sigtramp is placed
directly under the location where the program arguments and
environment can be found. */
{
int mib[2];
long ps_strings;
size_t len;
mib[0] = CTL_KERN;
mib[1] = KERN_PS_STRINGS;
len = sizeof (ps_strings);
if (sysctl (mib, 2, &ps_strings, &len, NULL, 0) == 0)
{
amd64fbsd_sigtramp_start_addr = ps_strings - 32;
amd64fbsd_sigtramp_end_addr = ps_strings;
}
}
}

View file

@ -0,0 +1,155 @@
/* Target-dependent code for FreeBSD/amd64.
Copyright 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "arch-utils.h"
#include "frame.h"
#include "gdbcore.h"
#include "regcache.h"
#include "osabi.h"
#include "gdb_string.h"
#include "amd64-tdep.h"
#include "solib-svr4.h"
/* Support for signal handlers. */
/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
routine, return the address of the associated sigcontext structure. */
static CORE_ADDR
amd64fbsd_sigcontext_addr (struct frame_info *next_frame)
{
CORE_ADDR sp;
/* The `struct sigcontext' (which really is an `ucontext_t' on
FreeBSD/amd64) lives at a fixed offset in the signal frame. See
<machine/sigframe.h>. */
sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
return sp + 16;
}
/* FreeBSD 5.1-RELEASE or later. */
/* Mapping between the general-purpose registers in `struct reg'
format and GDB's register cache layout.
Note that some registers are 32-bit, but since we're little-endian
we get away with that. */
/* From <machine/reg.h>. */
static int amd64fbsd_r_reg_offset[] =
{
14 * 8, /* %rax */
11 * 8, /* %rbx */
13 * 8, /* %rcx */
12 * 8, /* %rdx */
9 * 8, /* %rsi */
8 * 8, /* %rdi */
10 * 8, /* %rbp */
20 * 8, /* %rsp */
7 * 8, /* %r8 ... */
6 * 8,
5 * 8,
4 * 8,
3 * 8,
2 * 8,
1 * 8,
0 * 8, /* ... %r15 */
17 * 8, /* %rip */
19 * 8, /* %eflags */
18 * 8, /* %cs */
21 * 8, /* %ss */
-1, /* %ds */
-1, /* %es */
-1, /* %fs */
-1 /* %gs */
};
/* Location of the signal trampoline. */
CORE_ADDR amd64fbsd_sigtramp_start_addr = 0x7fffffffffc0;
CORE_ADDR amd64fbsd_sigtramp_end_addr = 0x7fffffffffe0;
/* From <machine/signal.h>. */
int amd64fbsd_sc_reg_offset[] =
{
24 + 6 * 8, /* %rax */
24 + 7 * 8, /* %rbx */
24 + 3 * 8, /* %rcx */
24 + 2 * 8, /* %rdx */
24 + 1 * 8, /* %rsi */
24 + 0 * 8, /* %rdi */
24 + 8 * 8, /* %rbp */
24 + 22 * 8, /* %rsp */
24 + 4 * 8, /* %r8 ... */
24 + 5 * 8,
24 + 9 * 8,
24 + 10 * 8,
24 + 11 * 8,
24 + 12 * 8,
24 + 13 * 8,
24 + 14 * 8, /* ... %r15 */
24 + 19 * 8, /* %rip */
24 + 21 * 8, /* %eflags */
24 + 20 * 8, /* %cs */
24 + 23 * 8, /* %ss */
-1, /* %ds */
-1, /* %es */
-1, /* %fs */
-1 /* %gs */
};
void
amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* Obviously FreeBSD is BSD-based. */
i386bsd_init_abi (info, gdbarch);
tdep->gregset_reg_offset = amd64fbsd_r_reg_offset;
tdep->gregset_num_regs = ARRAY_SIZE (amd64fbsd_r_reg_offset);
tdep->sizeof_gregset = 22 * 8;
amd64_init_abi (info, gdbarch);
tdep->sigtramp_start = amd64fbsd_sigtramp_start_addr;
tdep->sigtramp_end = amd64fbsd_sigtramp_end_addr;
tdep->sigcontext_addr = amd64fbsd_sigcontext_addr;
tdep->sc_reg_offset = amd64fbsd_sc_reg_offset;
tdep->sc_num_regs = ARRAY_SIZE (amd64fbsd_sc_reg_offset);
/* FreeBSD uses SVR4-style shared libraries. */
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_lp64_fetch_link_map_offsets);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64fbsd_tdep (void);
void
_initialize_amd64fbsd_tdep (void)
{
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
GDB_OSABI_FREEBSD_ELF, amd64fbsd_init_abi);
}

View file

@ -0,0 +1,68 @@
/* Native-dependent code for NetBSD/amd64.
Copyright 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdb_assert.h"
#include "amd64-tdep.h"
#include "amd64-nat.h"
/* Mapping between the general-purpose registers in NetBSD/amd64
`struct reg' format and GDB's register cache layout for
NetBSD/i386.
Note that most (if not all) NetBSD/amd64 registers are 64-bit,
while the NetBSD/i386 registers are all 32-bit, but since we're
little-endian we get away with that. */
/* From <machine/reg.h>. */
static int amd64nbsd32_r_reg_offset[] =
{
14 * 8, /* %eax */
3 * 8, /* %ecx */
2 * 8, /* %edx */
13 * 8, /* %ebx */
24 * 8, /* %esp */
12 * 8, /* %ebp */
1 * 8, /* %esi */
0 * 8, /* %edi */
21 * 8, /* %eip */
23 * 8, /* %eflags */
22 * 8, /* %cs */
25 * 8, /* %ss */
18 * 8, /* %ds */
17 * 8, /* %es */
16 * 8, /* %fs */
15 * 8 /* %gs */
};
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64nbsd_nat (void);
void
_initialize_amd64nbsd_nat (void)
{
amd64_native_gregset32_reg_offset = amd64nbsd32_r_reg_offset;
amd64_native_gregset32_num_regs = ARRAY_SIZE (amd64nbsd32_r_reg_offset);
amd64_native_gregset64_reg_offset = amd64nbsd_r_reg_offset;
}

View file

@ -0,0 +1,135 @@
/* Target-dependent code for NetBSD/amd64.
Copyright 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "arch-utils.h"
#include "frame.h"
#include "gdbcore.h"
#include "osabi.h"
#include "gdb_assert.h"
#include "amd64-tdep.h"
#include "nbsd-tdep.h"
#include "solib-svr4.h"
/* Support for signal handlers. */
/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
routine, return the address of the associated sigcontext structure. */
static CORE_ADDR
amd64nbsd_sigcontext_addr (struct frame_info *next_frame)
{
CORE_ADDR sp;
/* The stack pointer points at `struct sigcontext' upon entry of a
signal trampoline. */
sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
return sp;
}
/* NetBSD 2.0 or later. */
/* Mapping between the general-purpose registers in `struct reg'
format and GDB's register cache layout. */
/* From <machine/reg.h>. */
int amd64nbsd_r_reg_offset[] =
{
14 * 8, /* %rax */
13 * 8, /* %rbx */
3 * 8, /* %rcx */
2 * 8, /* %rdx */
1 * 8, /* %rsi */
0 * 8, /* %rdi */
12 * 8, /* %rbp */
24 * 8, /* %rsp */
4 * 8, /* %r8 .. */
5 * 8,
6 * 8,
7 * 8,
8 * 8,
9 * 8,
10 * 8,
11 * 8, /* ... %r15 */
21 * 8, /* %rip */
23 * 8, /* %eflags */
22 * 8, /* %cs */
25 * 8, /* %ss */
18 * 8, /* %ds */
17 * 8, /* %es */
16 * 8, /* %fs */
15 * 8 /* %gs */
};
static void
amd64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int *sc_reg_offset;
int i;
/* Initialize general-purpose register set details first. */
tdep->gregset_reg_offset = amd64nbsd_r_reg_offset;
tdep->gregset_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
tdep->sizeof_gregset = 26 * 8;
amd64_init_abi (info, gdbarch);
tdep->jb_pc_offset = 7 * 8;
/* NetBSD has its own convention for signal trampolines. */
set_gdbarch_pc_in_sigtramp (gdbarch, nbsd_pc_in_sigtramp);
tdep->sigcontext_addr = amd64nbsd_sigcontext_addr;
/* Initialize the array with register offsets in `struct
sigcontext'. This `struct sigcontext' has an sc_mcontext member
at offset 32, and in <machine/reg.h> we have an explicit comment
saying that `struct reg' is the same as mcontext.__gregs. */
tdep->sc_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
tdep->sc_reg_offset = XCALLOC (tdep->sc_num_regs, int);
for (i = 0; i < tdep->sc_num_regs; i++)
{
if (amd64nbsd_r_reg_offset[i] < 0)
tdep->sc_reg_offset[i] = -1;
else
tdep->sc_reg_offset[i] = 32 + amd64nbsd_r_reg_offset[i];
}
/* NetBSD uses SVR4-style shared libraries. */
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_lp64_fetch_link_map_offsets);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64nbsd_tdep (void);
void
_initialize_amd64nbsd_ndep (void)
{
/* The NetBSD/amd64 native dependent code makes this assumption. */
gdb_assert (ARRAY_SIZE (amd64nbsd_r_reg_offset) == AMD64_NUM_GREGS);
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
GDB_OSABI_NETBSD_ELF, amd64nbsd_init_abi);
}

View file

@ -0,0 +1,68 @@
/* Native-dependent code for OpenBSD/amd64.
Copyright 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdb_assert.h"
#include "amd64-tdep.h"
#include "amd64-nat.h"
/* Mapping between the general-purpose registers in OpenBSD/amd64
`struct reg' format and GDB's register cache layout for
OpenBSD/i386.
Note that most (if not all) OpenBSD/amd64 registers are 64-bit,
while the OpenBSD/i386 registers are all 32-bit, but since we're
little-endian we get away with that. */
/* From <machine/reg.h>. */
static int amd64obsd32_r_reg_offset[] =
{
14 * 8, /* %eax */
3 * 8, /* %ecx */
2 * 8, /* %edx */
13 * 8, /* %ebx */
15 * 8, /* %esp */
12 * 8, /* %ebp */
1 * 8, /* %esi */
0 * 8, /* %edi */
16 * 8, /* %eip */
17 * 8, /* %eflags */
18 * 8, /* %cs */
19 * 8, /* %ss */
20 * 8, /* %ds */
21 * 8, /* %es */
22 * 8, /* %fs */
23 * 8 /* %gs */
};
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64obsd_nat (void);
void
_initialize_amd64obsd_nat (void)
{
amd64_native_gregset32_reg_offset = amd64obsd32_r_reg_offset;
amd64_native_gregset32_num_regs = ARRAY_SIZE (amd64obsd32_r_reg_offset);
amd64_native_gregset64_reg_offset = amd64obsd_r_reg_offset;
}

View file

@ -0,0 +1,224 @@
/* Target-dependent code for OpenBSD/amd64.
Copyright 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "frame.h"
#include "gdbcore.h"
#include "osabi.h"
#include "regset.h"
#include "target.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "amd64-tdep.h"
#include "i387-tdep.h"
#include "solib-svr4.h"
/* Support for core dumps. */
static void
amd64obsd_supply_regset (const struct regset *regset,
struct regcache *regcache, int regnum,
const void *regs, size_t len)
{
const struct gdbarch_tdep *tdep = regset->descr;
gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE);
i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
amd64_supply_fxsave (regcache, regnum, (char *)regs + tdep->sizeof_gregset);
}
static const struct regset *
amd64obsd_regset_from_core_section (struct gdbarch *gdbarch,
const char *sect_name, size_t sect_size)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* OpenBSD core dumps don't use seperate register sets for the
general-purpose and floating-point registers. */
if (strcmp (sect_name, ".reg") == 0
&& sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE)
{
if (tdep->gregset == NULL)
{
tdep->gregset = XMALLOC (struct regset);
tdep->gregset->descr = tdep;
tdep->gregset->supply_regset = amd64obsd_supply_regset;
}
return tdep->gregset;
}
return NULL;
}
/* Support for signal handlers. */
static const int amd64obsd_page_size = 4096;
static int
amd64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
{
CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
const char sigreturn[] =
{
0x48, 0xc7, 0xc0,
0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */
0xcd, 0x80 /* int $0x80 */
};
char *buf;
if (name)
return 0;
/* If we can't read the instructions at START_PC, return zero. */
buf = alloca (sizeof sigreturn);
if (target_read_memory (start_pc + 0x7, buf, sizeof sigreturn))
return 0;
/* Check for sigreturn(2). */
if (memcmp (buf, sigreturn, sizeof sigreturn))
return 0;
return 1;
}
/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
routine, return the address of the associated sigcontext structure. */
static CORE_ADDR
amd64obsd_sigcontext_addr (struct frame_info *next_frame)
{
/* The %rsp register points at `struct sigcontext' upon entry of a
signal trampoline. */
return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
}
/* OpenBSD 3.5 or later. */
/* Mapping between the general-purpose registers in `struct reg'
format and GDB's register cache layout. */
/* From <machine/reg.h>. */
int amd64obsd_r_reg_offset[] =
{
14 * 8, /* %rax */
13 * 8, /* %rbx */
3 * 8, /* %rcx */
2 * 8, /* %rdx */
1 * 8, /* %rsi */
0 * 8, /* %rdi */
12 * 8, /* %rbp */
15 * 8, /* %rsp */
4 * 8, /* %r8 .. */
5 * 8,
6 * 8,
7 * 8,
8 * 8,
9 * 8,
10 * 8,
11 * 8, /* ... %r15 */
16 * 8, /* %rip */
17 * 8, /* %eflags */
18 * 8, /* %cs */
19 * 8, /* %ss */
20 * 8, /* %ds */
21 * 8, /* %es */
22 * 8, /* %fs */
23 * 8 /* %gs */
};
/* From <machine/signal.h>. */
static int amd64obsd_sc_reg_offset[] =
{
14 * 8, /* %rax */
13 * 8, /* %rbx */
3 * 8, /* %rcx */
2 * 8, /* %rdx */
1 * 8, /* %rsi */
0 * 8, /* %rdi */
12 * 8, /* %rbp */
24 * 8, /* %rsp */
4 * 8, /* %r8 ... */
5 * 8,
6 * 8,
7 * 8,
8 * 8,
9 * 8,
10 * 8,
11 * 8, /* ... %r15 */
21 * 8, /* %rip */
23 * 8, /* %eflags */
22 * 8, /* %cs */
25 * 8, /* %ss */
18 * 8, /* %ds */
17 * 8, /* %es */
16 * 8, /* %fs */
15 * 8 /* %gs */
};
static void
amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
amd64_init_abi (info, gdbarch);
/* Initialize general-purpose register set details. */
tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
tdep->sizeof_gregset = 24 * 8;
set_gdbarch_regset_from_core_section (gdbarch,
amd64obsd_regset_from_core_section);
tdep->jb_pc_offset = 7 * 8;
set_gdbarch_pc_in_sigtramp (gdbarch, amd64obsd_pc_in_sigtramp);
tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
/* OpenBSD uses SVR4-style shared libraries. */
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_lp64_fetch_link_map_offsets);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64obsd_tdep (void);
void
_initialize_amd64obsd_tdep (void)
{
/* The OpenBSD/amd64 native dependent code makes this assumption. */
gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
/* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
GDB_OSABI_NETBSD_AOUT, amd64obsd_init_abi);
}

View file

@ -155,28 +155,28 @@ annotate_signalled (void)
void
annotate_signal_name (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032signal-name\n");
}
void
annotate_signal_name_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032signal-name-end\n");
}
void
annotate_signal_string (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032signal-string\n");
}
void
annotate_signal_string_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032signal-string-end\n");
}
@ -193,35 +193,35 @@ annotate_signal (void)
void
annotate_breakpoints_headers (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032breakpoints-headers\n");
}
void
annotate_field (int num)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032field %d\n", num);
}
void
annotate_breakpoints_table (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032breakpoints-table\n");
}
void
annotate_record (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032record\n");
}
void
annotate_breakpoints_table_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032breakpoints-table-end\n");
}
@ -238,7 +238,7 @@ annotate_frames_invalid (void)
void
annotate_field_begin (struct type *type)
{
if (annotation_level > 1)
if (annotation_level == 2)
{
printf_filtered ("\n\032\032field-begin ");
print_value_flags (type);
@ -249,21 +249,21 @@ annotate_field_begin (struct type *type)
void
annotate_field_name_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032field-name-end\n");
}
void
annotate_field_value (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032field-value\n");
}
void
annotate_field_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032field-end\n");
}
@ -291,7 +291,7 @@ annotate_error_begin (void)
void
annotate_value_history_begin (int histindex, struct type *type)
{
if (annotation_level > 1)
if (annotation_level == 2)
{
printf_filtered ("\n\032\032value-history-begin %d ", histindex);
print_value_flags (type);
@ -302,7 +302,7 @@ annotate_value_history_begin (int histindex, struct type *type)
void
annotate_value_begin (struct type *type)
{
if (annotation_level > 1)
if (annotation_level == 2)
{
printf_filtered ("\n\032\032value-begin ");
print_value_flags (type);
@ -313,91 +313,91 @@ annotate_value_begin (struct type *type)
void
annotate_value_history_value (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032value-history-value\n");
}
void
annotate_value_history_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032value-history-end\n");
}
void
annotate_value_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032value-end\n");
}
void
annotate_display_begin (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032display-begin\n");
}
void
annotate_display_number_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032display-number-end\n");
}
void
annotate_display_format (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032display-format\n");
}
void
annotate_display_expression (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032display-expression\n");
}
void
annotate_display_expression_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032display-expression-end\n");
}
void
annotate_display_value (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032display-value\n");
}
void
annotate_display_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032display-end\n");
}
void
annotate_arg_begin (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032arg-begin\n");
}
void
annotate_arg_name_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032arg-name-end\n");
}
void
annotate_arg_value (struct type *type)
{
if (annotation_level > 1)
if (annotation_level == 2)
{
printf_filtered ("\n\032\032arg-value ");
print_value_flags (type);
@ -408,7 +408,7 @@ annotate_arg_value (struct type *type)
void
annotate_arg_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032arg-end\n");
}
@ -430,7 +430,7 @@ annotate_source (char *filename, int line, int character, int mid, CORE_ADDR pc)
void
annotate_frame_begin (int level, CORE_ADDR pc)
{
if (annotation_level > 1)
if (annotation_level == 2)
{
printf_filtered ("\n\032\032frame-begin %d 0x", level);
print_address_numeric (pc, 0, gdb_stdout);
@ -441,98 +441,98 @@ annotate_frame_begin (int level, CORE_ADDR pc)
void
annotate_function_call (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032function-call\n");
}
void
annotate_signal_handler_caller (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032signal-handler-caller\n");
}
void
annotate_frame_address (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-address\n");
}
void
annotate_frame_address_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-address-end\n");
}
void
annotate_frame_function_name (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-function-name\n");
}
void
annotate_frame_args (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-args\n");
}
void
annotate_frame_source_begin (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-source-begin\n");
}
void
annotate_frame_source_file (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-source-file\n");
}
void
annotate_frame_source_file_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-source-file-end\n");
}
void
annotate_frame_source_line (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-source-line\n");
}
void
annotate_frame_source_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-source-end\n");
}
void
annotate_frame_where (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-where\n");
}
void
annotate_frame_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032frame-end\n");
}
void
annotate_array_section_begin (int index, struct type *elttype)
{
if (annotation_level > 1)
if (annotation_level == 2)
{
printf_filtered ("\n\032\032array-section-begin %d ", index);
print_value_flags (elttype);
@ -543,28 +543,28 @@ annotate_array_section_begin (int index, struct type *elttype)
void
annotate_elt_rep (unsigned int repcount)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032elt-rep %u\n", repcount);
}
void
annotate_elt_rep_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032elt-rep-end\n");
}
void
annotate_elt (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032elt\n");
}
void
annotate_array_section_end (void)
{
if (annotation_level > 1)
if (annotation_level == 2)
printf_filtered ("\n\032\032array-section-end\n");
}

View file

@ -1,5 +1,7 @@
/* Dynamic architecture support for GDB, the GNU debugger.
Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
Inc.
This file is part of GDB.
@ -20,78 +22,66 @@
#include "defs.h"
#if GDB_MULTI_ARCH
#include "arch-utils.h"
#include "buildsym.h"
#include "gdbcmd.h"
#include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
#else
/* Just include everything in sight so that the every old definition
of macro is visible. */
#include "gdb_string.h"
#include "symtab.h"
#include "frame.h"
#include "inferior.h"
#include "breakpoint.h"
#include "gdb_wait.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "target.h"
#include "annotate.h"
#endif
#include "regcache.h"
#include "gdb_assert.h"
#include "sim-regno.h"
#include "osabi.h"
#include "version.h"
#include "floatformat.h"
/* Use the program counter to determine the contents and size
of a breakpoint instruction. If no target-dependent macro
BREAKPOINT_FROM_PC has been defined to implement this function,
assume that the breakpoint doesn't depend on the PC, and
use the values of the BIG_BREAKPOINT and LITTLE_BREAKPOINT macros.
Return a pointer to a string of bytes that encode a breakpoint
instruction, stores the length of the string to *lenptr,
and optionally adjust the pc to point to the correct memory location
for inserting the breakpoint. */
unsigned char *
legacy_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
/* Implementation of extract return value that grubs around in the
register cache. */
void
legacy_extract_return_value (struct type *type, struct regcache *regcache,
void *valbuf)
{
/* {BIG_,LITTLE_}BREAKPOINT 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. */
#ifdef BIG_BREAKPOINT
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
{
static unsigned char big_break_insn[] = BIG_BREAKPOINT;
*lenptr = sizeof (big_break_insn);
return big_break_insn;
}
#endif
#ifdef LITTLE_BREAKPOINT
if (TARGET_BYTE_ORDER != BFD_ENDIAN_BIG)
{
static unsigned char little_break_insn[] = LITTLE_BREAKPOINT;
*lenptr = sizeof (little_break_insn);
return little_break_insn;
}
#endif
#ifdef BREAKPOINT
{
static unsigned char break_insn[] = BREAKPOINT;
*lenptr = sizeof (break_insn);
return break_insn;
}
#endif
*lenptr = 0;
return NULL;
char *registers = deprecated_grub_regcache_for_registers (regcache);
bfd_byte *buf = valbuf;
DEPRECATED_EXTRACT_RETURN_VALUE (type, registers, buf); /* OK */
}
int
generic_frameless_function_invocation_not (struct frame_info *fi)
/* Implementation of store return value that grubs the register cache.
Takes a local copy of the buffer to avoid const problems. */
void
legacy_store_return_value (struct type *type, struct regcache *regcache,
const void *buf)
{
return 0;
bfd_byte *b = alloca (TYPE_LENGTH (type));
gdb_assert (regcache == current_regcache);
memcpy (b, buf, TYPE_LENGTH (type));
DEPRECATED_STORE_RETURN_VALUE (type, b);
}
int
always_use_struct_convention (int gcc_p, struct type *value_type)
{
return 1;
}
int
legacy_register_sim_regno (int regnum)
{
/* Only makes sense to supply raw registers. */
gdb_assert (regnum >= 0 && regnum < NUM_REGS);
/* NOTE: cagney/2002-05-13: The old code did it this way and it is
suspected that some GDB/SIM combinations may rely on this
behavour. The default should be one2one_register_sim_regno
(below). */
if (REGISTER_NAME (regnum) != NULL
&& REGISTER_NAME (regnum)[0] != '\0')
return regnum;
else
return LEGACY_SIM_REGNO_IGNORE;
}
int
@ -106,34 +96,30 @@ generic_skip_trampoline_code (CORE_ADDR pc)
return 0;
}
CORE_ADDR
generic_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
{
return 0;
}
int
generic_in_solib_call_trampoline (CORE_ADDR pc, char *name)
{
return 0;
}
int
generic_in_solib_return_trampoline (CORE_ADDR pc, char *name)
{
return 0;
}
int
generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
return 0;
}
char *
legacy_register_name (int i)
{
#ifdef REGISTER_NAMES
static char *names[] = REGISTER_NAMES;
if (i < 0 || i >= (sizeof (names) / sizeof (*names)))
return NULL;
else
return names[i];
#else
internal_error (__FILE__, __LINE__,
"legacy_register_name: called.");
return NULL;
#endif
}
#if defined (CALL_DUMMY)
LONGEST legacy_call_dummy_words[] = CALL_DUMMY;
#else
@ -142,31 +128,15 @@ LONGEST legacy_call_dummy_words[1];
int legacy_sizeof_call_dummy_words = sizeof (legacy_call_dummy_words);
void
generic_remote_translate_xfer_address (CORE_ADDR gdb_addr, int gdb_len,
generic_remote_translate_xfer_address (struct gdbarch *gdbarch,
struct regcache *regcache,
CORE_ADDR gdb_addr, int gdb_len,
CORE_ADDR * rem_addr, int *rem_len)
{
*rem_addr = gdb_addr;
*rem_len = gdb_len;
}
int
generic_prologue_frameless_p (CORE_ADDR ip)
{
#ifdef SKIP_PROLOGUE_FRAMELESS_P
return ip == SKIP_PROLOGUE_FRAMELESS_P (ip);
#else
return ip == SKIP_PROLOGUE (ip);
#endif
}
/* New/multi-arched targets should use the correct gdbarch field
instead of using this global pointer. */
int
legacy_print_insn (bfd_vma vma, disassemble_info *info)
{
return (*tm_print_insn) (vma, info);
}
/* Helper functions for INNER_THAN */
int
@ -187,11 +157,7 @@ core_addr_greaterthan (CORE_ADDR lhs, CORE_ADDR rhs)
const struct floatformat *
default_float_format (struct gdbarch *gdbarch)
{
#if GDB_MULTI_ARCH
int byte_order = gdbarch_byte_order (gdbarch);
#else
int byte_order = TARGET_BYTE_ORDER;
#endif
switch (byte_order)
{
case BFD_ENDIAN_BIG:
@ -208,11 +174,7 @@ default_float_format (struct gdbarch *gdbarch)
const struct floatformat *
default_double_format (struct gdbarch *gdbarch)
{
#if GDB_MULTI_ARCH
int byte_order = gdbarch_byte_order (gdbarch);
#else
int byte_order = TARGET_BYTE_ORDER;
#endif
switch (byte_order)
{
case BFD_ENDIAN_BIG:
@ -225,151 +187,36 @@ default_double_format (struct gdbarch *gdbarch)
}
}
void
default_print_float_info (void)
{
#ifdef FLOAT_INFO
#if GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL
#error "FLOAT_INFO defined in multi-arch"
#endif
FLOAT_INFO;
#else
printf_filtered ("No floating point info available for this processor.\n");
#endif
}
/* Misc helper functions for targets. */
int
frame_num_args_unknown (struct frame_info *fi)
{
return -1;
}
int
generic_register_convertible_not (int num)
{
return 0;
}
/* Under some ABI's that specify the `struct convention' for returning
structures by value, by the time we've returned from the function,
the return value is sitting there in the caller's buffer, but GDB
has no way to find the address of that buffer.
On such architectures, use this function as your
extract_struct_value_address method. When asked to a struct
returned by value in this fashion, GDB will print a nice error
message, instead of garbage. */
CORE_ADDR
generic_cannot_extract_struct_value_address (char *dummy)
{
return 0;
}
int
default_register_sim_regno (int num)
{
return num;
}
CORE_ADDR
core_addr_identity (CORE_ADDR addr)
{
return addr;
}
CORE_ADDR
convert_from_func_ptr_addr_identity (struct gdbarch *gdbarch, CORE_ADDR addr,
struct target_ops *targ)
{
return addr;
}
int
no_op_reg_to_regnum (int reg)
{
return reg;
}
/* For use by frame_args_address and frame_locals_address. */
CORE_ADDR
default_frame_address (struct frame_info *fi)
deprecated_init_frame_pc_default (int fromleaf, struct frame_info *prev)
{
return fi->frame;
}
/* Default prepare_to_procced(). */
int
default_prepare_to_proceed (int select_it)
{
return 0;
}
/* Generic prepare_to_proceed(). This one should be suitable for most
targets that support threads. */
int
generic_prepare_to_proceed (int select_it)
{
ptid_t wait_ptid;
struct target_waitstatus wait_status;
/* Get the last target status returned by target_wait(). */
get_last_target_status (&wait_ptid, &wait_status);
/* Make sure we were stopped either at a breakpoint, or because
of a Ctrl-C. */
if (wait_status.kind != TARGET_WAITKIND_STOPPED
|| (wait_status.value.sig != TARGET_SIGNAL_TRAP &&
wait_status.value.sig != TARGET_SIGNAL_INT))
{
return 0;
}
if (!ptid_equal (wait_ptid, minus_one_ptid)
&& !ptid_equal (inferior_ptid, wait_ptid))
{
/* Switched over from WAIT_PID. */
CORE_ADDR wait_pc = read_pc_pid (wait_ptid);
if (wait_pc != read_pc ())
{
if (select_it)
{
/* Switch back to WAIT_PID thread. */
inferior_ptid = wait_ptid;
/* FIXME: This stuff came from switch_to_thread() in
thread.c (which should probably be a public function). */
flush_cached_frames ();
registers_changed ();
stop_pc = wait_pc;
select_frame (get_current_frame (), 0);
}
/* We return 1 to indicate that there is a breakpoint here,
so we need to step over it before continuing to avoid
hitting it straight away. */
if (breakpoint_here_p (wait_pc))
{
return 1;
}
}
}
return 0;
}
void
init_frame_pc_noop (int fromleaf, struct frame_info *prev)
{
return;
}
void
init_frame_pc_default (int fromleaf, struct frame_info *prev)
{
if (fromleaf)
prev->pc = SAVED_PC_AFTER_CALL (prev->next);
else if (prev->next != NULL)
prev->pc = FRAME_SAVED_PC (prev->next);
if (fromleaf && DEPRECATED_SAVED_PC_AFTER_CALL_P ())
return DEPRECATED_SAVED_PC_AFTER_CALL (get_next_frame (prev));
else if (get_next_frame (prev) != NULL)
return DEPRECATED_FRAME_SAVED_PC (get_next_frame (prev));
else
prev->pc = read_pc ();
return read_pc ();
}
void
@ -391,34 +238,118 @@ cannot_register_not (int regnum)
}
/* Legacy version of target_virtual_frame_pointer(). Assumes that
there is an FP_REGNUM and that it is the same, cooked or raw. */
there is an DEPRECATED_FP_REGNUM and that it is the same, cooked or
raw. */
void
legacy_virtual_frame_pointer (CORE_ADDR pc,
int *frame_regnum,
LONGEST *frame_offset)
{
gdb_assert (FP_REGNUM >= 0);
*frame_regnum = FP_REGNUM;
/* FIXME: cagney/2002-09-13: This code is used when identifying the
frame pointer of the current PC. It is assuming that a single
register and an offset can determine this. I think it should
instead generate a byte code expression as that would work better
with things like Dwarf2's CFI. */
if (DEPRECATED_FP_REGNUM >= 0 && DEPRECATED_FP_REGNUM < NUM_REGS)
*frame_regnum = DEPRECATED_FP_REGNUM;
else if (SP_REGNUM >= 0 && SP_REGNUM < NUM_REGS)
*frame_regnum = SP_REGNUM;
else
/* Should this be an internal error? I guess so, it is reflecting
an architectural limitation in the current design. */
internal_error (__FILE__, __LINE__, "No virtual frame pointer available");
*frame_offset = 0;
}
/* Assume the world is flat. Every register is large enough to fit a
target integer. */
/* Assume the world is sane, every register's virtual and real size
is identical. */
int
generic_register_raw_size (int regnum)
generic_register_size (int regnum)
{
gdb_assert (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS);
return TARGET_INT_BIT / HOST_CHAR_BIT;
if (gdbarch_register_type_p (current_gdbarch))
return TYPE_LENGTH (gdbarch_register_type (current_gdbarch, regnum));
else
/* FIXME: cagney/2003-03-01: Once all architectures implement
gdbarch_register_type(), this entire function can go away. It
is made obsolete by register_size(). */
return TYPE_LENGTH (DEPRECATED_REGISTER_VIRTUAL_TYPE (regnum)); /* OK */
}
/* Assume the virtual size corresponds to the virtual type. */
/* Assume all registers are adjacent. */
int
generic_register_virtual_size (int regnum)
generic_register_byte (int regnum)
{
return TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (regnum));
int byte;
int i;
gdb_assert (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS);
byte = 0;
for (i = 0; i < regnum; i++)
{
byte += generic_register_size (i);
}
return byte;
}
int
legacy_pc_in_sigtramp (CORE_ADDR pc, char *name)
{
#if !defined (IN_SIGTRAMP)
if (SIGTRAMP_START_P ())
return (pc) >= SIGTRAMP_START (pc) && (pc) < SIGTRAMP_END (pc);
else
return name && strcmp ("_sigtramp", name) == 0;
#else
return IN_SIGTRAMP (pc, name);
#endif
}
int
legacy_convert_register_p (int regnum, struct type *type)
{
return (DEPRECATED_REGISTER_CONVERTIBLE_P ()
&& DEPRECATED_REGISTER_CONVERTIBLE (regnum));
}
void
legacy_register_to_value (struct frame_info *frame, int regnum,
struct type *type, void *to)
{
char from[MAX_REGISTER_SIZE];
get_frame_register (frame, regnum, from);
DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL (regnum, type, from, to);
}
void
legacy_value_to_register (struct frame_info *frame, int regnum,
struct type *type, const void *tmp)
{
char to[MAX_REGISTER_SIZE];
char *from = alloca (TYPE_LENGTH (type));
memcpy (from, from, TYPE_LENGTH (type));
DEPRECATED_REGISTER_CONVERT_TO_RAW (type, regnum, from, to);
put_frame_register (frame, regnum, to);
}
int
default_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
{
if (DEPRECATED_REG_STRUCT_HAS_ADDR_P ()
&& DEPRECATED_REG_STRUCT_HAS_ADDR (processing_gcc_compilation, type))
{
CHECK_TYPEDEF (type);
return (TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION
|| TYPE_CODE (type) == TYPE_CODE_SET
|| TYPE_CODE (type) == TYPE_CODE_BITSTRING);
}
return 0;
}
@ -431,8 +362,17 @@ generic_register_virtual_size (int regnum)
The choice of initial value is entirely arbitrary. During startup,
the function initialize_current_architecture() updates this value
based on default byte-order information extracted from BFD. */
int target_byte_order = BFD_ENDIAN_BIG;
int target_byte_order_auto = 1;
static int target_byte_order = BFD_ENDIAN_BIG;
static int target_byte_order_auto = 1;
enum bfd_endian
selected_byte_order (void)
{
if (target_byte_order_auto)
return BFD_ENDIAN_UNKNOWN;
else
return target_byte_order;
}
static const char endian_big[] = "big";
static const char endian_little[] = "little";
@ -451,7 +391,7 @@ static const char *set_endian_string;
static void
show_endian (char *args, int from_tty)
{
if (TARGET_BYTE_ORDER_AUTO)
if (target_byte_order_auto)
printf_unfiltered ("The target endianness is set automatically (currently %s endian)\n",
(TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "big" : "little"));
else
@ -468,39 +408,21 @@ set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c)
}
else if (set_endian_string == endian_little)
{
struct gdbarch_info info;
target_byte_order_auto = 0;
if (GDB_MULTI_ARCH)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
info.byte_order = BFD_ENDIAN_LITTLE;
if (! gdbarch_update_p (info))
{
printf_unfiltered ("Little endian target not supported by GDB\n");
}
}
else
{
target_byte_order = BFD_ENDIAN_LITTLE;
}
gdbarch_info_init (&info);
info.byte_order = BFD_ENDIAN_LITTLE;
if (! gdbarch_update_p (info))
printf_unfiltered ("Little endian target not supported by GDB\n");
}
else if (set_endian_string == endian_big)
{
struct gdbarch_info info;
target_byte_order_auto = 0;
if (GDB_MULTI_ARCH)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
info.byte_order = BFD_ENDIAN_BIG;
if (! gdbarch_update_p (info))
{
printf_unfiltered ("Big endian target not supported by GDB\n");
}
}
else
{
target_byte_order = BFD_ENDIAN_BIG;
}
gdbarch_info_init (&info);
info.byte_order = BFD_ENDIAN_BIG;
if (! gdbarch_update_p (info))
printf_unfiltered ("Big endian target not supported by GDB\n");
}
else
internal_error (__FILE__, __LINE__,
@ -508,126 +430,23 @@ set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c)
show_endian (NULL, from_tty);
}
/* Set the endianness from a BFD. */
static void
set_endian_from_file (bfd *abfd)
{
int want;
if (GDB_MULTI_ARCH)
internal_error (__FILE__, __LINE__,
"set_endian_from_file: not for multi-arch");
if (bfd_big_endian (abfd))
want = BFD_ENDIAN_BIG;
else
want = BFD_ENDIAN_LITTLE;
if (TARGET_BYTE_ORDER_AUTO)
target_byte_order = want;
else if (TARGET_BYTE_ORDER != want)
warning ("%s endian file does not match %s endian target.",
want == BFD_ENDIAN_BIG ? "big" : "little",
TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "big" : "little");
}
/* Functions to manipulate the architecture of the target */
enum set_arch { set_arch_auto, set_arch_manual };
int target_architecture_auto = 1;
static int target_architecture_auto = 1;
const char *set_architecture_string;
static const char *set_architecture_string;
/* Old way of changing the current architecture. */
extern const struct bfd_arch_info bfd_default_arch_struct;
const struct bfd_arch_info *target_architecture = &bfd_default_arch_struct;
int (*target_architecture_hook) (const struct bfd_arch_info *ap);
static int
arch_ok (const struct bfd_arch_info *arch)
const char *
selected_architecture_name (void)
{
if (GDB_MULTI_ARCH)
internal_error (__FILE__, __LINE__,
"arch_ok: not multi-arched");
/* Should be performing the more basic check that the binary is
compatible with GDB. */
/* Check with the target that the architecture is valid. */
return (target_architecture_hook == NULL
|| target_architecture_hook (arch));
}
static void
set_arch (const struct bfd_arch_info *arch,
enum set_arch type)
{
if (GDB_MULTI_ARCH)
internal_error (__FILE__, __LINE__,
"set_arch: not multi-arched");
switch (type)
{
case set_arch_auto:
if (!arch_ok (arch))
warning ("Target may not support %s architecture",
arch->printable_name);
target_architecture = arch;
break;
case set_arch_manual:
if (!arch_ok (arch))
{
printf_unfiltered ("Target does not support `%s' architecture.\n",
arch->printable_name);
}
else
{
target_architecture_auto = 0;
target_architecture = arch;
}
break;
}
if (gdbarch_debug)
gdbarch_dump (current_gdbarch, gdb_stdlog);
}
/* Set the architecture from arch/machine (deprecated) */
void
set_architecture_from_arch_mach (enum bfd_architecture arch,
unsigned long mach)
{
const struct bfd_arch_info *wanted = bfd_lookup_arch (arch, mach);
if (GDB_MULTI_ARCH)
internal_error (__FILE__, __LINE__,
"set_architecture_from_arch_mach: not multi-arched");
if (wanted != NULL)
set_arch (wanted, set_arch_manual);
else
internal_error (__FILE__, __LINE__,
"gdbarch: hardwired architecture/machine not recognized");
}
/* Set the architecture from a BFD (deprecated) */
static void
set_architecture_from_file (bfd *abfd)
{
const struct bfd_arch_info *wanted = bfd_get_arch_info (abfd);
if (GDB_MULTI_ARCH)
internal_error (__FILE__, __LINE__,
"set_architecture_from_file: not multi-arched");
if (target_architecture_auto)
{
set_arch (wanted, set_arch_auto);
}
else if (wanted != target_architecture)
{
warning ("%s architecture file may be incompatible with %s target.",
wanted->printable_name,
target_architecture->printable_name);
}
return NULL;
else
return set_architecture_string;
}
/* Called if the user enters ``show architecture'' without an
argument. */
@ -653,7 +472,7 @@ set_architecture (char *ignore_args, int from_tty, struct cmd_list_element *c)
{
target_architecture_auto = 1;
}
else if (GDB_MULTI_ARCH)
else
{
struct gdbarch_info info;
gdbarch_info_init (&info);
@ -667,37 +486,75 @@ set_architecture (char *ignore_args, int from_tty, struct cmd_list_element *c)
printf_unfiltered ("Architecture `%s' not recognized.\n",
set_architecture_string);
}
else
{
const struct bfd_arch_info *arch
= bfd_scan_arch (set_architecture_string);
if (arch == NULL)
internal_error (__FILE__, __LINE__,
"set_architecture: bfd_scan_arch failed");
set_arch (arch, set_arch_manual);
}
show_architecture (NULL, from_tty);
}
/* Try to select a global architecture that matches "info". Return
non-zero if the attempt succeds. */
int
gdbarch_update_p (struct gdbarch_info info)
{
struct gdbarch *new_gdbarch = gdbarch_find_by_info (info);
/* If there no architecture by that name, reject the request. */
if (new_gdbarch == NULL)
{
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
"Architecture not found\n");
return 0;
}
/* If it is the same old architecture, accept the request (but don't
swap anything). */
if (new_gdbarch == current_gdbarch)
{
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
"Architecture 0x%08lx (%s) unchanged\n",
(long) new_gdbarch,
gdbarch_bfd_arch_info (new_gdbarch)->printable_name);
return 1;
}
/* It's a new architecture, swap it in. */
if (gdbarch_debug)
fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
"New architecture 0x%08lx (%s) selected\n",
(long) new_gdbarch,
gdbarch_bfd_arch_info (new_gdbarch)->printable_name);
deprecated_current_gdbarch_select_hack (new_gdbarch);
return 1;
}
/* Return the architecture for ABFD. If no suitable architecture
could be find, return NULL. */
struct gdbarch *
gdbarch_from_bfd (bfd *abfd)
{
struct gdbarch *old_gdbarch = current_gdbarch;
struct gdbarch *new_gdbarch;
struct gdbarch_info info;
gdbarch_info_init (&info);
info.abfd = abfd;
return gdbarch_find_by_info (info);
}
/* Set the dynamic target-system-dependent parameters (architecture,
byte-order) using information found in the BFD */
void
set_gdbarch_from_file (bfd *abfd)
{
if (GDB_MULTI_ARCH)
{
struct gdbarch_info info;
gdbarch_info_init (&info);
info.abfd = abfd;
if (! gdbarch_update_p (info))
error ("Architecture of file not recognized.\n");
}
else
{
set_architecture_from_file (abfd);
set_endian_from_file (abfd);
}
struct gdbarch *gdbarch;
gdbarch = gdbarch_from_bfd (abfd);
if (gdbarch == NULL)
error ("Architecture of file not recognized.\n");
deprecated_current_gdbarch_select_hack (gdbarch);
}
/* Initialize the current architecture. Update the ``set
@ -784,22 +641,9 @@ initialize_current_architecture (void)
info.byte_order = BFD_ENDIAN_BIG;
}
if (GDB_MULTI_ARCH)
{
if (! gdbarch_update_p (info))
{
internal_error (__FILE__, __LINE__,
"initialize_current_architecture: Selection of initial architecture failed");
}
}
else
{
/* If the multi-arch logic comes up with a byte-order (from BFD)
use it for the non-multi-arch case. */
if (info.byte_order != BFD_ENDIAN_UNKNOWN)
target_byte_order = info.byte_order;
initialize_non_multiarch ();
}
if (! gdbarch_update_p (info))
internal_error (__FILE__, __LINE__,
"initialize_current_architecture: Selection of initial architecture failed");
/* Create the ``set architecture'' command appending ``auto'' to the
list of architectures. */
@ -830,7 +674,7 @@ initialize_current_architecture (void)
/* Initialize a gdbarch info to values that will be automatically
overridden. Note: Originally, this ``struct info'' was initialized
using memset(0). Unfortunatly, that ran into problems, namely
using memset(0). Unfortunately, that ran into problems, namely
BFD_ENDIAN_BIG is zero. An explicit initialization function that
can explicitly set each field to a well defined value is used. */
@ -839,11 +683,60 @@ gdbarch_info_init (struct gdbarch_info *info)
{
memset (info, 0, sizeof (struct gdbarch_info));
info->byte_order = BFD_ENDIAN_UNKNOWN;
info->osabi = GDB_OSABI_UNINITIALIZED;
}
/* Similar to init, but this time fill in the blanks. Information is
obtained from the specified architecture, global "set ..." options,
and explicitly initialized INFO fields. */
void
gdbarch_info_fill (struct gdbarch *gdbarch, struct gdbarch_info *info)
{
/* "(gdb) set architecture ...". */
if (info->bfd_arch_info == NULL
&& !target_architecture_auto
&& gdbarch != NULL)
info->bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
if (info->bfd_arch_info == NULL
&& info->abfd != NULL
&& bfd_get_arch (info->abfd) != bfd_arch_unknown
&& bfd_get_arch (info->abfd) != bfd_arch_obscure)
info->bfd_arch_info = bfd_get_arch_info (info->abfd);
if (info->bfd_arch_info == NULL
&& gdbarch != NULL)
info->bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
/* "(gdb) set byte-order ...". */
if (info->byte_order == BFD_ENDIAN_UNKNOWN
&& !target_byte_order_auto
&& gdbarch != NULL)
info->byte_order = gdbarch_byte_order (gdbarch);
/* From the INFO struct. */
if (info->byte_order == BFD_ENDIAN_UNKNOWN
&& info->abfd != NULL)
info->byte_order = (bfd_big_endian (info->abfd) ? BFD_ENDIAN_BIG
: bfd_little_endian (info->abfd) ? BFD_ENDIAN_LITTLE
: BFD_ENDIAN_UNKNOWN);
/* From the current target. */
if (info->byte_order == BFD_ENDIAN_UNKNOWN
&& gdbarch != NULL)
info->byte_order = gdbarch_byte_order (gdbarch);
/* "(gdb) set osabi ...". Handled by gdbarch_lookup_osabi. */
if (info->osabi == GDB_OSABI_UNINITIALIZED)
info->osabi = gdbarch_lookup_osabi (info->abfd);
if (info->osabi == GDB_OSABI_UNINITIALIZED
&& gdbarch != NULL)
info->osabi = gdbarch_osabi (gdbarch);
/* Must have at least filled in the architecture. */
gdb_assert (info->bfd_arch_info != NULL);
}
/* */
extern initialize_file_ftype _initialize_gdbarch_utils;
extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */
void
_initialize_gdbarch_utils (void)

View file

@ -1,5 +1,7 @@
/* Dynamic architecture support for GDB, the GNU debugger.
Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
Copyright 1998, 1999, 2000, 2002, 2003 Free Software Foundation,
Inc.
This file is part of GDB.
@ -21,37 +23,31 @@
#ifndef GDBARCH_UTILS_H
#define GDBARCH_UTILS_H
struct gdbarch;
struct frame_info;
struct minimal_symbol;
struct type;
struct gdbarch_info;
/* gdbarch trace variable */
extern int gdbarch_debug;
/* Fallback for register convertible. */
extern gdbarch_register_convertible_ftype generic_register_convertible_not;
/* Implementation of extract return value that grubs around in the
register cache. */
extern gdbarch_extract_return_value_ftype legacy_extract_return_value;
extern CORE_ADDR generic_cannot_extract_struct_value_address (char *dummy);
/* Implementation of store return value that grubs the register cache. */
extern gdbarch_store_return_value_ftype legacy_store_return_value;
/* Helper function for targets that don't know how my arguments are
being passed */
extern gdbarch_frame_num_args_ftype frame_num_args_unknown;
/* Implementation of breakpoint from PC using any of the deprecated
macros BREAKPOINT, LITTLE_BREAKPOINT, BIG_BREAPOINT. For legacy
targets that don't yet implement their own breakpoint_from_pc(). */
extern gdbarch_breakpoint_from_pc_ftype legacy_breakpoint_from_pc;
/* Frameless functions not identifable. */
extern gdbarch_frameless_function_invocation_ftype generic_frameless_function_invocation_not;
/* To return any structure or union type by value, store it at the
address passed as an invisible first argument to the function. */
extern gdbarch_use_struct_convention_ftype always_use_struct_convention;
/* Only structures, unions, and arrays are returned using the struct
convention. Note that arrays are never passed by value in the C
language family, so that case is irrelevant for C. */
extern gdbarch_return_value_on_stack_ftype generic_return_value_on_stack_not;
/* Map onto old REGISTER_NAMES. */
extern char *legacy_register_name (int i);
/* Accessor for old global function pointer for disassembly. */
extern int legacy_print_insn (bfd_vma vma, disassemble_info *info);
/* Backward compatible call_dummy_words. */
extern LONGEST legacy_call_dummy_words[];
extern int legacy_sizeof_call_dummy_words;
@ -59,11 +55,6 @@ extern int legacy_sizeof_call_dummy_words;
/* Typical remote_translate_xfer_address */
extern gdbarch_remote_translate_xfer_address_ftype generic_remote_translate_xfer_address;
/* Generic implementation of prologue_frameless_p. Just calls
SKIP_PROLOG and checks the return value to see if it actually
changed. */
extern gdbarch_prologue_frameless_p_ftype generic_prologue_frameless_p;
/* The only possible cases for inner_than. */
extern int core_addr_lessthan (CORE_ADDR lhs, CORE_ADDR rhs);
extern int core_addr_greaterthan (CORE_ADDR lhs, CORE_ADDR rhs);
@ -72,55 +63,18 @@ extern int core_addr_greaterthan (CORE_ADDR lhs, CORE_ADDR rhs);
extern const struct floatformat *default_float_format (struct gdbarch *gdbarch);
extern const struct floatformat *default_double_format (struct gdbarch *gdbarch);
/* Helper function for targets that don't know how my arguments are
being passed */
extern int frame_num_args_unknown (struct frame_info *fi);
/* The following DEPRECATED interfaces are for pre- multi-arch legacy
targets. */
/* DEPRECATED pre- multi-arch interface. Explicitly set the dynamic
target-system-dependent parameters based on bfd_architecture and
machine. This function is deprecated, use
set_gdbarch_from_arch_machine(). */
extern void set_architecture_from_arch_mach (enum bfd_architecture, unsigned long);
/* DEPRECATED pre- multi-arch interface. Notify the target dependent
backend of a change to the selected architecture. A zero return
status indicates that the target did not like the change. */
extern int (*target_architecture_hook) (const struct bfd_arch_info *);
/* Default raw->sim register re-numbering - does nothing. */
extern int default_register_sim_regno (int reg_nr);
/* Identity function on a CORE_ADDR. Just returns its parameter. */
/* Identity functions on a CORE_ADDR. Just return the "addr". */
extern CORE_ADDR core_addr_identity (CORE_ADDR addr);
extern gdbarch_convert_from_func_ptr_addr_ftype convert_from_func_ptr_addr_identity;
/* No-op conversion of reg to regnum. */
extern int no_op_reg_to_regnum (int reg);
/* Default frame_args_address and frame_locals_address. */
extern CORE_ADDR default_frame_address (struct frame_info *);
/* Default prepare_to_procced. */
extern int default_prepare_to_proceed (int select_it);
extern int generic_prepare_to_proceed (int select_it);
/* Versions of init_frame_pc(). Do nothing; do the default. */
void init_frame_pc_noop (int fromleaf, struct frame_info *prev);
void init_frame_pc_default (int fromleaf, struct frame_info *prev);
extern CORE_ADDR deprecated_init_frame_pc_default (int fromleaf, struct frame_info *prev);
/* Do nothing version of elf_make_msymbol_special. */
@ -136,28 +90,78 @@ void default_coff_make_msymbol_special (int val, struct minimal_symbol *msym);
int cannot_register_not (int regnum);
/* Legacy version of target_virtual_frame_pointer(). Assumes that
there is an FP_REGNUM and that it is the same, cooked or raw. */
there is an DEPRECATED_FP_REGNUM and that it is the same, cooked or
raw. */
extern gdbarch_virtual_frame_pointer_ftype legacy_virtual_frame_pointer;
extern CORE_ADDR generic_skip_trampoline_code (CORE_ADDR pc);
extern CORE_ADDR generic_skip_solib_resolver (struct gdbarch *gdbarch,
CORE_ADDR pc);
extern int generic_in_solib_call_trampoline (CORE_ADDR pc, char *name);
extern int generic_in_solib_return_trampoline (CORE_ADDR pc, char *name);
extern int generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc);
extern void default_print_float_info (void);
/* Assume that the world is sane, a registers raw and virtual size
both match its type. */
/* Assume all registers are the same size and a size identical to that
of the integer type. */
extern int generic_register_raw_size (int regnum);
extern int generic_register_size (int regnum);
/* Assume the virtual size of registers corresponds to the virtual type. */
/* Assume that the world is sane, the registers are all adjacent. */
extern int generic_register_byte (int regnum);
extern int generic_register_virtual_size (int regnum);
/* Prop up old targets that use various IN_SIGTRAMP() macros. */
extern int legacy_pc_in_sigtramp (CORE_ADDR pc, char *name);
/* The orginal register_convert*() functions were overloaded. They
were used to both: convert between virtual and raw register formats
(something that is discouraged); and to convert a register to the
type of a corresponding variable. These legacy functions preserve
that overloaded behavour in existing targets. */
extern int legacy_convert_register_p (int regnum, struct type *type);
extern void legacy_register_to_value (struct frame_info *frame, int regnum,
struct type *type, void *to);
extern void legacy_value_to_register (struct frame_info *frame, int regnum,
struct type *type, const void *from);
extern int default_stabs_argument_has_addr (struct gdbarch *gdbarch,
struct type *type);
/* For compatibility with older architectures, returns
(LEGACY_SIM_REGNO_IGNORE) when the register doesn't have a valid
name. */
extern int legacy_register_sim_regno (int regnum);
/* Return the selected byte order, or BFD_ENDIAN_UNKNOWN if no byte
order was explicitly selected. */
extern enum bfd_endian selected_byte_order (void);
/* Return the selected architecture's name, or NULL if no architecture
was explicitly selected. */
extern const char *selected_architecture_name (void);
/* Initialize a ``struct info''. Can't use memset(0) since some
default values are not zero. */
default values are not zero. "fill" takes all available
information and fills in any unspecified fields. */
extern void gdbarch_info_init (struct gdbarch_info *info);
extern void gdbarch_info_fill (struct gdbarch *gdbarch,
struct gdbarch_info *info);
/* Similar to init, but this time fill in the blanks. Information is
obtained from the specified architecture, global "set ..." options,
and explicitly initialized INFO fields. */
extern void gdbarch_info_fill (struct gdbarch *gdbarch,
struct gdbarch_info *info);
/* Return the architecture for ABFD. If no suitable architecture
could be find, return NULL. */
extern struct gdbarch *gdbarch_from_bfd (bfd *abfd);
#endif

View file

@ -1,5 +1,5 @@
/* Common target dependent code for GDB on ARM systems.
Copyright 2002 Free Software Foundation, Inc.
Copyright 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
@ -25,39 +25,33 @@
the user is concerned but do serve to get the desired values when
passed to read_register. */
#define ARM_A1_REGNUM 0 /* first integer-like argument */
#define ARM_A4_REGNUM 3 /* last integer-like argument */
#define ARM_AP_REGNUM 11
#define ARM_SP_REGNUM 13 /* Contains address of top of stack */
#define ARM_LR_REGNUM 14 /* address to return to from a function call */
#define ARM_PC_REGNUM 15 /* Contains program counter */
#define ARM_F0_REGNUM 16 /* first floating point register */
#define ARM_F3_REGNUM 19 /* last floating point argument register */
#define ARM_F7_REGNUM 23 /* last floating point register */
#define ARM_FPS_REGNUM 24 /* floating point status register */
#define ARM_PS_REGNUM 25 /* Contains processor status */
#define ARM_FP_REGNUM 11 /* Frame register in ARM code, if used. */
#define THUMB_FP_REGNUM 7 /* Frame register in Thumb code, if used. */
#define ARM_NUM_ARG_REGS 4
#define ARM_LAST_ARG_REGNUM ARM_A4_REGNUM
#define ARM_NUM_FP_ARG_REGS 4
#define ARM_LAST_FP_ARG_REGNUM ARM_F3_REGNUM
enum gdb_regnum {
ARM_A1_REGNUM = 0, /* first integer-like argument */
ARM_A4_REGNUM = 3, /* last integer-like argument */
ARM_AP_REGNUM = 11,
ARM_SP_REGNUM = 13, /* Contains address of top of stack */
ARM_LR_REGNUM = 14, /* address to return to from a function call */
ARM_PC_REGNUM = 15, /* Contains program counter */
ARM_F0_REGNUM = 16, /* first floating point register */
ARM_F3_REGNUM = 19, /* last floating point argument register */
ARM_F7_REGNUM = 23, /* last floating point register */
ARM_FPS_REGNUM = 24, /* floating point status register */
ARM_PS_REGNUM = 25, /* Contains processor status */
ARM_FP_REGNUM = 11, /* Frame register in ARM code, if used. */
THUMB_FP_REGNUM = 7, /* Frame register in Thumb code, if used. */
ARM_NUM_ARG_REGS = 4,
ARM_LAST_ARG_REGNUM = ARM_A4_REGNUM,
ARM_NUM_FP_ARG_REGS = 4,
ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM
};
/* Size of integer registers. */
#define INT_REGISTER_RAW_SIZE 4
#define INT_REGISTER_VIRTUAL_SIZE 4
#define INT_REGISTER_SIZE 4
/* Say how long FP registers are. Used for documentation purposes and
code readability in this header. IEEE extended doubles are 80
bits. DWORD aligned they use 96 bits. */
#define FP_REGISTER_RAW_SIZE 12
/* GCC doesn't support long doubles (extended IEEE values). The FP
register virtual size is therefore 64 bits. Used for documentation
purposes and code readability in this header. */
#define FP_REGISTER_VIRTUAL_SIZE 8
#define FP_REGISTER_SIZE 12
/* Status registers are the same size as general purpose registers.
Used for documentation purposes and code readability in this
@ -99,44 +93,32 @@
#define FLAG_C 0x20000000
#define FLAG_V 0x10000000
/* ABI variants that we know about. If you add to this enum, please
update the table of names in tm-arm.c. */
enum arm_abi
{
ARM_ABI_UNKNOWN = 0,
ARM_ABI_EABI_V1,
ARM_ABI_EABI_V2,
ARM_ABI_LINUX,
ARM_ABI_NETBSD_AOUT,
ARM_ABI_NETBSD_ELF,
ARM_ABI_APCS,
ARM_ABI_FREEBSD,
ARM_ABI_WINCE,
ARM_ABI_INVALID /* Keep this last. */
};
/* Type of floating-point code in use by inferior. There are really 3 models
that are traditionally supported (plus the endianness issue), but gcc can
only generate 2 of those. The third is APCS_FLOAT, where arguments to
functions are passed in floating-point registers.
In addition to the traditional models, VFP adds two more. */
In addition to the traditional models, VFP adds two more.
If you update this enum, don't forget to update fp_model_strings in
arm-tdep.c. */
enum arm_float_model
{
ARM_FLOAT_SOFT,
ARM_FLOAT_FPA,
ARM_FLOAT_SOFT_VFP,
ARM_FLOAT_VFP
ARM_FLOAT_AUTO, /* Automatic detection. Do not set in tdep. */
ARM_FLOAT_SOFT_FPA, /* Traditional soft-float (mixed-endian on LE ARM). */
ARM_FLOAT_FPA, /* FPA co-processor. GCC calling convention. */
ARM_FLOAT_SOFT_VFP, /* Soft-float with pure-endian doubles. */
ARM_FLOAT_VFP, /* Full VFP calling convention. */
ARM_FLOAT_LAST /* Keep at end. */
};
/* A method to the setting based on user's choice and ABI setting. */
enum arm_float_model arm_get_fp_model (struct gdbarch *);
/* Target-dependent structure in gdbarch. */
struct gdbarch_tdep
{
enum arm_abi arm_abi; /* OS/ABI of inferior. */
const char *abi_name; /* Name of the above. */
enum arm_float_model fp_model; /* Floating point calling conventions. */
CORE_ADDR lowest_pc; /* Lowest address at which instructions
@ -165,10 +147,3 @@ int arm_pc_is_thumb (CORE_ADDR);
CORE_ADDR thumb_get_next_pc (CORE_ADDR);
CORE_ADDR arm_get_next_pc (CORE_ADDR);
/* How a OS variant tells the ARM generic code that it can handle an ABI
type. */
void
arm_gdbarch_register_os_abi (enum arm_abi abi,
void (*init_abi)(struct gdbarch_info,
struct gdbarch *));

View file

@ -1,5 +1,5 @@
/* Target-specific functions for ARM running under NetBSD.
Copyright 2002 Free Software Foundation, Inc.
Copyright 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
@ -19,12 +19,15 @@
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "osabi.h"
#include "arm-tdep.h"
#include "nbsd-tdep.h"
#include "solib-svr4.h"
/* Description of the longjmp buffer. */
#define JB_PC 24
#define JB_ELEMENT_SIZE INT_REGISTER_RAW_SIZE
#define ARM_NBSD_JB_PC 24
#define ARM_NBSD_JB_ELEMENT_SIZE INT_REGISTER_SIZE
/* For compatibility with previous implemenations of GDB on arm/NetBSD,
override the default little-endian breakpoint. */
@ -49,8 +52,8 @@ arm_netbsd_init_abi_common (struct gdbarch_info info,
tdep->arm_breakpoint = arm_nbsd_arm_le_breakpoint;
tdep->arm_breakpoint_size = sizeof (arm_nbsd_arm_le_breakpoint);
tdep->jb_pc = JB_PC;
tdep->jb_elt_size = JB_ELEMENT_SIZE;
tdep->jb_pc = ARM_NBSD_JB_PC;
tdep->jb_elt_size = ARM_NBSD_JB_ELEMENT_SIZE;
}
static void
@ -63,7 +66,7 @@ arm_netbsd_aout_init_abi (struct gdbarch_info info,
set_gdbarch_in_solib_call_trampoline
(gdbarch, arm_netbsd_aout_in_solib_call_trampoline);
tdep->fp_model = ARM_FLOAT_SOFT;
tdep->fp_model = ARM_FLOAT_SOFT_FPA;
}
static void
@ -74,12 +77,29 @@ arm_netbsd_elf_init_abi (struct gdbarch_info info,
arm_netbsd_init_abi_common (info, gdbarch);
set_solib_svr4_fetch_link_map_offsets (gdbarch,
nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
tdep->fp_model = ARM_FLOAT_SOFT_VFP;
}
static enum gdb_osabi
arm_netbsd_aout_osabi_sniffer (bfd *abfd)
{
if (strcmp (bfd_get_target (abfd), "a.out-arm-netbsd") == 0)
return GDB_OSABI_NETBSD_AOUT;
return GDB_OSABI_UNKNOWN;
}
void
_initialize_arm_netbsd_tdep (void)
{
arm_gdbarch_register_os_abi (ARM_ABI_NETBSD_AOUT, arm_netbsd_aout_init_abi);
arm_gdbarch_register_os_abi (ARM_ABI_NETBSD_ELF, arm_netbsd_elf_init_abi);
gdbarch_register_osabi_sniffer (bfd_arch_arm, bfd_target_aout_flavour,
arm_netbsd_aout_osabi_sniffer);
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NETBSD_AOUT,
arm_netbsd_aout_init_abi);
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NETBSD_ELF,
arm_netbsd_elf_init_abi);
}

300
contrib/gdb/gdb/auxv.c Normal file
View file

@ -0,0 +1,300 @@
/* Auxiliary vector support for GDB, the GNU debugger.
Copyright 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "target.h"
#include "gdbtypes.h"
#include "command.h"
#include "inferior.h"
#include "valprint.h"
#include "gdb_assert.h"
#include "auxv.h"
#include "elf/common.h"
#include <unistd.h>
#include <fcntl.h>
/* This function is called like a to_xfer_partial hook,
but must be called with TARGET_OBJECT_AUXV.
It handles access via /proc/PID/auxv, which is the common method.
This function is appropriate for doing:
#define NATIVE_XFER_AUXV procfs_xfer_auxv
for a native target that uses inftarg.c's child_xfer_partial hook. */
LONGEST
procfs_xfer_auxv (struct target_ops *ops,
int /* enum target_object */ object,
const char *annex,
void *readbuf,
const void *writebuf,
ULONGEST offset,
LONGEST len)
{
char *pathname;
int fd;
LONGEST n;
gdb_assert (object == TARGET_OBJECT_AUXV);
gdb_assert (readbuf || writebuf);
pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid));
fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY);
xfree (pathname);
if (fd < 0)
return -1;
if (offset != (ULONGEST) 0
&& lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
n = -1;
else if (readbuf != NULL)
n = read (fd, readbuf, len);
else
n = write (fd, writebuf, len);
(void) close (fd);
return n;
}
/* Read all the auxv data into a contiguous xmalloc'd buffer,
stored in *DATA. Return the size in bytes of this data.
If zero, there is no data and *DATA is null.
if < 0, there was an error and *DATA is null. */
LONGEST
target_auxv_read (struct target_ops *ops, char **data)
{
size_t auxv_alloc = 512, auxv_pos = 0;
char *auxv = xmalloc (auxv_alloc);
int n;
while (1)
{
n = target_read_partial (ops, TARGET_OBJECT_AUXV,
NULL, &auxv[auxv_pos], 0,
auxv_alloc - auxv_pos);
if (n <= 0)
break;
auxv_pos += n;
if (auxv_pos < auxv_alloc) /* Read all there was. */
break;
gdb_assert (auxv_pos == auxv_alloc);
auxv_alloc *= 2;
auxv = xrealloc (auxv, auxv_alloc);
}
if (auxv_pos == 0)
{
xfree (auxv);
*data = NULL;
return n;
}
*data = auxv;
return auxv_pos;
}
/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
Return 0 if *READPTR is already at the end of the buffer.
Return -1 if there is insufficient buffer for a whole entry.
Return 1 if an entry was read into *TYPEP and *VALP. */
int
target_auxv_parse (struct target_ops *ops, char **readptr, char *endptr,
CORE_ADDR *typep, CORE_ADDR *valp)
{
const int sizeof_auxv_field = TYPE_LENGTH (builtin_type_void_data_ptr);
char *ptr = *readptr;
if (endptr == ptr)
return 0;
if (endptr - ptr < sizeof_auxv_field * 2)
return -1;
*typep = extract_unsigned_integer (ptr, sizeof_auxv_field);
ptr += sizeof_auxv_field;
*valp = extract_unsigned_integer (ptr, sizeof_auxv_field);
ptr += sizeof_auxv_field;
*readptr = ptr;
return 1;
}
/* Extract the auxiliary vector entry with a_type matching MATCH.
Return zero if no such entry was found, or -1 if there was
an error getting the information. On success, return 1 after
storing the entry's value field in *VALP. */
int
target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
{
CORE_ADDR type, val;
char *data;
int n = target_auxv_read (ops, &data);
char *ptr = data;
int ents = 0;
if (n <= 0)
return n;
while (1)
switch (target_auxv_parse (ops, &ptr, data + n, &type, &val))
{
case 1: /* Here's an entry, check it. */
if (type == match)
{
xfree (data);
*valp = val;
return 1;
}
break;
case 0: /* End of the vector. */
xfree (data);
return 0;
default: /* Bogosity. */
xfree (data);
return -1;
}
/*NOTREACHED*/
}
/* Print the contents of the target's AUXV on the specified file. */
int
fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
{
CORE_ADDR type, val;
char *data;
int len = target_auxv_read (ops, &data);
char *ptr = data;
int ents = 0;
if (len <= 0)
return len;
while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0)
{
extern int addressprint;
const char *name = "???";
const char *description = "";
enum { dec, hex, str } flavor = hex;
switch (type)
{
#define TAG(tag, text, kind) \
case tag: name = #tag; description = text; flavor = kind; break
TAG (AT_NULL, "End of vector", hex);
TAG (AT_IGNORE, "Entry should be ignored", hex);
TAG (AT_EXECFD, "File descriptor of program", dec);
TAG (AT_PHDR, "Program headers for program", hex);
TAG (AT_PHENT, "Size of program header entry", dec);
TAG (AT_PHNUM, "Number of program headers", dec);
TAG (AT_PAGESZ, "System page size", dec);
TAG (AT_BASE, "Base address of interpreter", hex);
TAG (AT_FLAGS, "Flags", hex);
TAG (AT_ENTRY, "Entry point of program", hex);
TAG (AT_NOTELF, "Program is not ELF", dec);
TAG (AT_UID, "Real user ID", dec);
TAG (AT_EUID, "Effective user ID", dec);
TAG (AT_GID, "Real group ID", dec);
TAG (AT_EGID, "Effective group ID", dec);
TAG (AT_CLKTCK, "Frequency of times()", dec);
TAG (AT_PLATFORM, "String identifying platform", str);
TAG (AT_HWCAP, "Machine-dependent CPU capability hints", hex);
TAG (AT_FPUCW, "Used FPU control word", dec);
TAG (AT_DCACHEBSIZE, "Data cache block size", dec);
TAG (AT_ICACHEBSIZE, "Instruction cache block size", dec);
TAG (AT_UCACHEBSIZE, "Unified cache block size", dec);
TAG (AT_IGNOREPPC, "Entry should be ignored", dec);
TAG (AT_SYSINFO, "Special system info/entry points", hex);
TAG (AT_SYSINFO_EHDR, "System-supplied DSO's ELF header", hex);
TAG (AT_SECURE, "Boolean, was exec setuid-like?", dec);
TAG (AT_SUN_UID, "Effective user ID", dec);
TAG (AT_SUN_RUID, "Real user ID", dec);
TAG (AT_SUN_GID, "Effective group ID", dec);
TAG (AT_SUN_RGID, "Real group ID", dec);
TAG (AT_SUN_LDELF, "Dynamic linker's ELF header", hex);
TAG (AT_SUN_LDSHDR, "Dynamic linker's section headers", hex);
TAG (AT_SUN_LDNAME, "String giving name of dynamic linker", str);
TAG (AT_SUN_LPAGESZ, "Large pagesize", dec);
TAG (AT_SUN_PLATFORM, "Platform name string", str);
TAG (AT_SUN_HWCAP, "Machine-dependent CPU capability hints", hex);
TAG (AT_SUN_IFLUSH, "Should flush icache?", dec);
TAG (AT_SUN_CPU, "CPU name string", str);
TAG (AT_SUN_EMUL_ENTRY, "COFF entry point address", hex);
TAG (AT_SUN_EMUL_EXECFD, "COFF executable file descriptor", dec);
TAG (AT_SUN_EXECNAME,
"Canonicalized file name given to execve", str);
TAG (AT_SUN_MMU, "String for name of MMU module", str);
TAG (AT_SUN_LDDATA, "Dynamic linker's data segment address", hex);
}
fprintf_filtered (file, "%-4s %-20s %-30s ",
paddr_d (type), name, description);
switch (flavor)
{
case dec:
fprintf_filtered (file, "%s\n", paddr_d (val));
break;
case hex:
fprintf_filtered (file, "0x%s\n", paddr_nz (val));
break;
case str:
if (addressprint)
fprintf_filtered (file, "0x%s", paddr_nz (val));
val_print_string (val, -1, 1, file);
fprintf_filtered (file, "\n");
break;
}
++ents;
}
xfree (data);
return ents;
}
static void
info_auxv_command (char *cmd, int from_tty)
{
if (! target_has_stack)
error ("The program has no auxiliary information now.");
else
{
int ents = fprint_target_auxv (gdb_stdout, &current_target);
if (ents < 0)
error ("No auxiliary vector found, or failed reading it.");
else if (ents == 0)
error ("Auxiliary vector is empty.");
}
}
extern initialize_file_ftype _initialize_auxv; /* -Wmissing-prototypes; */
void
_initialize_auxv (void)
{
add_info ("auxv", info_auxv_command,
"Display the inferior's auxiliary vector.\n\
This is information provided by the operating system at program startup.");
}

75
contrib/gdb/gdb/auxv.h Normal file
View file

@ -0,0 +1,75 @@
/* Auxiliary vector support for GDB, the GNU debugger.
Copyright 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef AUXV_H
#define AUXV_H
/* See "include/elf/common.h" for the definition of valid AT_* values. */
/* Avoid miscellaneous includes in this file, so that it can be
included by nm-*.h for the procfs_xfer_auxv decl if that is
used in NATIVE_XFER_AUXV. */
struct target_ops; /* Forward declaration. */
/* Read all the auxv data into a contiguous xmalloc'd buffer,
stored in *DATA. Return the size in bytes of this data.
If zero, there is no data and *DATA is null.
if < 0, there was an error and *DATA is null. */
extern LONGEST target_auxv_read (struct target_ops *ops, char **data);
/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
Return 0 if *READPTR is already at the end of the buffer.
Return -1 if there is insufficient buffer for a whole entry.
Return 1 if an entry was read into *TYPEP and *VALP. */
extern int target_auxv_parse (struct target_ops *ops,
char **readptr, char *endptr,
CORE_ADDR *typep, CORE_ADDR *valp);
/* Extract the auxiliary vector entry with a_type matching MATCH.
Return zero if no such entry was found, or -1 if there was
an error getting the information. On success, return 1 after
storing the entry's value field in *VALP. */
extern int target_auxv_search (struct target_ops *ops,
CORE_ADDR match, CORE_ADDR *valp);
/* Print the contents of the target's AUXV on the specified file. */
extern int fprint_target_auxv (struct ui_file *file, struct target_ops *ops);
/* This function is called like a to_xfer_partial hook,
but must be called with TARGET_OBJECT_AUXV.
It handles access via /proc/PID/auxv, which is the common method.
This function is appropriate for doing:
#define NATIVE_XFER_AUXV procfs_xfer_auxv
for a native target that uses inftarg.c's child_xfer_partial hook. */
extern LONGEST procfs_xfer_auxv (struct target_ops *ops,
int /* enum target_object */ object,
const char *annex,
void *readbuf,
const void *writebuf,
ULONGEST offset,
LONGEST len);
#endif

View file

@ -1,5 +1,7 @@
/* GDB-specific functions for operating on agent expressions
Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
/* GDB-specific functions for operating on agent expressions.
Copyright 1998, 1999, 2000, 2001, 2003 Free Software Foundation,
Inc.
This file is part of GDB.
@ -30,6 +32,9 @@
#include "target.h"
#include "ax.h"
#include "ax-gdb.h"
#include "gdb_string.h"
#include "block.h"
#include "regcache.h"
/* To make sense of this file, you should read doc/agentexpr.texi.
Then look at the types and enums in ax-gdb.h. For the code itself,
@ -129,7 +134,6 @@ static void gen_sizeof (union exp_element **pc,
static void gen_expr (union exp_element **pc,
struct agent_expr *ax, struct axs_value *value);
static void print_axs_value (struct ui_file *f, struct axs_value * value);
static void agent_command (char *exp, int from_tty);
@ -353,7 +357,7 @@ gen_sign_extend (struct agent_expr *ax, struct type *type)
{
/* Do we need to sign-extend this? */
if (!TYPE_UNSIGNED (type))
ax_ext (ax, type->length * TARGET_CHAR_BIT);
ax_ext (ax, TYPE_LENGTH (type) * TARGET_CHAR_BIT);
}
@ -363,7 +367,7 @@ gen_sign_extend (struct agent_expr *ax, struct type *type)
static void
gen_extend (struct agent_expr *ax, struct type *type)
{
int bits = type->length * TARGET_CHAR_BIT;
int bits = TYPE_LENGTH (type) * TARGET_CHAR_BIT;
/* I just had to. */
((TYPE_UNSIGNED (type) ? ax_zero_ext : ax_ext) (ax, bits));
}
@ -381,7 +385,7 @@ gen_fetch (struct agent_expr *ax, struct type *type)
ax_trace_quick (ax, TYPE_LENGTH (type));
}
switch (type->code)
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
case TYPE_CODE_ENUM:
@ -389,7 +393,7 @@ gen_fetch (struct agent_expr *ax, struct type *type)
case TYPE_CODE_CHAR:
/* It's a scalar value, so we know how to dereference it. How
many bytes long is it? */
switch (type->length)
switch (TYPE_LENGTH (type))
{
case 8 / TARGET_CHAR_BIT:
ax_simple (ax, aop_ref8);
@ -575,7 +579,7 @@ gen_var_ref (struct agent_expr *ax, struct axs_value *value, struct symbol *var)
case LOC_TYPEDEF:
error ("Cannot compute value of typedef `%s'.",
SYMBOL_SOURCE_NAME (var));
SYMBOL_PRINT_NAME (var));
break;
case LOC_BLOCK:
@ -604,9 +608,9 @@ gen_var_ref (struct agent_expr *ax, struct axs_value *value, struct symbol *var)
case LOC_UNRESOLVED:
{
struct minimal_symbol *msym
= lookup_minimal_symbol (SYMBOL_NAME (var), NULL, NULL);
= lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (var), NULL, NULL);
if (!msym)
error ("Couldn't resolve symbol `%s'.", SYMBOL_SOURCE_NAME (var));
error ("Couldn't resolve symbol `%s'.", SYMBOL_PRINT_NAME (var));
/* Push the address of the variable. */
ax_const_l (ax, SYMBOL_VALUE_ADDRESS (msym));
@ -614,14 +618,24 @@ gen_var_ref (struct agent_expr *ax, struct axs_value *value, struct symbol *var)
}
break;
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
/* FIXME: cagney/2004-01-26: It should be possible to
unconditionally call the SYMBOL_OPS method when available.
Unfortunately DWARF 2 stores the frame-base (instead of the
function) location in a function's symbol. Oops! For the
moment enable this when/where applicable. */
SYMBOL_OPS (var)->tracepoint_var_ref (var, ax, value);
break;
case LOC_OPTIMIZED_OUT:
error ("The variable `%s' has been optimized out.",
SYMBOL_SOURCE_NAME (var));
SYMBOL_PRINT_NAME (var));
break;
default:
error ("Cannot find value of botched symbol `%s'.",
SYMBOL_SOURCE_NAME (var));
SYMBOL_PRINT_NAME (var));
break;
}
}
@ -699,7 +713,7 @@ gen_usual_unary (struct agent_expr *ax, struct axs_value *value)
the stack. Should we tweak the type? */
/* Some types require special handling. */
switch (value->type->code)
switch (TYPE_CODE (value->type))
{
/* Functions get converted to a pointer to the function. */
case TYPE_CODE_FUNC:
@ -874,7 +888,7 @@ gen_cast (struct agent_expr *ax, struct axs_value *value, struct type *type)
/* Dereference typedefs. */
type = check_typedef (type);
switch (type->code)
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
/* It's implementation-defined, and I'll bet this is what GCC
@ -925,9 +939,9 @@ gen_scale (struct agent_expr *ax, enum agent_op op, struct type *type)
{
struct type *element = TYPE_TARGET_TYPE (type);
if (element->length != 1)
if (TYPE_LENGTH (element) != 1)
{
ax_const_l (ax, element->length);
ax_const_l (ax, TYPE_LENGTH (element));
ax_simple (ax, op);
}
}
@ -943,8 +957,8 @@ gen_add (struct agent_expr *ax, struct axs_value *value,
struct axs_value *value1, struct axs_value *value2, char *name)
{
/* Is it INT+PTR? */
if (value1->type->code == TYPE_CODE_INT
&& value2->type->code == TYPE_CODE_PTR)
if (TYPE_CODE (value1->type) == TYPE_CODE_INT
&& TYPE_CODE (value2->type) == TYPE_CODE_PTR)
{
/* Swap the values and proceed normally. */
ax_simple (ax, aop_swap);
@ -955,8 +969,8 @@ gen_add (struct agent_expr *ax, struct axs_value *value,
}
/* Is it PTR+INT? */
else if (value1->type->code == TYPE_CODE_PTR
&& value2->type->code == TYPE_CODE_INT)
else if (TYPE_CODE (value1->type) == TYPE_CODE_PTR
&& TYPE_CODE (value2->type) == TYPE_CODE_INT)
{
gen_scale (ax, aop_mul, value1->type);
ax_simple (ax, aop_add);
@ -966,8 +980,8 @@ gen_add (struct agent_expr *ax, struct axs_value *value,
/* Must be number + number; the usual binary conversions will have
brought them both to the same width. */
else if (value1->type->code == TYPE_CODE_INT
&& value2->type->code == TYPE_CODE_INT)
else if (TYPE_CODE (value1->type) == TYPE_CODE_INT
&& TYPE_CODE (value2->type) == TYPE_CODE_INT)
{
ax_simple (ax, aop_add);
gen_extend (ax, value1->type); /* Catch overflow. */
@ -989,10 +1003,10 @@ static void
gen_sub (struct agent_expr *ax, struct axs_value *value,
struct axs_value *value1, struct axs_value *value2)
{
if (value1->type->code == TYPE_CODE_PTR)
if (TYPE_CODE (value1->type) == TYPE_CODE_PTR)
{
/* Is it PTR - INT? */
if (value2->type->code == TYPE_CODE_INT)
if (TYPE_CODE (value2->type) == TYPE_CODE_INT)
{
gen_scale (ax, aop_mul, value1->type);
ax_simple (ax, aop_sub);
@ -1003,7 +1017,7 @@ gen_sub (struct agent_expr *ax, struct axs_value *value,
/* Is it PTR - PTR? Strictly speaking, the types ought to
match, but this is what the normal GDB expression evaluator
tests for. */
else if (value2->type->code == TYPE_CODE_PTR
else if (TYPE_CODE (value2->type) == TYPE_CODE_PTR
&& (TYPE_LENGTH (TYPE_TARGET_TYPE (value1->type))
== TYPE_LENGTH (TYPE_TARGET_TYPE (value2->type))))
{
@ -1018,8 +1032,8 @@ an integer nor a pointer of the same type.");
}
/* Must be number + number. */
else if (value1->type->code == TYPE_CODE_INT
&& value2->type->code == TYPE_CODE_INT)
else if (TYPE_CODE (value1->type) == TYPE_CODE_INT
&& TYPE_CODE (value2->type) == TYPE_CODE_INT)
{
ax_simple (ax, aop_sub);
gen_extend (ax, value1->type); /* Catch overflow. */
@ -1044,8 +1058,8 @@ gen_binop (struct agent_expr *ax, struct axs_value *value,
enum agent_op op_unsigned, int may_carry, char *name)
{
/* We only handle INT op INT. */
if ((value1->type->code != TYPE_CODE_INT)
|| (value2->type->code != TYPE_CODE_INT))
if ((TYPE_CODE (value1->type) != TYPE_CODE_INT)
|| (TYPE_CODE (value2->type) != TYPE_CODE_INT))
error ("Illegal combination of types in %s.", name);
ax_simple (ax,
@ -1092,7 +1106,7 @@ gen_deref (struct agent_expr *ax, struct axs_value *value)
{
/* The caller should check the type, because several operators use
this, and we don't know what error message to generate. */
if (value->type->code != TYPE_CODE_PTR)
if (TYPE_CODE (value->type) != TYPE_CODE_PTR)
internal_error (__FILE__, __LINE__,
"gen_deref: expected a pointer");
@ -1102,7 +1116,7 @@ gen_deref (struct agent_expr *ax, struct axs_value *value)
T" to "T", and mark the value as an lvalue in memory. Leave it
to the consumer to actually dereference it. */
value->type = check_typedef (TYPE_TARGET_TYPE (value->type));
value->kind = ((value->type->code == TYPE_CODE_FUNC)
value->kind = ((TYPE_CODE (value->type) == TYPE_CODE_FUNC)
? axs_rvalue : axs_lvalue_memory);
}
@ -1114,7 +1128,7 @@ gen_address_of (struct agent_expr *ax, struct axs_value *value)
/* Special case for taking the address of a function. The ANSI
standard describes this as a special case, too, so this
arrangement is not without motivation. */
if (value->type->code == TYPE_CODE_FUNC)
if (TYPE_CODE (value->type) == TYPE_CODE_FUNC)
/* The value's already an rvalue on the stack, so we just need to
change the type. */
value->type = lookup_pointer_type (value->type);
@ -1156,7 +1170,7 @@ find_field (struct type *type, char *name)
{
char *this_name = TYPE_FIELD_NAME (type, i);
if (this_name && STREQ (name, this_name))
if (this_name && strcmp (name, this_name) == 0)
return i;
if (this_name[0] == '\0')
@ -1346,7 +1360,7 @@ gen_struct_ref (struct agent_expr *ax, struct axs_value *value, char *field,
/* Follow pointers until we reach a non-pointer. These aren't the C
semantics, but they're what the normal GDB evaluator does, so we
should at least be consistent. */
while (value->type->code == TYPE_CODE_PTR)
while (TYPE_CODE (value->type) == TYPE_CODE_PTR)
{
gen_usual_unary (ax, value);
gen_deref (ax, value);
@ -1410,7 +1424,7 @@ gen_repeat (union exp_element **pc, struct agent_expr *ax,
if (!v)
error ("Right operand of `@' must be a constant, in agent expressions.");
if (v->type->code != TYPE_CODE_INT)
if (TYPE_CODE (v->type) != TYPE_CODE_INT)
error ("Right operand of `@' must be an integer.");
length = value_as_long (v);
if (length <= 0)
@ -1586,7 +1600,7 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
(*pc) += 3;
value->kind = axs_lvalue_register;
value->u.reg = reg;
value->type = REGISTER_VIRTUAL_TYPE (reg);
value->type = register_type (current_gdbarch, reg);
}
break;
@ -1787,33 +1801,6 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr)
discard_cleanups (old_chain);
return ax;
}
/* The "agent" command, for testing: compile and disassemble an expression. */
static void
print_axs_value (struct ui_file *f, struct axs_value *value)
{
switch (value->kind)
{
case axs_rvalue:
fputs_filtered ("rvalue", f);
break;
case axs_lvalue_memory:
fputs_filtered ("memory lvalue", f);
break;
case axs_lvalue_register:
fprintf_filtered (f, "register %d lvalue", value->u.reg);
break;
}
fputs_filtered (" : ", f);
type_print (value->type, "", f, -1);
}
static void
agent_command (char *exp, int from_tty)
@ -1835,7 +1822,7 @@ agent_command (char *exp, int from_tty)
expr = parse_expression (exp);
old_chain = make_cleanup (free_current_contents, &expr);
agent = gen_trace_for_expr (fi->pc, expr);
agent = gen_trace_for_expr (get_frame_pc (fi), expr);
make_cleanup_free_agent_expr (agent);
ax_print (gdb_stdout, agent);

View file

@ -20,7 +20,8 @@
#ifndef AX_GDB_H
#define AX_GDB_H
struct expression;
/* Types and enums */

View file

@ -27,6 +27,7 @@
#include "ax.h"
#include "value.h"
#include "gdb_string.h"
static void grow_expr (struct agent_expr *x, int n);

View file

@ -2,7 +2,7 @@
Written by Fred Fish <fnf@cygnus.com>
Rewritten by Jim Blandy <jimb@cygnus.com>
Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
@ -22,13 +22,76 @@
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "obstack.h"
#include "gdb_obstack.h"
#include "bcache.h"
#include "gdb_string.h" /* For memcpy declaration */
#include "gdb_assert.h"
#include <stddef.h>
#include <stdlib.h>
/* The type used to hold a single bcache string. The user data is
stored in d.data. Since it can be any type, it needs to have the
same alignment as the most strict alignment of any type on the host
machine. I don't know of any really correct way to do this in
stock ANSI C, so just do it the same way obstack.h does. */
struct bstring
{
/* Hash chain. */
struct bstring *next;
/* Assume the data length is no more than 64k. */
unsigned short length;
/* The half hash hack. This contains the upper 16 bits of the hash
value and is used as a pre-check when comparing two strings and
avoids the need to do length or memcmp calls. It proves to be
roughly 100% effective. */
unsigned short half_hash;
union
{
char data[1];
double dummy;
}
d;
};
/* The structure for a bcache itself. The bcache is initialized, in
bcache_xmalloc(), by filling it with zeros and then setting the
corresponding obstack's malloc() and free() methods. */
struct bcache
{
/* All the bstrings are allocated here. */
struct obstack cache;
/* How many hash buckets we're using. */
unsigned int num_buckets;
/* Hash buckets. This table is allocated using malloc, so when we
grow the table we can return the old table to the system. */
struct bstring **bucket;
/* Statistics. */
unsigned long unique_count; /* number of unique strings */
long total_count; /* total number of strings cached, including dups */
long unique_size; /* size of unique strings, in bytes */
long total_size; /* total number of bytes cached, including dups */
long structure_size; /* total size of bcache, including infrastructure */
/* Number of times that the hash table is expanded and hence
re-built, and the corresponding number of times that a string is
[re]hashed as part of entering it into the expanded table. The
total number of hashes can be computed by adding TOTAL_COUNT to
expand_hash_count. */
unsigned long expand_count;
unsigned long expand_hash_count;
/* Number of times that the half-hash compare hit (compare the upper
16 bits of hash values) hit, but the corresponding combined
length/data compare missed. */
unsigned long half_hash_miss_count;
};
/* The old hash function was stolen from SDBM. This is what DB 3.0 uses now,
* and is better than the old one.
*/
@ -73,6 +136,11 @@ expand_hash_table (struct bcache *bcache)
struct bstring **new_buckets;
unsigned int i;
/* Count the stats. Every unique item needs to be re-hashed and
re-entered. */
bcache->expand_count++;
bcache->expand_hash_count += bcache->unique_count;
/* Find the next size. */
new_num_buckets = bcache->num_buckets * 2;
for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
@ -127,9 +195,11 @@ expand_hash_table (struct bcache *bcache)
/* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has
never seen those bytes before, add a copy of them to BCACHE. In
either case, return a pointer to BCACHE's copy of that string. */
void *
bcache (const void *addr, int length, struct bcache *bcache)
static void *
bcache_data (const void *addr, int length, struct bcache *bcache)
{
unsigned long full_hash;
unsigned short half_hash;
int hash_index;
struct bstring *s;
@ -140,13 +210,24 @@ bcache (const void *addr, int length, struct bcache *bcache)
bcache->total_count++;
bcache->total_size += length;
hash_index = hash (addr, length) % bcache->num_buckets;
full_hash = hash (addr, length);
half_hash = (full_hash >> 16);
hash_index = full_hash % bcache->num_buckets;
/* Search the hash bucket for a string identical to the caller's. */
/* Search the hash bucket for a string identical to the caller's.
As a short-circuit first compare the upper part of each hash
values. */
for (s = bcache->bucket[hash_index]; s; s = s->next)
if (s->length == length
&& ! memcmp (&s->d.data, addr, length))
return &s->d.data;
{
if (s->half_hash == half_hash)
{
if (s->length == length
&& ! memcmp (&s->d.data, addr, length))
return &s->d.data;
else
bcache->half_hash_miss_count++;
}
}
/* The user's string isn't in the list. Insert it after *ps. */
{
@ -155,6 +236,7 @@ bcache (const void *addr, int length, struct bcache *bcache)
memcpy (&new->d.data, addr, length);
new->length = length;
new->next = bcache->bucket[hash_index];
new->half_hash = half_hash;
bcache->bucket[hash_index] = new;
bcache->unique_count++;
@ -165,20 +247,41 @@ bcache (const void *addr, int length, struct bcache *bcache)
}
}
void *
deprecated_bcache (const void *addr, int length, struct bcache *bcache)
{
return bcache_data (addr, length, bcache);
}
const void *
bcache (const void *addr, int length, struct bcache *bcache)
{
return bcache_data (addr, length, bcache);
}
/* Freeing bcaches. */
/* Allocating and freeing bcaches. */
struct bcache *
bcache_xmalloc (void)
{
/* Allocate the bcache pre-zeroed. */
struct bcache *b = XCALLOC (1, struct bcache);
/* We could use obstack_specify_allocation here instead, but
gdb_obstack.h specifies the allocation/deallocation
functions. */
obstack_init (&b->cache);
return b;
}
/* Free all the storage associated with BCACHE. */
void
free_bcache (struct bcache *bcache)
bcache_xfree (struct bcache *bcache)
{
if (bcache == NULL)
return;
obstack_free (&bcache->cache, 0);
if (bcache->bucket)
xfree (bcache->bucket);
/* This isn't necessary, but at least the bcache is always in a
consistent state. */
memset (bcache, 0, sizeof (*bcache));
xfree (bcache->bucket);
xfree (bcache);
}
@ -214,12 +317,16 @@ print_bcache_statistics (struct bcache *c, char *type)
int occupied_buckets;
int max_chain_length;
int median_chain_length;
int max_entry_size;
int median_entry_size;
/* Count the number of occupied buckets, and measure chain lengths. */
/* Count the number of occupied buckets, tally the various string
lengths, and measure chain lengths. */
{
unsigned int b;
int *chain_length
= (int *) alloca (c->num_buckets * sizeof (*chain_length));
int *chain_length = XCALLOC (c->num_buckets + 1, int);
int *entry_size = XCALLOC (c->unique_count + 1, int);
int stringi = 0;
occupied_buckets = 0;
@ -235,7 +342,10 @@ print_bcache_statistics (struct bcache *c, char *type)
while (s)
{
gdb_assert (b < c->num_buckets);
chain_length[b]++;
gdb_assert (stringi < c->unique_count);
entry_size[stringi++] = s->length;
s = s->next;
}
}
@ -244,6 +354,8 @@ print_bcache_statistics (struct bcache *c, char *type)
/* To compute the median, we need the set of chain lengths sorted. */
qsort (chain_length, c->num_buckets, sizeof (chain_length[0]),
compare_ints);
qsort (entry_size, c->unique_count, sizeof (entry_size[0]),
compare_ints);
if (c->num_buckets > 0)
{
@ -255,6 +367,19 @@ print_bcache_statistics (struct bcache *c, char *type)
max_chain_length = 0;
median_chain_length = 0;
}
if (c->unique_count > 0)
{
max_entry_size = entry_size[c->unique_count - 1];
median_entry_size = entry_size[c->unique_count / 2];
}
else
{
max_entry_size = 0;
median_entry_size = 0;
}
xfree (chain_length);
xfree (entry_size);
}
printf_filtered (" Cached '%s' statistics:\n", type);
@ -270,6 +395,15 @@ print_bcache_statistics (struct bcache *c, char *type)
print_percentage (c->total_size - c->unique_size, c->total_size);
printf_filtered ("\n");
printf_filtered (" Max entry size: %d\n", max_entry_size);
printf_filtered (" Average entry size: ");
if (c->unique_count > 0)
printf_filtered ("%ld\n", c->unique_size / c->unique_count);
else
printf_filtered ("(not applicable)\n");
printf_filtered (" Median entry size: %d\n", median_entry_size);
printf_filtered ("\n");
printf_filtered (" Total memory used by bcache, including overhead: %ld\n",
c->structure_size);
printf_filtered (" Percentage memory overhead: ");
@ -279,6 +413,12 @@ print_bcache_statistics (struct bcache *c, char *type)
printf_filtered ("\n");
printf_filtered (" Hash table size: %3d\n", c->num_buckets);
printf_filtered (" Hash table expands: %lu\n",
c->expand_count);
printf_filtered (" Hash table hashes: %lu\n",
c->total_count + c->expand_hash_count);
printf_filtered (" Half hash misses: %lu\n",
c->half_hash_miss_count);
printf_filtered (" Hash table population: ");
print_percentage (occupied_buckets, c->num_buckets);
printf_filtered (" Median hash chain length: %3d\n",
@ -291,3 +431,9 @@ print_bcache_statistics (struct bcache *c, char *type)
printf_filtered (" Maximum hash chain length: %3d\n", max_chain_length);
printf_filtered ("\n");
}
int
bcache_memory_used (struct bcache *bcache)
{
return obstack_memory_used (&bcache->cache);
}

View file

@ -1,7 +1,8 @@
/* Include file cached obstack implementation.
Written by Fred Fish <fnf@cygnus.com>
Rewritten by Jim Blandy <jimb@cygnus.com>
Copyright 1999, 2000 Free Software Foundation, Inc.
Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
@ -47,84 +48,123 @@
You shouldn't modify the strings you get from a bcache, because:
- You don't necessarily know who you're sharing space with. If I
stick eight bytes of text in a bcache, and then stick an
eight-byte structure in the same bcache, there's no guarantee
those two objects don't actually comprise the same sequence of
bytes. If they happen to, the bcache will use a single byte
string for both of them. Then, modifying the structure will
change the string. In bizarre ways.
stick eight bytes of text in a bcache, and then stick an eight-byte
structure in the same bcache, there's no guarantee those two
objects don't actually comprise the same sequence of bytes. If
they happen to, the bcache will use a single byte string for both
of them. Then, modifying the structure will change the string. In
bizarre ways.
- Even if you know for some other reason that all that's okay,
there's another problem. A bcache stores all its strings in a
hash table. If you modify a string's contents, you will probably
change its hash value. This means that the modified string is
now in the wrong place in the hash table, and future bcache
probes will never find it. So by mutating a string, you give up
any chance of sharing its space with future duplicates. */
there's another problem. A bcache stores all its strings in a hash
table. If you modify a string's contents, you will probably change
its hash value. This means that the modified string is now in the
wrong place in the hash table, and future bcache probes will never
find it. So by mutating a string, you give up any chance of
sharing its space with future duplicates.
/* The type used to hold a single bcache string. The user data is
stored in d.data. Since it can be any type, it needs to have the
same alignment as the most strict alignment of any type on the host
machine. I don't know of any really correct way to do this in
stock ANSI C, so just do it the same way obstack.h does.
Size of bcache VS hashtab:
It would be nicer to have this stuff hidden away in bcache.c, but
struct objstack contains a struct bcache directly --- not a pointer
to one --- and then the memory-mapped stuff makes this a real pain.
We don't strictly need to expose struct bstring, but it's better to
have it all in one place. */
For bcache, the most critical cost is size (or more exactly the
overhead added by the bcache). It turns out that the bcache is
remarkably efficient.
struct bstring {
struct bstring *next;
size_t length;
Assuming a 32-bit system (the hash table slots are 4 bytes),
ignoring alignment, and limit strings to 255 bytes (1 byte length)
we get ...
union
{
char data[1];
double dummy;
}
d;
};
bcache: This uses a separate linked list to track the hash chain.
The numbers show roughly 100% occupancy of the hash table and an
average chain length of 4. Spreading the slot cost over the 4
chain elements:
4 (slot) / 4 (chain length) + 1 (length) + 4 (chain) = 6 bytes
hashtab: This uses a more traditional re-hash algorithm where the
chain is maintained within the hash table. The table occupancy is
kept below 75% but we'll assume its perfect:
4 (slot) x 4/3 (occupancy) + 1 (length) = 6 1/3 bytes
So a perfect hashtab has just slightly larger than an average
bcache.
It turns out that an average hashtab is far worse. Two things
hurt:
- Hashtab's occupancy is more like 50% (it ranges between 38% and
75%) giving a per slot cost of 4x2 vs 4x4/3.
- the string structure needs to be aligned to 8 bytes which for
hashtab wastes 7 bytes, while for bcache wastes only 3.
This gives:
hashtab: 4 x 2 + 1 + 7 = 16 bytes
bcache 4 / 4 + 1 + 4 + 3 = 9 bytes
The numbers of GDB debugging GDB support this. ~40% vs ~70% overhead.
/* The structure for a bcache itself.
To initialize a bcache, just fill it with zeros. */
struct bcache {
/* All the bstrings are allocated here. */
struct obstack cache;
Speed of bcache VS hashtab (the half hash hack):
/* How many hash buckets we're using. */
unsigned int num_buckets;
While hashtab has a typical chain length of 1, bcache has a chain
length of round 4. This means that the bcache will require
something like double the number of compares after that initial
hash. In both cases the comparison takes the form:
a.length == b.length && memcmp (a.data, b.data, a.length) == 0
That is lengths are checked before doing the memcmp.
For GDB debugging GDB, it turned out that all lengths were 24 bytes
(no C++ so only psymbols were cached) and hence, all compares
required a call to memcmp. As a hack, two bytes of padding
(mentioned above) are used to store the upper 16 bits of the
string's hash value and then that is used in the comparison vis:
a.half_hash == b.half_hash && a.length == b.length && memcmp
(a.data, b.data, a.length)
The numbers from GDB debugging GDB show this to be a remarkable
100% effective (only necessary length and memcmp tests being
performed).
Mind you, looking at the wall clock, the same GDB debugging GDB
showed only marginal speed up (0.780 vs 0.773s). Seems GDB is too
busy doing something else :-(
/* Hash buckets. This table is allocated using malloc, so when we
grow the table we can return the old table to the system. */
struct bstring **bucket;
*/
/* Statistics. */
unsigned long unique_count; /* number of unique strings */
long total_count; /* total number of strings cached, including dups */
long unique_size; /* size of unique strings, in bytes */
long total_size; /* total number of bytes cached, including dups */
long structure_size; /* total size of bcache, including infrastructure */
};
struct bcache;
/* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has
never seen those bytes before, add a copy of them to BCACHE. In
either case, return a pointer to BCACHE's copy of that string. */
extern void *bcache (const void *addr, int length, struct bcache *bcache);
either case, return a pointer to BCACHE's copy of that string.
Since the cached value is ment to be read-only, return a const
buffer. */
extern void *deprecated_bcache (const void *addr, int length,
struct bcache *bcache);
extern const void *bcache (const void *addr, int length,
struct bcache *bcache);
/* Free all the storage that BCACHE refers to. The result is a valid,
but empty, bcache. This does not free BCACHE itself, since that
might be part of some larger object. */
extern void free_bcache (struct bcache *bcache);
/* Free all the storage used by BCACHE. */
extern void bcache_xfree (struct bcache *bcache);
/* Create a new bcache object. */
extern struct bcache *bcache_xmalloc (void);
/* Print statistics on BCACHE's memory usage and efficacity at
eliminating duplication. TYPE should be a string describing the
kind of data BCACHE holds. Statistics are printed using
`printf_filtered' and its ilk. */
extern void print_bcache_statistics (struct bcache *bcache, char *type);
extern int bcache_memory_used (struct bcache *bcache);
/* The hash function */
extern unsigned long hash(const void *addr, int length);
#endif /* BCACHE_H */

View file

@ -0,0 +1,131 @@
/* Very simple "bfd" target, for GDB, the GNU debugger.
Copyright 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "target.h"
#include "bfd-target.h"
#include "gdb_assert.h"
#include "gdb_string.h"
/* Locate all mappable sections of a BFD file, filling in a target
section for each. */
struct section_closure
{
struct section_table *end;
};
static void
add_to_section_table (struct bfd *abfd, struct bfd_section *asect,
void *closure)
{
struct section_closure *pp = closure;
flagword aflag;
/* NOTE: cagney/2003-10-22: Is this pruning useful? */
aflag = bfd_get_section_flags (abfd, asect);
if (!(aflag & SEC_ALLOC))
return;
if (bfd_section_size (abfd, asect) == 0)
return;
pp->end->bfd = abfd;
pp->end->the_bfd_section = asect;
pp->end->addr = bfd_section_vma (abfd, asect);
pp->end->endaddr = pp->end->addr + bfd_section_size (abfd, asect);
pp->end++;
}
void
build_target_sections_from_bfd (struct target_ops *targ, struct bfd *abfd)
{
unsigned count;
struct section_table *start;
struct section_closure cl;
count = bfd_count_sections (abfd);
target_resize_to_sections (targ, count);
start = targ->to_sections;
cl.end = targ->to_sections;
bfd_map_over_sections (abfd, add_to_section_table, &cl);
gdb_assert (cl.end - start <= count);
}
LONGEST
target_bfd_xfer_partial (struct target_ops *ops,
enum target_object object,
const char *annex, void *readbuf,
const void *writebuf, ULONGEST offset, LONGEST len)
{
switch (object)
{
case TARGET_OBJECT_MEMORY:
{
struct section_table *s = target_section_by_addr (ops, offset);
if (s == NULL)
return -1;
/* If the length extends beyond the section, truncate it. Be
careful to not suffer from overflow (wish S contained a
length). */
if ((offset - s->addr + len) > (s->endaddr - s->addr))
len = (s->endaddr - s->addr) - (offset - s->addr);
if (readbuf != NULL
&& !bfd_get_section_contents (s->bfd, s->the_bfd_section,
readbuf, offset - s->addr, len))
return -1;
#if 1
if (writebuf != NULL)
return -1;
#else
/* FIXME: cagney/2003-10-31: The BFD interface doesn't yet
take a const buffer. */
if (writebuf != NULL
&& !bfd_set_section_contents (s->bfd, s->the_bfd_section,
writebuf, offset - s->addr, len))
return -1;
#endif
return len;
}
default:
return -1;
}
}
void
target_bfd_xclose (struct target_ops *t, int quitting)
{
bfd_close (t->to_data);
xfree (t->to_sections);
xfree (t);
}
struct target_ops *
target_bfd_reopen (struct bfd *bfd)
{
struct target_ops *t = XZALLOC (struct target_ops);
t->to_shortname = "bfd";
t->to_longname = "BFD backed target";
t->to_doc = "You should never see this";
t->to_xfer_partial = target_bfd_xfer_partial;
t->to_xclose = target_bfd_xclose;
t->to_data = bfd;
build_target_sections_from_bfd (t, bfd);
return t;
}

View file

@ -0,0 +1,39 @@
/* Very simple "bfd" target, for GDB, the GNU debugger.
Copyright 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef BFD_TARGET_H
#define BFD_TARGET_H
struct bfd;
struct target_ops;
/* Given an existing BFD, re-open it as a "struct target_ops". On
close, it will also close the corresponding BFD (which is like
freopen and fdopen). */
struct target_ops *target_bfd_reopen (struct bfd *bfd);
/* Map over ABFD's sections, creating corresponding entries in the
target's section table. */
void build_target_sections_from_bfd (struct target_ops *targ,
struct bfd *abfd);
#endif

295
contrib/gdb/gdb/block.c Normal file
View file

@ -0,0 +1,295 @@
/* Block-related functions for the GNU debugger, GDB.
Copyright 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "block.h"
#include "symtab.h"
#include "symfile.h"
#include "gdb_obstack.h"
#include "cp-support.h"
/* This is used by struct block to store namespace-related info for
C++ files, namely using declarations and the current namespace in
scope. */
struct block_namespace_info
{
const char *scope;
struct using_direct *using;
};
static void block_initialize_namespace (struct block *block,
struct obstack *obstack);
/* Return Nonzero if block a is lexically nested within block b,
or if a and b have the same pc range.
Return zero otherwise. */
int
contained_in (const struct block *a, const struct block *b)
{
if (!a || !b)
return 0;
return BLOCK_START (a) >= BLOCK_START (b)
&& BLOCK_END (a) <= BLOCK_END (b);
}
/* Return the symbol for the function which contains a specified
lexical block, described by a struct block BL. */
struct symbol *
block_function (const struct block *bl)
{
while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
bl = BLOCK_SUPERBLOCK (bl);
return BLOCK_FUNCTION (bl);
}
/* Return the blockvector immediately containing the innermost lexical block
containing the specified pc value and section, 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_sect (CORE_ADDR pc, struct bfd_section *section,
int *pindex, struct symtab *symtab)
{
struct block *b;
int bot, top, half;
struct blockvector *bl;
if (symtab == 0) /* if no symtab specified by caller */
{
/* First search all symtabs for one whose file contains our pc */
symtab = find_pc_sect_symtab (pc, section);
if (symtab == 0)
return 0;
}
bl = BLOCKVECTOR (symtab);
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 blockvector immediately containing the innermost lexical block
containing the specified pc value, or 0 if there is none.
Backward compatibility, no section. */
struct blockvector *
blockvector_for_pc (CORE_ADDR pc, int *pindex)
{
return blockvector_for_pc_sect (pc, find_pc_mapped_section (pc),
pindex, NULL);
}
/* Return the innermost lexical block containing the specified pc value
in the specified section, or 0 if there is none. */
struct block *
block_for_pc_sect (CORE_ADDR pc, struct bfd_section *section)
{
struct blockvector *bl;
int index;
bl = blockvector_for_pc_sect (pc, section, &index, NULL);
if (bl)
return BLOCKVECTOR_BLOCK (bl, index);
return 0;
}
/* Return the innermost lexical block containing the specified pc value,
or 0 if there is none. Backward compatibility, no section. */
struct block *
block_for_pc (CORE_ADDR pc)
{
return block_for_pc_sect (pc, find_pc_mapped_section (pc));
}
/* Now come some functions designed to deal with C++ namespace issues.
The accessors are safe to use even in the non-C++ case. */
/* This returns the namespace that BLOCK is enclosed in, or "" if it
isn't enclosed in a namespace at all. This travels the chain of
superblocks looking for a scope, if necessary. */
const char *
block_scope (const struct block *block)
{
for (; block != NULL; block = BLOCK_SUPERBLOCK (block))
{
if (BLOCK_NAMESPACE (block) != NULL
&& BLOCK_NAMESPACE (block)->scope != NULL)
return BLOCK_NAMESPACE (block)->scope;
}
return "";
}
/* Set BLOCK's scope member to SCOPE; if needed, allocate memory via
OBSTACK. (It won't make a copy of SCOPE, however, so that already
has to be allocated correctly.) */
void
block_set_scope (struct block *block, const char *scope,
struct obstack *obstack)
{
block_initialize_namespace (block, obstack);
BLOCK_NAMESPACE (block)->scope = scope;
}
/* This returns the first using directives associated to BLOCK, if
any. */
/* FIXME: carlton/2003-04-23: This uses the fact that we currently
only have using directives in static blocks, because we only
generate using directives from anonymous namespaces. Eventually,
when we support using directives everywhere, we'll want to replace
this by some iterator functions. */
struct using_direct *
block_using (const struct block *block)
{
const struct block *static_block = block_static_block (block);
if (static_block == NULL
|| BLOCK_NAMESPACE (static_block) == NULL)
return NULL;
else
return BLOCK_NAMESPACE (static_block)->using;
}
/* Set BLOCK's using member to USING; if needed, allocate memory via
OBSTACK. (It won't make a copy of USING, however, so that already
has to be allocated correctly.) */
void
block_set_using (struct block *block,
struct using_direct *using,
struct obstack *obstack)
{
block_initialize_namespace (block, obstack);
BLOCK_NAMESPACE (block)->using = using;
}
/* If BLOCK_NAMESPACE (block) is NULL, allocate it via OBSTACK and
ititialize its members to zero. */
static void
block_initialize_namespace (struct block *block, struct obstack *obstack)
{
if (BLOCK_NAMESPACE (block) == NULL)
{
BLOCK_NAMESPACE (block)
= obstack_alloc (obstack, sizeof (struct block_namespace_info));
BLOCK_NAMESPACE (block)->scope = NULL;
BLOCK_NAMESPACE (block)->using = NULL;
}
}
/* Return the static block associated to BLOCK. Return NULL if block
is NULL or if block is a global block. */
const struct block *
block_static_block (const struct block *block)
{
if (block == NULL || BLOCK_SUPERBLOCK (block) == NULL)
return NULL;
while (BLOCK_SUPERBLOCK (BLOCK_SUPERBLOCK (block)) != NULL)
block = BLOCK_SUPERBLOCK (block);
return block;
}
/* Return the static block associated to BLOCK. Return NULL if block
is NULL. */
const struct block *
block_global_block (const struct block *block)
{
if (block == NULL)
return NULL;
while (BLOCK_SUPERBLOCK (block) != NULL)
block = BLOCK_SUPERBLOCK (block);
return block;
}
/* Allocate a block on OBSTACK, and initialize its elements to
zero/NULL. This is useful for creating "dummy" blocks that don't
correspond to actual source files.
Warning: it sets the block's BLOCK_DICT to NULL, which isn't a
valid value. If you really don't want the block to have a
dictionary, then you should subsequently set its BLOCK_DICT to
dict_create_linear (obstack, NULL). */
struct block *
allocate_block (struct obstack *obstack)
{
struct block *bl = obstack_alloc (obstack, sizeof (struct block));
BLOCK_START (bl) = 0;
BLOCK_END (bl) = 0;
BLOCK_FUNCTION (bl) = NULL;
BLOCK_SUPERBLOCK (bl) = NULL;
BLOCK_DICT (bl) = NULL;
BLOCK_NAMESPACE (bl) = NULL;
BLOCK_GCC_COMPILED (bl) = 0;
return bl;
}

174
contrib/gdb/gdb/block.h Normal file
View file

@ -0,0 +1,174 @@
/* Code dealing with blocks for GDB.
Copyright 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef BLOCK_H
#define BLOCK_H
/* Opaque declarations. */
struct symbol;
struct symtab;
struct block_namespace_info;
struct using_direct;
struct obstack;
struct dictionary;
/* 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 blockvector begins with some special blocks.
The GLOBAL_BLOCK contains all the symbols defined in this compilation
whose scope is the entire program linked together.
The STATIC_BLOCK contains all the symbols whose scope is the
entire compilation excluding other separate compilations.
Blocks starting with the FIRST_LOCAL_BLOCK are not special.
Each block records a range of core addresses for the code that
is in the scope of the block. The STATIC_BLOCK and GLOBAL_BLOCK
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 block
{
/* Addresses in the executable code that are in this block. */
CORE_ADDR startaddr;
CORE_ADDR endaddr;
/* The symbol that names this block, if the block is the body of a
function; otherwise, zero. */
struct symbol *function;
/* The `struct block' for the containing block, or 0 if none.
The superblock of a top-level local block (i.e. a function in the
case of C) is the STATIC_BLOCK. The superblock of the
STATIC_BLOCK is the GLOBAL_BLOCK. */
struct block *superblock;
/* This is used to store the symbols in the block. */
struct dictionary *dict;
/* Used for language-specific info. */
union
{
struct
{
/* Contains information about namespace-related info relevant to
this block: using directives and the current namespace
scope. */
struct block_namespace_info *namespace;
}
cplus_specific;
}
language_specific;
/* Version of GCC used to compile the function corresponding
to this block, or 0 if not compiled with GCC. When possible,
GCC should be compatible with the native compiler, or if that
is not feasible, the differences should be fixed during symbol
reading. As of 16 Apr 93, this flag is never used to distinguish
between gcc2 and the native compiler.
If there is no function corresponding to this block, this meaning
of this flag is undefined. */
unsigned char gcc_compile_flag;
};
#define BLOCK_START(bl) (bl)->startaddr
#define BLOCK_END(bl) (bl)->endaddr
#define BLOCK_FUNCTION(bl) (bl)->function
#define BLOCK_SUPERBLOCK(bl) (bl)->superblock
#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag
#define BLOCK_DICT(bl) (bl)->dict
#define BLOCK_NAMESPACE(bl) (bl)->language_specific.cplus_specific.namespace
/* Macro to loop through all symbols in a block BL, in no particular
order. ITER helps keep track of the iteration, and should be a
struct dict_iterator. SYM points to the current symbol. */
#define ALL_BLOCK_SYMBOLS(block, iter, sym) \
ALL_DICT_SYMBOLS (BLOCK_DICT (block), iter, sym)
struct blockvector
{
/* Number of blocks in the list. */
int nblocks;
/* The blocks themselves. */
struct block *block[1];
};
#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks
#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n]
/* Special block numbers */
enum { GLOBAL_BLOCK = 0, STATIC_BLOCK = 1, FIRST_LOCAL_BLOCK = 2 };
extern struct symbol *block_function (const struct block *);
extern int contained_in (const struct block *, const struct block *);
extern struct blockvector *blockvector_for_pc (CORE_ADDR, int *);
extern struct blockvector *blockvector_for_pc_sect (CORE_ADDR, asection *,
int *, struct symtab *);
extern struct block *block_for_pc (CORE_ADDR);
extern struct block *block_for_pc_sect (CORE_ADDR, asection *);
extern const char *block_scope (const struct block *block);
extern void block_set_scope (struct block *block, const char *scope,
struct obstack *obstack);
extern struct using_direct *block_using (const struct block *block);
extern void block_set_using (struct block *block,
struct using_direct *using,
struct obstack *obstack);
extern const struct block *block_static_block (const struct block *block);
extern const struct block *block_global_block (const struct block *block);
extern struct block *allocate_block (struct obstack *obstack);
#endif /* BLOCK_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
/* Data structures associated with breakpoints in GDB.
Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@ -28,6 +29,7 @@
#include "gdb-events.h"
struct value;
struct block;
/* 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
@ -183,6 +185,97 @@ enum target_hw_bp_type
hw_execute = 3 /* Execute HW breakpoint */
};
/* GDB maintains two types of information about each breakpoint (or
watchpoint, or other related event). The first type corresponds
to struct breakpoint; this is a relatively high-level structure
which contains the source location(s), stopping conditions, user
commands to execute when the breakpoint is hit, and so forth.
The second type of information corresponds to struct bp_location.
Each breakpoint has one or (eventually) more locations associated
with it, which represent target-specific and machine-specific
mechanisms for stopping the program. For instance, a watchpoint
expression may require multiple hardware watchpoints in order to
catch all changes in the value of the expression being watched. */
enum bp_loc_type
{
bp_loc_software_breakpoint,
bp_loc_hardware_breakpoint,
bp_loc_hardware_watchpoint,
bp_loc_other /* Miscellaneous... */
};
struct bp_location
{
/* Chain pointer to the next breakpoint location. */
struct bp_location *next;
/* Type of this breakpoint location. */
enum bp_loc_type loc_type;
/* Each breakpoint location must belong to exactly one higher-level
breakpoint. This and the DUPLICATE flag are more straightforward
than reference counting. */
struct breakpoint *owner;
/* Nonzero if this breakpoint is now inserted. */
char inserted;
/* Nonzero if this is not the first breakpoint in the list
for the given address. */
char duplicate;
/* If we someday support real thread-specific breakpoints, then
the breakpoint location will need a thread identifier. */
/* Data for specific breakpoint types. These could be a union, but
simplicity is more important than memory usage for breakpoints. */
/* Note that zero is a perfectly valid code address on some platforms
(for example, the mn10200 (OBSOLETE) and mn10300 simulators). NULL
is not a special value for this field. Valid for all types except
bp_loc_other. */
CORE_ADDR address;
/* For any breakpoint type with an address, this is the BFD section
associated with the address. Used primarily for overlay debugging. */
asection *section;
/* "Real" contents of byte where breakpoint has been inserted.
Valid only when breakpoints are in the program. Under the complete
control of the target insert_breakpoint and remove_breakpoint routines.
No other code should assume anything about the value(s) here.
Valid only for bp_loc_software_breakpoint. */
char shadow_contents[BREAKPOINT_MAX];
/* Address at which breakpoint was requested, either by the user or
by GDB for internal breakpoints. This will usually be the same
as ``address'' (above) except for cases in which
ADJUST_BREAKPOINT_ADDRESS has computed a different address at
which to place the breakpoint in order to comply with a
processor's architectual constraints. */
CORE_ADDR requested_address;
};
/* This structure is a collection of function pointers that, if available,
will be called instead of the performing the default action for this
bptype. */
struct breakpoint_ops
{
/* The normal print routine for this breakpoint, called when we
hit it. */
enum print_stop_action (*print_it) (struct breakpoint *);
/* Display information about this breakpoint, for "info breakpoints". */
void (*print_one) (struct breakpoint *, CORE_ADDR *);
/* Display information about this breakpoint after setting it (roughly
speaking; this is called from "mention"). */
void (*print_mention) (struct breakpoint *);
};
/* Note that the ->silent field is not currently used by any commands
(though the code is in there if it was to be, and set_raw_breakpoint
does set it to 0). I implemented it because I thought it would be
@ -203,11 +296,8 @@ struct breakpoint
/* Number assigned to distinguish breakpoints. */
int number;
/* Address to break at.
Note that zero is a perfectly valid code address on some
platforms (for example, the mn10200 and mn10300 simulators).
NULL is not a special value for this field. */
CORE_ADDR address;
/* Location(s) associated with this high-level breakpoint. */
struct bp_location *loc;
/* Line number of this address. */
@ -223,21 +313,11 @@ struct breakpoint
/* Number of stops at this breakpoint that should
be continued automatically before really stopping. */
int ignore_count;
/* "Real" contents of byte where breakpoint has been inserted.
Valid only when breakpoints are in the program. Under the complete
control of the target insert_breakpoint and remove_breakpoint routines.
No other code should assume anything about the value(s) here. */
char shadow_contents[BREAKPOINT_MAX];
/* Nonzero if this breakpoint is now inserted. */
char inserted;
/* Nonzero if this is not the first breakpoint in the list
for the given address. */
char duplicate;
/* Chain of command lines to execute when this breakpoint is hit. */
struct command_line *commands;
/* Stack depth (address of frame). If nonzero, break only if fp
equals this. */
CORE_ADDR frame;
struct frame_id frame_id;
/* Conditional. Break only if this expression's value is nonzero. */
struct expression *cond;
@ -270,10 +350,10 @@ struct breakpoint
it the watchpoint_scope breakpoint or something like that. FIXME). */
struct breakpoint *related_breakpoint;
/* Holds the frame address which identifies the frame this watchpoint
should be evaluated in, or NULL if the watchpoint should be evaluated
on the outermost frame. */
CORE_ADDR watchpoint_frame;
/* Holds the frame address which identifies the frame this
watchpoint should be evaluated in, or `null' if the watchpoint
should be evaluated on the outermost frame. */
struct frame_id watchpoint_frame;
/* Thread number for thread-specific breakpoint, or -1 if don't care */
int thread;
@ -304,7 +384,19 @@ struct breakpoint
triggered. */
char *exec_pathname;
asection *section;
/* Methods associated with this breakpoint. */
struct breakpoint_ops *ops;
/* Was breakpoint issued from a tty? Saved for the use of pending breakpoints. */
int from_tty;
/* Flag value for pending breakpoint.
first bit : 0 non-temporary, 1 temporary.
second bit : 0 normal breakpoint, 1 hardware breakpoint. */
int flag;
/* Is breakpoint pending on shlib loads? */
int pending;
};
/* The following stuff is an abstract data type "bpstat" ("breakpoint
@ -322,7 +414,7 @@ extern void bpstat_clear (bpstat *);
is part of the bpstat is copied as well. */
extern bpstat bpstat_copy (bpstat);
extern bpstat bpstat_stop_status (CORE_ADDR *, int);
extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid);
/* This bpstat_what stuff tells wait_for_inferior what to do with a
breakpoint (a challenging task). */
@ -521,18 +613,22 @@ enum breakpoint_here
/* Prototypes for breakpoint-related functions. */
/* Forward declarations for prototypes */
struct frame_info;
extern enum breakpoint_here breakpoint_here_p (CORE_ADDR);
extern int breakpoint_inserted_here_p (CORE_ADDR);
extern int frame_in_dummy (struct frame_info *);
extern int software_breakpoint_inserted_here_p (CORE_ADDR);
/* FIXME: cagney/2002-11-10: The current [generic] dummy-frame code
implements a functional superset of this function. The only reason
it hasn't been removed is because some architectures still don't
use the new framework. Once they have been fixed, this can go. */
struct frame_info;
extern int deprecated_frame_in_dummy (struct frame_info *);
extern int breakpoint_thread_match (CORE_ADDR, ptid_t);
extern void until_break_command (char *, int);
extern void until_break_command (char *, int, int);
extern void breakpoint_re_set (void);
@ -541,7 +637,7 @@ extern void breakpoint_re_set_thread (struct breakpoint *);
extern int ep_is_exception_catchpoint (struct breakpoint *);
extern struct breakpoint *set_momentary_breakpoint
(struct symtab_and_line, struct frame_info *, enum bptype);
(struct symtab_and_line, struct frame_id, enum bptype);
extern void set_ignore_count (int, int, int);
@ -615,12 +711,12 @@ extern void disable_longjmp_breakpoint (void);
extern void enable_overlay_breakpoints (void);
extern void disable_overlay_breakpoints (void);
extern void set_longjmp_resume_breakpoint (CORE_ADDR, struct frame_info *);
extern void set_longjmp_resume_breakpoint (CORE_ADDR, struct frame_id);
/* These functions respectively disable or reenable all currently
enabled watchpoints. When disabled, the watchpoints are marked
call_disabled. When reenabled, they are marked enabled.
The intended client of these functions is infcmd.c\run_stack_dummy.
The intended client of these functions is call_function_by_hand.
The inferior must be stopped, and all breakpoints removed, when
these functions are used.

View file

@ -1,6 +1,7 @@
/* Support routines for building symbol tables in GDB's internal format.
Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@ -28,17 +29,24 @@
#include "defs.h"
#include "bfd.h"
#include "obstack.h"
#include "gdb_obstack.h"
#include "symtab.h"
#include "symfile.h" /* Needed for "struct complaint" */
#include "symfile.h"
#include "objfiles.h"
#include "gdbtypes.h"
#include "gdb_assert.h"
#include "complaints.h"
#include "gdb_string.h"
#include "expression.h" /* For "enum exp_opcode" used by... */
#include "language.h" /* For "longest_local_hex_string_custom" */
#include "language.h" /* For "local_hex_string" */
#include "bcache.h"
#include "filenames.h" /* For DOSish file names */
#include "macrotab.h"
#include "demangle.h" /* Needed by SYMBOL_INIT_DEMANGLED_NAME. */
#include "block.h"
#include "cp-support.h"
#include "dictionary.h"
/* Ask buildsym.h to define the vars it normally declares `extern'. */
#define EXTERN
/**/
@ -70,30 +78,13 @@ static int compare_line_numbers (const void *ln1p, const void *ln2p);
#define INITIAL_LINE_VECTOR_LENGTH 1000
/* Complaints about the symbols we have encountered. */
struct complaint block_end_complaint =
{"block end address less than block start address in %s (patched it)", 0, 0};
struct complaint anon_block_end_complaint =
{"block end address 0x%lx less than block start address 0x%lx (patched it)", 0, 0};
struct complaint innerblock_complaint =
{"inner block not inside outer block in %s", 0, 0};
struct complaint innerblock_anon_complaint =
{"inner block (0x%lx-0x%lx) not inside outer block (0x%lx-0x%lx)", 0, 0};
struct complaint blockvector_complaint =
{"block at %s out of order", 0, 0};
/* maintain the lists of symbols and blocks */
/* Add a pending list to free_pendings. */
void
add_free_pendings (struct pending *list)
{
register struct pending *link = list;
struct pending *link = list;
if (list)
{
@ -103,12 +94,15 @@ add_free_pendings (struct pending *list)
}
}
/* Add a symbol to one of the lists of symbols. */
/* Add a symbol to one of the lists of symbols. While we're at it, if
we're in the C++ case and don't have full namespace debugging info,
check to see if it references an anonymous namespace; if so, add an
appropriate using directive. */
void
add_symbol_to_list (struct symbol *symbol, struct pending **listhead)
{
register struct pending *link;
struct pending *link;
/* If this is an alias for another symbol, don't add it. */
if (symbol->ginfo.name && symbol->ginfo.name[0] == '#')
@ -134,6 +128,12 @@ add_symbol_to_list (struct symbol *symbol, struct pending **listhead)
}
(*listhead)->symbol[(*listhead)->nsyms++] = symbol;
/* Check to see if we might need to look for a mention of anonymous
namespaces. */
if (SYMBOL_LANGUAGE (symbol) == language_cplus)
cp_scan_for_anonymous_namespaces (symbol);
}
/* Find a symbol named NAME on a LIST. NAME need not be
@ -149,7 +149,7 @@ find_symbol_in_list (struct pending *list, char *name, int length)
{
for (j = list->nsyms; --j >= 0;)
{
pp = SYMBOL_NAME (list->symbol[j]);
pp = DEPRECATED_SYMBOL_NAME (list->symbol[j]);
if (*pp == *name && strncmp (pp, name, length) == 0 &&
pp[length] == '\0')
{
@ -164,9 +164,8 @@ find_symbol_in_list (struct pending *list, char *name, int length)
/* At end of reading syms, or in case of quit, really free as many
`struct pending's as we can easily find. */
/* ARGSUSED */
void
really_free_pendings (PTR dummy)
really_free_pendings (void *dummy)
{
struct pending *next, *next1;
@ -192,6 +191,9 @@ really_free_pendings (PTR dummy)
xfree ((void *) next);
}
global_symbols = NULL;
if (pending_macros)
free_macro_table (pending_macros);
}
/* This function is called to discard any pending blocks. */
@ -200,7 +202,7 @@ void
free_pending_blocks (void)
{
#if 0 /* Now we make the links in the
symbol_obstack, so don't free
objfile_obstack, so don't free
them. */
struct pending_block *bnext, *bnext1;
@ -223,40 +225,29 @@ finish_block (struct symbol *symbol, struct pending **listhead,
CORE_ADDR start, CORE_ADDR end,
struct objfile *objfile)
{
register struct pending *next, *next1;
register struct block *block;
register struct pending_block *pblock;
struct pending *next, *next1;
struct block *block;
struct pending_block *pblock;
struct pending_block *opblock;
register int i;
register int j;
/* Count the length of the list of symbols. */
block = allocate_block (&objfile->objfile_obstack);
for (next = *listhead, i = 0;
next;
i += next->nsyms, next = next->next)
if (symbol)
{
/* EMPTY */ ;
BLOCK_DICT (block) = dict_create_linear (&objfile->objfile_obstack,
*listhead);
}
block = (struct block *) obstack_alloc (&objfile->symbol_obstack,
(sizeof (struct block) + ((i - 1) * sizeof (struct symbol *))));
/* Copy the symbols into the block. */
BLOCK_NSYMS (block) = i;
for (next = *listhead; next; next = next->next)
else
{
for (j = next->nsyms - 1; j >= 0; j--)
{
BLOCK_SYM (block, --i) = next->symbol[j];
}
BLOCK_DICT (block) = dict_create_hashed (&objfile->objfile_obstack,
*listhead);
}
BLOCK_START (block) = start;
BLOCK_END (block) = end;
/* Superblock filled in when containing block is made */
BLOCK_SUPERBLOCK (block) = NULL;
BLOCK_NAMESPACE (block) = NULL;
BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
@ -265,6 +256,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
if (symbol)
{
struct type *ftype = SYMBOL_TYPE (symbol);
struct dict_iterator iter;
SYMBOL_BLOCK_VALUE (symbol) = block;
BLOCK_FUNCTION (block) = symbol;
@ -275,7 +267,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
parameter symbols. */
int nparams = 0, iparams;
struct symbol *sym;
ALL_BLOCK_SYMBOLS (block, i, sym)
ALL_BLOCK_SYMBOLS (block, iter, sym)
{
switch (SYMBOL_CLASS (sym))
{
@ -285,6 +277,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_LOCAL_ARG:
case LOC_COMPUTED_ARG:
nparams++;
break;
case LOC_UNDEF:
@ -300,6 +293,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
case LOC_BASEREG:
case LOC_UNRESOLVED:
case LOC_OPTIMIZED_OUT:
case LOC_COMPUTED:
default:
break;
}
@ -310,9 +304,12 @@ finish_block (struct symbol *symbol, struct pending **listhead,
TYPE_FIELDS (ftype) = (struct field *)
TYPE_ALLOC (ftype, nparams * sizeof (struct field));
for (i = iparams = 0; iparams < nparams; i++)
iparams = 0;
ALL_BLOCK_SYMBOLS (block, iter, sym)
{
sym = BLOCK_SYM (block, i);
if (iparams == nparams)
break;
switch (SYMBOL_CLASS (sym))
{
case LOC_ARG:
@ -321,6 +318,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_LOCAL_ARG:
case LOC_COMPUTED_ARG:
TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym);
TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0;
iparams++;
@ -338,12 +336,19 @@ finish_block (struct symbol *symbol, struct pending **listhead,
case LOC_BASEREG:
case LOC_UNRESOLVED:
case LOC_OPTIMIZED_OUT:
case LOC_COMPUTED:
default:
break;
}
}
}
}
/* If we're in the C++ case, set the block's scope. */
if (SYMBOL_LANGUAGE (symbol) == language_cplus)
{
cp_set_block_scope (symbol, block, &objfile->objfile_obstack);
}
}
else
{
@ -368,11 +373,15 @@ finish_block (struct symbol *symbol, struct pending **listhead,
{
if (symbol)
{
complain (&block_end_complaint, SYMBOL_SOURCE_NAME (symbol));
complaint (&symfile_complaints,
"block end address less than block start address in %s (patched it)",
SYMBOL_PRINT_NAME (symbol));
}
else
{
complain (&anon_block_end_complaint, BLOCK_END (block), BLOCK_START (block));
complaint (&symfile_complaints,
"block end address 0x%s less than block start address 0x%s (patched it)",
paddr_nz (BLOCK_END (block)), paddr_nz (BLOCK_START (block)));
}
/* Better than nothing */
BLOCK_END (block) = BLOCK_START (block);
@ -383,7 +392,9 @@ finish_block (struct symbol *symbol, struct pending **listhead,
start of this scope that don't have superblocks yet. */
opblock = NULL;
for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
for (pblock = pending_blocks;
pblock && pblock != old_blocks;
pblock = pblock->next)
{
if (BLOCK_SUPERBLOCK (pblock->block) == NULL)
{
@ -396,14 +407,18 @@ finish_block (struct symbol *symbol, struct pending **listhead,
{
if (symbol)
{
complain (&innerblock_complaint,
SYMBOL_SOURCE_NAME (symbol));
complaint (&symfile_complaints,
"inner block not inside outer block in %s",
SYMBOL_PRINT_NAME (symbol));
}
else
{
complain (&innerblock_anon_complaint, BLOCK_START (pblock->block),
BLOCK_END (pblock->block), BLOCK_START (block),
BLOCK_END (block));
complaint (&symfile_complaints,
"inner block (0x%s-0x%s) not inside outer block (0x%s-0x%s)",
paddr_nz (BLOCK_START (pblock->block)),
paddr_nz (BLOCK_END (pblock->block)),
paddr_nz (BLOCK_START (block)),
paddr_nz (BLOCK_END (block)));
}
if (BLOCK_START (pblock->block) < BLOCK_START (block))
BLOCK_START (pblock->block) = BLOCK_START (block);
@ -419,21 +434,22 @@ finish_block (struct symbol *symbol, struct pending **listhead,
record_pending_block (objfile, block, opblock);
}
/* Record BLOCK on the list of all blocks in the file. Put it after
OPBLOCK, or at the beginning if opblock is NULL. This puts the
block in the list after all its subblocks.
Allocate the pending block struct in the symbol_obstack to save
Allocate the pending block struct in the objfile_obstack to save
time. This wastes a little space. FIXME: Is it worth it? */
void
record_pending_block (struct objfile *objfile, struct block *block,
struct pending_block *opblock)
{
register struct pending_block *pblock;
struct pending_block *pblock;
pblock = (struct pending_block *)
obstack_alloc (&objfile->symbol_obstack, sizeof (struct pending_block));
obstack_alloc (&objfile->objfile_obstack, sizeof (struct pending_block));
pblock->block = block;
if (opblock)
{
@ -447,16 +463,12 @@ record_pending_block (struct objfile *objfile, struct block *block,
}
}
/* Note that this is only used in this file and in dstread.c, which
should be fixed to not need direct access to this function. When
that is done, it can be made static again. */
struct blockvector *
static struct blockvector *
make_blockvector (struct objfile *objfile)
{
register struct pending_block *next;
register struct blockvector *blockvector;
register int i;
struct pending_block *next;
struct blockvector *blockvector;
int i;
/* Count the length of the list of blocks. */
@ -465,7 +477,7 @@ make_blockvector (struct objfile *objfile)
}
blockvector = (struct blockvector *)
obstack_alloc (&objfile->symbol_obstack,
obstack_alloc (&objfile->objfile_obstack,
(sizeof (struct blockvector)
+ (i - 1) * sizeof (struct block *)));
@ -508,8 +520,8 @@ make_blockvector (struct objfile *objfile)
CORE_ADDR start
= BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i));
complain (&blockvector_complaint,
longest_local_hex_string ((LONGEST) start));
complaint (&symfile_complaints, "block at %s out of order",
local_hex_string ((LONGEST) start));
}
}
}
@ -526,7 +538,7 @@ make_blockvector (struct objfile *objfile)
void
start_subfile (char *name, char *dirname)
{
register struct subfile *subfile;
struct subfile *subfile;
/* See if this subfile is already known as a subfile of the current
main source file. */
@ -580,15 +592,9 @@ start_subfile (char *name, char *dirname)
later via a call to record_debugformat. */
subfile->debugformat = NULL;
/* cfront output is a C program, so in most ways it looks like a C
program. But to demangle we need to set the language to C++. We
can distinguish cfront code by the fact that it has #line
directives which specify a file name ending in .C.
So if the filename of this subfile ends in .C, then change the
/* If the filename of this subfile ends in .C, then change the
language of any pending subfiles from C to C++. We also accept
any other C++ suffixes accepted by deduce_language_from_filename
(in particular, some people use .cxx with cfront). */
any other C++ suffixes accepted by deduce_language_from_filename. */
/* Likewise for f2c. */
if (subfile->name)
@ -662,7 +668,7 @@ patch_subfile_names (struct subfile *subfile, char *name)
void
push_subfile (void)
{
register struct subfile_stack *tem
struct subfile_stack *tem
= (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack));
tem->next = subfile_stack;
@ -677,8 +683,8 @@ push_subfile (void)
char *
pop_subfile (void)
{
register char *name;
register struct subfile_stack *link = subfile_stack;
char *name;
struct subfile_stack *link = subfile_stack;
if (link == NULL)
{
@ -694,7 +700,7 @@ pop_subfile (void)
line vector for SUBFILE. */
void
record_line (register struct subfile *subfile, int line, CORE_ADDR pc)
record_line (struct subfile *subfile, int line, CORE_ADDR pc)
{
struct linetable_entry *e;
/* Ignore the dummy line number in libg.o */
@ -777,6 +783,10 @@ start_symtab (char *name, char *dirname, CORE_ADDR start_addr)
}
context_stack_depth = 0;
/* Set up support for C++ namespace support, in case we need it. */
cp_initialize_namespace ();
/* Initialize the list of sub source files with one entry for this
file (the top-level source file). */
@ -805,10 +815,10 @@ start_symtab (char *name, char *dirname, CORE_ADDR start_addr)
struct symtab *
end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
{
register struct symtab *symtab = NULL;
register struct blockvector *blockvector;
register struct subfile *subfile;
register struct context_stack *cstk;
struct symtab *symtab = NULL;
struct blockvector *blockvector;
struct subfile *subfile;
struct context_stack *cstk;
struct subfile *nextsub;
/* Finish the lexical context of the last function in the file; pop
@ -828,9 +838,8 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
same. FIXME: Find out why it is happening. This is not
believed to happen in most cases (even for coffread.c);
it used to be an abort(). */
static struct complaint msg =
{"Context stack not empty in end_symtab", 0, 0};
complain (&msg);
complaint (&symfile_complaints,
"Context stack not empty in end_symtab");
context_stack_depth = 0;
}
}
@ -883,7 +892,8 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
if (pending_blocks == NULL
&& file_symbols == NULL
&& global_symbols == NULL
&& have_line_numbers == 0)
&& have_line_numbers == 0
&& pending_macros == NULL)
{
/* Ignore symtabs that have no functions with real debugging
info. */
@ -898,6 +908,8 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
objfile);
blockvector = make_blockvector (objfile);
cp_finalize_namespace (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK),
&objfile->objfile_obstack);
}
#ifndef PROCESS_LINENUMBER_HOOK
@ -944,11 +956,12 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
/* Fill in its components. */
symtab->blockvector = blockvector;
symtab->macro_table = pending_macros;
if (subfile->line_vector)
{
/* Reallocate the line table on the symbol obstack */
symtab->linetable = (struct linetable *)
obstack_alloc (&objfile->symbol_obstack, linetablesize);
obstack_alloc (&objfile->objfile_obstack, linetablesize);
memcpy (symtab->linetable, subfile->line_vector, linetablesize);
}
else
@ -960,7 +973,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
{
/* Reallocate the dirname on the symbol obstack */
symtab->dirname = (char *)
obstack_alloc (&objfile->symbol_obstack,
obstack_alloc (&objfile->objfile_obstack,
strlen (subfile->dirname) + 1);
strcpy (symtab->dirname, subfile->dirname);
}
@ -969,7 +982,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
symtab->dirname = NULL;
}
symtab->free_code = free_linetable;
symtab->free_ptr = NULL;
symtab->free_func = NULL;
/* Use whatever language we have been using for this
subfile, not the one that was deduced in allocate_symtab
@ -984,7 +997,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
{
symtab->debugformat = obsavestring (subfile->debugformat,
strlen (subfile->debugformat),
&objfile->symbol_obstack);
&objfile->objfile_obstack);
}
/* All symtabs for the main file and the subfiles share a
@ -1022,6 +1035,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
last_source_file = NULL;
current_subfile = NULL;
pending_macros = NULL;
return symtab;
}
@ -1033,7 +1047,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
struct context_stack *
push_context (int desc, CORE_ADDR valu)
{
register struct context_stack *new;
struct context_stack *new;
if (context_stack_depth == context_stack_size)
{
@ -1056,6 +1070,17 @@ push_context (int desc, CORE_ADDR valu)
return new;
}
/* Pop a context block. Returns the address of the context block just
popped. */
struct context_stack *
pop_context (void)
{
gdb_assert (context_stack_depth > 0);
return (&context_stack[--context_stack_depth]);
}
/* Compute a small integer hash code for the given name. */
@ -1084,7 +1109,7 @@ record_debugformat (char *format)
void
merge_symbol_lists (struct pending **srclist, struct pending **targetlist)
{
register int i;
int i;
if (!srclist || !*srclist)
return;
@ -1112,6 +1137,7 @@ buildsym_init (void)
file_symbols = NULL;
global_symbols = NULL;
pending_blocks = NULL;
pending_macros = NULL;
}
/* Initialize anything that needs initializing when a completely new

View file

@ -1,6 +1,6 @@
/* Build symbol tables in GDB's internal format.
Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1995, 1996,
1997, 1998, 1999, 2000 Free Software Foundation, Inc.
1997, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
@ -22,6 +22,9 @@
#if !defined (BUILDSYM_H)
#define BUILDSYM_H 1
struct objfile;
struct symbol;
/* This module provides definitions used for creating and adding to
the symbol table. These routines are called from various symbol-
file-reading routines.
@ -34,6 +37,8 @@
normally extern, but which get defined in a single module using
this technique. */
struct block;
#ifndef EXTERN
#define EXTERN extern
#endif
@ -83,16 +88,6 @@ EXTERN unsigned char processing_gcc_compilation;
EXTERN unsigned char processing_acc_compilation;
/* elz: added this flag to know when a block is compiled with HP
compilers (cc, aCC). This is necessary because of the macro
COERCE_FLOAT_TO_DOUBLE defined in tm_hppa.h, which causes a
coercion of float to double to always occur in parameter passing
for a function called by gdb (see the function value_arg_coerce in
valops.c). This is necessary only if the target was compiled with
gcc, not with HP compilers or with g++ */
EXTERN unsigned char processing_hp_compilation;
/* Count symbols as they are processed, for error messages. */
EXTERN unsigned int symnum;
@ -173,11 +168,8 @@ EXTERN int context_stack_depth;
EXTERN int context_stack_size;
/* Macro "function" for popping contexts from the stack. Pushing is
done by a real function, push_context. This returns a pointer to a
struct context_stack. */
#define pop_context() (&context_stack[--context_stack_depth]);
/* Non-zero if the context stack is empty. */
#define outermost_context_p() (context_stack_depth == 0)
/* Nonzero if within a function (so symbols should be local, if
nothing says specifically). */
@ -246,7 +238,7 @@ extern void finish_block (struct symbol *symbol,
CORE_ADDR start, CORE_ADDR end,
struct objfile *objfile);
extern void really_free_pendings (PTR dummy);
extern void really_free_pendings (void *dummy);
extern void start_subfile (char *name, char *dirname);
@ -269,6 +261,8 @@ extern void buildsym_init (void);
extern struct context_stack *push_context (int desc, CORE_ADDR valu);
extern struct context_stack *pop_context (void);
extern void record_line (struct subfile *subfile, int line, CORE_ADDR pc);
extern void start_symtab (char *name, char *dirname, CORE_ADDR start_addr);
@ -277,12 +271,6 @@ extern int hashname (char *name);
extern void free_pending_blocks (void);
/* FIXME: Note that this is used only in buildsym.c and dstread.c,
which should be fixed to not need direct access to
make_blockvector. */
extern struct blockvector *make_blockvector (struct objfile *objfile);
/* FIXME: Note that this is used only in buildsym.c and dstread.c,
which should be fixed to not need direct access to
record_pending_block. */
@ -296,6 +284,10 @@ extern void record_debugformat (char *format);
extern void merge_symbol_lists (struct pending **srclist,
struct pending **targetlist);
/* The macro table for the compilation unit whose symbols we're
currently reading. All the symtabs for this CU will point to this. */
EXTERN struct macro_table *pending_macros;
#undef EXTERN
#endif /* defined (BUILDSYM_H) */

3443
contrib/gdb/gdb/c-exp.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* YACC parser for C expressions, for GDB.
Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
1998, 1999, 2000
1998, 1999, 2000, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@ -49,6 +49,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h" /* Required by objfiles.h. */
#include "symfile.h" /* Required by objfiles.h. */
#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
#include "charset.h"
#include "block.h"
#include "cp-support.h"
/* Flag indicating we're dealing with HP-compiled objects */
extern int hp_som_som_object_present;
@ -89,6 +92,8 @@ extern int hp_som_som_object_present;
#define yylloc c_lloc
#define yyreds c_reds /* With YYDEBUG defined */
#define yytoks c_toks /* With YYDEBUG defined */
#define yyname c_name /* With YYDEBUG defined */
#define yyrule c_rule /* With YYDEBUG defined */
#define yylhs c_yylhs
#define yylen c_yylen
#define yydefred c_yydefred
@ -100,9 +105,11 @@ extern int hp_som_som_object_present;
#define yycheck c_yycheck
#ifndef YYDEBUG
#define YYDEBUG 0 /* Default to no yydebug support */
#define YYDEBUG 1 /* Default to yydebug support */
#endif
#define YYFPRINTF parser_fprintf
int yyparse (void);
static int yylex (void);
@ -147,7 +154,7 @@ static int parse_number (char *, int, int, YYSTYPE *);
%type <voidval> exp exp1 type_exp start variable qualified_name lcurly
%type <lval> rcurly
%type <tval> type typebase
%type <tval> type typebase qualified_type
%type <tvec> nonempty_typelist
/* %type <bval> block */
@ -194,7 +201,6 @@ static int parse_number (char *, int, int, YYSTYPE *);
%token <opcode> ASSIGN_MODIFY
/* C++ */
%token THIS
%token TRUEKEYWORD
%token FALSEKEYWORD
@ -243,9 +249,11 @@ exp1 : exp
/* Expressions, not including the comma operator. */
exp : '*' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_IND); }
;
exp : '&' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_ADDR); }
;
exp : '-' exp %prec UNARY
{ write_exp_elt_opcode (UNOP_NEG); }
@ -527,11 +535,6 @@ exp : STRING
;
/* C++. */
exp : THIS
{ write_exp_elt_opcode (OP_THIS);
write_exp_elt_opcode (OP_THIS); }
;
exp : TRUEKEYWORD
{ write_exp_elt_opcode (OP_LONG);
write_exp_elt_type (builtin_type_bool);
@ -565,7 +568,7 @@ block : BLOCKNAME
block : block COLONCOLON name
{ struct symbol *tem
= lookup_symbol (copy_name ($3), $1,
VAR_NAMESPACE, (int *) NULL,
VAR_DOMAIN, (int *) NULL,
(struct symtab **) NULL);
if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
error ("No function \"%s\" in specified context.",
@ -576,7 +579,7 @@ block : block COLONCOLON name
variable: block COLONCOLON name
{ struct symbol *sym;
sym = lookup_symbol (copy_name ($3), $1,
VAR_NAMESPACE, (int *) NULL,
VAR_DOMAIN, (int *) NULL,
(struct symtab **) NULL);
if (sym == 0)
error ("No symbol \"%s\" in specified context.",
@ -593,7 +596,8 @@ qualified_name: typebase COLONCOLON name
{
struct type *type = $1;
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION)
&& TYPE_CODE (type) != TYPE_CODE_UNION
&& TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
error ("`%s' is not defined as an aggregate type.",
TYPE_NAME (type));
@ -607,7 +611,8 @@ qualified_name: typebase COLONCOLON name
struct type *type = $1;
struct stoken tmp_token;
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION)
&& TYPE_CODE (type) != TYPE_CODE_UNION
&& TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
error ("`%s' is not defined as an aggregate type.",
TYPE_NAME (type));
@ -635,7 +640,7 @@ variable: qualified_name
sym =
lookup_symbol (name, (const struct block *) NULL,
VAR_NAMESPACE, (int *) NULL,
VAR_DOMAIN, (int *) NULL,
(struct symtab **) NULL);
if (sym)
{
@ -699,7 +704,7 @@ variable: name_not_typename
else
{
struct minimal_symbol *msymbol;
register char *arg = copy_name ($1.stoken);
char *arg = copy_name ($1.stoken);
msymbol =
lookup_minimal_symbol (arg, NULL, NULL);
@ -780,7 +785,7 @@ array_mod: '[' ']'
func_mod: '(' ')'
{ $$ = 0; }
| '(' nonempty_typelist ')'
{ free ((PTR)$2); $$ = 0; }
{ free ($2); $$ = 0; }
;
/* We used to try to recognize more pointer to member types here, but
@ -807,24 +812,50 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */
{ $$ = builtin_type_short; }
| LONG INT_KEYWORD
{ $$ = builtin_type_long; }
| LONG SIGNED_KEYWORD INT_KEYWORD
{ $$ = builtin_type_long; }
| LONG SIGNED_KEYWORD
{ $$ = builtin_type_long; }
| SIGNED_KEYWORD LONG INT_KEYWORD
{ $$ = builtin_type_long; }
| UNSIGNED LONG INT_KEYWORD
{ $$ = builtin_type_unsigned_long; }
| LONG UNSIGNED INT_KEYWORD
{ $$ = builtin_type_unsigned_long; }
| LONG UNSIGNED
{ $$ = builtin_type_unsigned_long; }
| LONG LONG
{ $$ = builtin_type_long_long; }
| LONG LONG INT_KEYWORD
{ $$ = builtin_type_long_long; }
| LONG LONG SIGNED_KEYWORD INT_KEYWORD
{ $$ = builtin_type_long_long; }
| LONG LONG SIGNED_KEYWORD
{ $$ = builtin_type_long_long; }
| SIGNED_KEYWORD LONG LONG
{ $$ = builtin_type_long_long; }
| SIGNED_KEYWORD LONG LONG INT_KEYWORD
{ $$ = builtin_type_long_long; }
| UNSIGNED LONG LONG
{ $$ = builtin_type_unsigned_long_long; }
| UNSIGNED LONG LONG INT_KEYWORD
{ $$ = builtin_type_unsigned_long_long; }
| SIGNED_KEYWORD LONG LONG
{ $$ = lookup_signed_typename ("long long"); }
| SIGNED_KEYWORD LONG LONG INT_KEYWORD
{ $$ = lookup_signed_typename ("long long"); }
| LONG LONG UNSIGNED
{ $$ = builtin_type_unsigned_long_long; }
| LONG LONG UNSIGNED INT_KEYWORD
{ $$ = builtin_type_unsigned_long_long; }
| SHORT INT_KEYWORD
{ $$ = builtin_type_short; }
| SHORT SIGNED_KEYWORD INT_KEYWORD
{ $$ = builtin_type_short; }
| SHORT SIGNED_KEYWORD
{ $$ = builtin_type_short; }
| UNSIGNED SHORT INT_KEYWORD
{ $$ = builtin_type_unsigned_short; }
| SHORT UNSIGNED
{ $$ = builtin_type_unsigned_short; }
| SHORT UNSIGNED INT_KEYWORD
{ $$ = builtin_type_unsigned_short; }
| DOUBLE_KEYWORD
{ $$ = builtin_type_double; }
| LONG DOUBLE_KEYWORD
@ -860,6 +891,77 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */
{ $$ = follow_types ($2); }
| typebase const_or_volatile_or_space_identifier_noopt
{ $$ = follow_types ($1); }
| qualified_type
;
/* FIXME: carlton/2003-09-25: This next bit leads to lots of
reduce-reduce conflicts, because the parser doesn't know whether or
not to use qualified_name or qualified_type: the rules are
identical. If the parser is parsing 'A::B::x', then, when it sees
the second '::', it knows that the expression to the left of it has
to be a type, so it uses qualified_type. But if it is parsing just
'A::B', then it doesn't have any way of knowing which rule to use,
so there's a reduce-reduce conflict; it picks qualified_name, since
that occurs earlier in this file than qualified_type.
There's no good way to fix this with the grammar as it stands; as
far as I can tell, some of the problems arise from ambiguities that
GDB introduces ('start' can be either an expression or a type), but
some of it is inherent to the nature of C++ (you want to treat the
input "(FOO)" fairly differently depending on whether FOO is an
expression or a type, and if FOO is a complex expression, this can
be hard to determine at the right time). Fortunately, it works
pretty well in most cases. For example, if you do 'ptype A::B',
where A::B is a nested type, then the parser will mistakenly
misidentify it as an expression; but evaluate_subexp will get
called with 'noside' set to EVAL_AVOID_SIDE_EFFECTS, and everything
will work out anyways. But there are situations where the parser
will get confused: the most common one that I've run into is when
you want to do
print *((A::B *) x)"
where the parser doesn't realize that A::B has to be a type until
it hits the first right paren, at which point it's too late. (The
workaround is to type "print *(('A::B' *) x)" instead.) (And
another solution is to fix our symbol-handling code so that the
user never wants to type something like that in the first place,
because we get all the types right without the user's help!)
Perhaps we could fix this by making the lexer smarter. Some of
this functionality used to be in the lexer, but in a way that
worked even less well than the current solution: that attempt
involved having the parser sometimes handle '::' and having the
lexer sometimes handle it, and without a clear division of
responsibility, it quickly degenerated into a big mess. Probably
the eventual correct solution will give more of a role to the lexer
(ideally via code that is shared between the lexer and
decode_line_1), but I'm not holding my breath waiting for somebody
to get around to cleaning this up... */
qualified_type: typebase COLONCOLON name
{
struct type *type = $1;
struct type *new_type;
char *ncopy = alloca ($3.length + 1);
memcpy (ncopy, $3.ptr, $3.length);
ncopy[$3.length] = '\0';
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION
&& TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
error ("`%s' is not defined as an aggregate type.",
TYPE_NAME (type));
new_type = cp_lookup_nested_type (type, ncopy,
expression_context_block);
if (new_type == NULL)
error ("No type \"%s\" within class or namespace \"%s\".",
ncopy, TYPE_NAME (type));
$$ = new_type;
}
;
typename: TYPENAME
@ -942,20 +1044,20 @@ name_not_typename : NAME
static int
parse_number (p, len, parsed_float, putithere)
register char *p;
register int len;
char *p;
int len;
int parsed_float;
YYSTYPE *putithere;
{
/* FIXME: Shouldn't these be unsigned? We don't deal with negative values
here, and we do kind of silly things like cast to unsigned. */
register LONGEST n = 0;
register LONGEST prevn = 0;
LONGEST n = 0;
LONGEST prevn = 0;
ULONGEST un;
register int i = 0;
register int c;
register int base = input_radix;
int i = 0;
int c;
int base = input_radix;
int unsigned_p = 0;
/* Number of "L" suffixes encountered. */
@ -1218,12 +1320,24 @@ yylex ()
retry:
/* Check if this is a macro invocation that we need to expand. */
if (! scanning_macro_expansion ())
{
char *expanded = macro_expand_next (&lexptr,
expression_macro_lookup_func,
expression_macro_lookup_baton);
if (expanded)
scan_macro_expansion (expanded);
}
prev_lexptr = lexptr;
unquoted_expr = 1;
tokstart = lexptr;
/* See if it is a special token of length 3. */
for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
if (STREQN (tokstart, tokentab3[i].operator, 3))
if (strncmp (tokstart, tokentab3[i].operator, 3) == 0)
{
lexptr += 3;
yylval.opcode = tokentab3[i].opcode;
@ -1232,7 +1346,7 @@ yylex ()
/* See if it is a special token of length 2. */
for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
if (STREQN (tokstart, tokentab2[i].operator, 2))
if (strncmp (tokstart, tokentab2[i].operator, 2) == 0)
{
lexptr += 2;
yylval.opcode = tokentab2[i].opcode;
@ -1242,7 +1356,17 @@ yylex ()
switch (c = *tokstart)
{
case 0:
return 0;
/* If we were just scanning the result of a macro expansion,
then we need to resume scanning the original text.
Otherwise, we were already scanning the original text, and
we're really done. */
if (scanning_macro_expansion ())
{
finished_macro_expansion ();
goto retry;
}
else
return 0;
case ' ':
case '\t':
@ -1260,6 +1384,15 @@ yylex ()
c = parse_escape (&lexptr);
else if (c == '\'')
error ("Empty character constant.");
else if (! host_char_to_target (c, &c))
{
int toklen = lexptr - tokstart + 1;
char *tok = alloca (toklen + 1);
memcpy (tok, tokstart, toklen);
tok[toklen] = '\0';
error ("There is no character corresponding to %s in the target "
"character set `%s'.", tok, target_charset ());
}
yylval.typed_val_int.val = c;
yylval.typed_val_int.type = builtin_type_char;
@ -1295,7 +1428,9 @@ yylex ()
return c;
case ',':
if (comma_terminates && paren_depth == 0)
if (comma_terminates
&& paren_depth == 0
&& ! scanning_macro_expansion ())
return 0;
lexptr++;
return c;
@ -1319,7 +1454,7 @@ yylex ()
{
/* It's a number. */
int got_dot = 0, got_e = 0, toktype;
register char *p = tokstart;
char *p = tokstart;
int hex = input_radix > 10;
if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
@ -1408,6 +1543,8 @@ yylex ()
tempbufindex = 0;
do {
char *char_start_pos = tokptr;
/* Grow the static temp buffer if necessary, including allocating
the first one on demand. */
if (tempbufindex + 1 >= tempbufsize)
@ -1430,7 +1567,19 @@ yylex ()
tempbuf[tempbufindex++] = c;
break;
default:
tempbuf[tempbufindex++] = *tokptr++;
c = *tokptr++;
if (! host_char_to_target (c, &c))
{
int len = tokptr - char_start_pos;
char *copy = alloca (len + 1);
memcpy (copy, char_start_pos, len);
copy[len] = '\0';
error ("There is no character corresponding to `%s' "
"in the target character set `%s'.",
copy, target_charset ());
}
tempbuf[tempbufindex++] = c;
break;
}
} while ((*tokptr != '"') && (*tokptr != '\0'));
@ -1474,9 +1623,13 @@ yylex ()
c = tokstart[++namelen];
}
/* The token "if" terminates the expression and is NOT
removed from the input stream. */
if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
/* The token "if" terminates the expression and is NOT removed from
the input stream. It doesn't count if it appears in the
expansion of a macro. */
if (namelen == 2
&& tokstart[0] == 'i'
&& tokstart[1] == 'f'
&& ! scanning_macro_expansion ())
{
return 0;
}
@ -1489,63 +1642,52 @@ yylex ()
switch (namelen)
{
case 8:
if (STREQN (tokstart, "unsigned", 8))
if (strncmp (tokstart, "unsigned", 8) == 0)
return UNSIGNED;
if (current_language->la_language == language_cplus
&& STREQN (tokstart, "template", 8))
&& strncmp (tokstart, "template", 8) == 0)
return TEMPLATE;
if (STREQN (tokstart, "volatile", 8))
if (strncmp (tokstart, "volatile", 8) == 0)
return VOLATILE_KEYWORD;
break;
case 6:
if (STREQN (tokstart, "struct", 6))
if (strncmp (tokstart, "struct", 6) == 0)
return STRUCT;
if (STREQN (tokstart, "signed", 6))
if (strncmp (tokstart, "signed", 6) == 0)
return SIGNED_KEYWORD;
if (STREQN (tokstart, "sizeof", 6))
if (strncmp (tokstart, "sizeof", 6) == 0)
return SIZEOF;
if (STREQN (tokstart, "double", 6))
if (strncmp (tokstart, "double", 6) == 0)
return DOUBLE_KEYWORD;
break;
case 5:
if (current_language->la_language == language_cplus)
{
if (STREQN (tokstart, "false", 5))
if (strncmp (tokstart, "false", 5) == 0)
return FALSEKEYWORD;
if (STREQN (tokstart, "class", 5))
if (strncmp (tokstart, "class", 5) == 0)
return CLASS;
}
if (STREQN (tokstart, "union", 5))
if (strncmp (tokstart, "union", 5) == 0)
return UNION;
if (STREQN (tokstart, "short", 5))
if (strncmp (tokstart, "short", 5) == 0)
return SHORT;
if (STREQN (tokstart, "const", 5))
if (strncmp (tokstart, "const", 5) == 0)
return CONST_KEYWORD;
break;
case 4:
if (STREQN (tokstart, "enum", 4))
if (strncmp (tokstart, "enum", 4) == 0)
return ENUM;
if (STREQN (tokstart, "long", 4))
if (strncmp (tokstart, "long", 4) == 0)
return LONG;
if (current_language->la_language == language_cplus)
{
if (STREQN (tokstart, "true", 4))
if (strncmp (tokstart, "true", 4) == 0)
return TRUEKEYWORD;
if (STREQN (tokstart, "this", 4))
{
static const char this_name[] =
{ CPLUS_MARKER, 't', 'h', 'i', 's', '\0' };
if (lookup_symbol (this_name, expression_context_block,
VAR_NAMESPACE, (int *) NULL,
(struct symtab **) NULL))
return THIS;
}
}
break;
case 3:
if (STREQN (tokstart, "int", 3))
if (strncmp (tokstart, "int", 3) == 0)
return INT_KEYWORD;
break;
default:
@ -1565,7 +1707,13 @@ yylex ()
string to get a reasonable class/namespace spec or a
fully-qualified name. This is a kludge to get around the
HP aCC compiler's generation of symbol names with embedded
colons for namespace and nested classes. */
colons for namespace and nested classes. */
/* NOTE: carlton/2003-09-24: I don't entirely understand the
HP-specific code, either here or in linespec. Having said that,
I suspect that we're actually moving towards their model: we want
symbols whose names are fully qualified, which matches the
description above. */
if (unquoted_expr)
{
/* Only do it if not inside single quotes */
@ -1591,7 +1739,7 @@ yylex ()
int hextype;
sym = lookup_symbol (tmp, expression_context_block,
VAR_NAMESPACE,
VAR_DOMAIN,
current_language->la_language == language_cplus
? &is_a_field_of_this : (int *) NULL,
(struct symtab **) NULL);
@ -1619,92 +1767,10 @@ yylex ()
if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
{
#if 1
/* Despite the following flaw, we need to keep this code enabled.
Because we can get called from check_stub_method, if we don't
handle nested types then it screws many operations in any
program which uses nested types. */
/* In "A::x", if x is a member function of A and there happens
to be a type (nested or not, since the stabs don't make that
distinction) named x, then this code incorrectly thinks we
are dealing with nested types rather than a member function. */
char *p;
char *namestart;
struct symbol *best_sym;
/* Look ahead to detect nested types. This probably should be
done in the grammar, but trying seemed to introduce a lot
of shift/reduce and reduce/reduce conflicts. It's possible
that it could be done, though. Or perhaps a non-grammar, but
less ad hoc, approach would work well. */
/* Since we do not currently have any way of distinguishing
a nested type from a non-nested one (the stabs don't tell
us whether a type is nested), we just ignore the
containing type. */
p = lexptr;
best_sym = sym;
while (1)
{
/* Skip whitespace. */
while (*p == ' ' || *p == '\t' || *p == '\n')
++p;
if (*p == ':' && p[1] == ':')
{
/* Skip the `::'. */
p += 2;
/* Skip whitespace. */
while (*p == ' ' || *p == '\t' || *p == '\n')
++p;
namestart = p;
while (*p == '_' || *p == '$' || (*p >= '0' && *p <= '9')
|| (*p >= 'a' && *p <= 'z')
|| (*p >= 'A' && *p <= 'Z'))
++p;
if (p != namestart)
{
struct symbol *cur_sym;
/* As big as the whole rest of the expression, which is
at least big enough. */
char *ncopy = alloca (strlen (tmp)+strlen (namestart)+3);
char *tmp1;
tmp1 = ncopy;
memcpy (tmp1, tmp, strlen (tmp));
tmp1 += strlen (tmp);
memcpy (tmp1, "::", 2);
tmp1 += 2;
memcpy (tmp1, namestart, p - namestart);
tmp1[p - namestart] = '\0';
cur_sym = lookup_symbol (ncopy, expression_context_block,
VAR_NAMESPACE, (int *) NULL,
(struct symtab **) NULL);
if (cur_sym)
{
if (SYMBOL_CLASS (cur_sym) == LOC_TYPEDEF)
{
best_sym = cur_sym;
lexptr = p;
}
else
break;
}
else
break;
}
else
break;
}
else
break;
}
yylval.tsym.type = SYMBOL_TYPE (best_sym);
#else /* not 0 */
/* NOTE: carlton/2003-09-25: There used to be code here to
handle nested types. It didn't work very well. See the
comment before qualified_type for more info. */
yylval.tsym.type = SYMBOL_TYPE (sym);
#endif /* not 0 */
return TYPENAME;
}
if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0)
@ -1738,5 +1804,8 @@ void
yyerror (msg)
char *msg;
{
if (prev_lexptr)
lexptr = prev_lexptr;
error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
}

View file

@ -1,5 +1,5 @@
/* C language support routines for GDB, the GNU debugger.
Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002
Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@ -27,6 +27,12 @@
#include "language.h"
#include "c-lang.h"
#include "valprint.h"
#include "macroscope.h"
#include "gdb_assert.h"
#include "charset.h"
#include "gdb_string.h"
#include "demangle.h"
#include "cp-support.h"
extern void _initialize_c_language (void);
static void c_emit_char (int c, struct ui_file * stream, int quoter);
@ -36,54 +42,32 @@ static void c_emit_char (int c, struct ui_file * stream, int quoter);
characters and strings is language specific. */
static void
c_emit_char (register int c, struct ui_file *stream, int quoter)
c_emit_char (int c, struct ui_file *stream, int quoter)
{
const char *escape;
int host_char;
c &= 0xFF; /* Avoid sign bit follies */
if (PRINT_LITERAL_FORM (c))
escape = c_target_char_has_backslash_escape (c);
if (escape)
{
if (c == '\\' || c == quoter)
{
fputs_filtered ("\\", stream);
}
fprintf_filtered (stream, "%c", c);
if (quoter == '"' && strcmp (escape, "0") == 0)
/* Print nulls embedded in double quoted strings as \000 to
prevent ambiguity. */
fprintf_filtered (stream, "\\000");
else
fprintf_filtered (stream, "\\%s", escape);
}
else if (target_char_to_host (c, &host_char)
&& host_char_print_literally (host_char))
{
if (host_char == '\\' || host_char == quoter)
fputs_filtered ("\\", stream);
fprintf_filtered (stream, "%c", host_char);
}
else
{
switch (c)
{
case '\n':
fputs_filtered ("\\n", stream);
break;
case '\b':
fputs_filtered ("\\b", stream);
break;
case '\t':
fputs_filtered ("\\t", stream);
break;
case '\f':
fputs_filtered ("\\f", stream);
break;
case '\r':
fputs_filtered ("\\r", stream);
break;
case '\013':
fputs_filtered ("\\v", stream);
break;
case '\033':
fputs_filtered ("\\e", stream);
break;
case '\007':
fputs_filtered ("\\a", stream);
break;
case '\0':
fputs_filtered ("\\0", stream);
break;
default:
fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
break;
}
}
fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
}
void
@ -104,11 +88,10 @@ void
c_printstr (struct ui_file *stream, char *string, unsigned int length,
int width, int force_ellipses)
{
register unsigned int i;
unsigned int i;
unsigned int things_printed = 0;
int in_quotes = 0;
int need_comma = 0;
extern int inspect_it;
/* If the string was not truncated due to `set print elements', and
the last byte of it is a null, we don't print that, in traditional C
@ -224,7 +207,7 @@ c_printstr (struct ui_file *stream, char *string, unsigned int length,
struct type *
c_create_fundamental_type (struct objfile *objfile, int typeid)
{
register struct type *type = NULL;
struct type *type = NULL;
switch (typeid)
{
@ -338,6 +321,30 @@ c_create_fundamental_type (struct objfile *objfile, int typeid)
TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
0, "long double", objfile);
break;
case FT_COMPLEX:
type = init_type (TYPE_CODE_FLT,
2 * TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
0, "complex float", objfile);
TYPE_TARGET_TYPE (type)
= init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
0, "float", objfile);
break;
case FT_DBL_PREC_COMPLEX:
type = init_type (TYPE_CODE_FLT,
2 * TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
0, "complex double", objfile);
TYPE_TARGET_TYPE (type)
= init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
0, "double", objfile);
break;
case FT_EXT_PREC_COMPLEX:
type = init_type (TYPE_CODE_FLT,
2 * TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
0, "complex long double", objfile);
TYPE_TARGET_TYPE (type)
= init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
0, "long double", objfile);
break;
case FT_TEMPLATE_ARG:
type = init_type (TYPE_CODE_TEMPLATE_ARG,
0,
@ -347,7 +354,128 @@ c_create_fundamental_type (struct objfile *objfile, int typeid)
return (type);
}
/* Preprocessing and parsing C and C++ expressions. */
/* When we find that lexptr (the global var defined in parse.c) is
pointing at a macro invocation, we expand the invocation, and call
scan_macro_expansion to save the old lexptr here and point lexptr
into the expanded text. When we reach the end of that, we call
end_macro_expansion to pop back to the value we saved here. The
macro expansion code promises to return only fully-expanded text,
so we don't need to "push" more than one level.
This is disgusting, of course. It would be cleaner to do all macro
expansion beforehand, and then hand that to lexptr. But we don't
really know where the expression ends. Remember, in a command like
(gdb) break *ADDRESS if CONDITION
we evaluate ADDRESS in the scope of the current frame, but we
evaluate CONDITION in the scope of the breakpoint's location. So
it's simply wrong to try to macro-expand the whole thing at once. */
static char *macro_original_text;
static char *macro_expanded_text;
void
scan_macro_expansion (char *expansion)
{
/* We'd better not be trying to push the stack twice. */
gdb_assert (! macro_original_text);
gdb_assert (! macro_expanded_text);
/* Save the old lexptr value, so we can return to it when we're done
parsing the expanded text. */
macro_original_text = lexptr;
lexptr = expansion;
/* Save the expanded text, so we can free it when we're finished. */
macro_expanded_text = expansion;
}
int
scanning_macro_expansion (void)
{
return macro_original_text != 0;
}
void
finished_macro_expansion (void)
{
/* There'd better be something to pop back to, and we better have
saved a pointer to the start of the expanded text. */
gdb_assert (macro_original_text);
gdb_assert (macro_expanded_text);
/* Pop back to the original text. */
lexptr = macro_original_text;
macro_original_text = 0;
/* Free the expanded text. */
xfree (macro_expanded_text);
macro_expanded_text = 0;
}
static void
scan_macro_cleanup (void *dummy)
{
if (macro_original_text)
finished_macro_expansion ();
}
/* We set these global variables before calling c_parse, to tell it
how it to find macro definitions for the expression at hand. */
macro_lookup_ftype *expression_macro_lookup_func;
void *expression_macro_lookup_baton;
static struct macro_definition *
null_macro_lookup (const char *name, void *baton)
{
return 0;
}
static int
c_preprocess_and_parse (void)
{
/* Set up a lookup function for the macro expander. */
struct macro_scope *scope = 0;
struct cleanup *back_to = make_cleanup (free_current_contents, &scope);
if (expression_context_block)
scope = sal_macro_scope (find_pc_line (expression_context_pc, 0));
else
scope = default_macro_scope ();
if (scope)
{
expression_macro_lookup_func = standard_macro_lookup;
expression_macro_lookup_baton = (void *) scope;
}
else
{
expression_macro_lookup_func = null_macro_lookup;
expression_macro_lookup_baton = 0;
}
gdb_assert (! macro_original_text);
make_cleanup (scan_macro_cleanup, 0);
{
int result = c_parse ();
do_cleanups (back_to);
return result;
}
}
/* Table mapping opcodes into strings for printing operators
and precedences of the operators. */
@ -415,9 +543,9 @@ const struct language_defn c_language_defn =
range_check_off,
type_check_off,
case_sensitive_on,
c_parse,
&exp_descriptor_standard,
c_preprocess_and_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
c_printstr, /* Function to print string constant */
c_emit_char, /* Print a single char */
@ -425,6 +553,11 @@ const struct language_defn c_language_defn =
c_print_type, /* Print a type using appropriate syntax */
c_val_print, /* Print a value using appropriate syntax */
c_value_print, /* Print a top-level value */
NULL, /* Language specific skip_trampoline */
NULL, /* value_of_this */
basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
basic_lookup_transparent_type,/* lookup_transparent_type */
NULL, /* Language specific symbol demangler */
{"", "", "", ""}, /* Binary format info */
{"0%lo", "0", "o", ""}, /* Octal format info */
{"%ld", "", "d", ""}, /* Decimal format info */
@ -433,6 +566,7 @@ const struct language_defn c_language_defn =
1, /* c-style arrays */
0, /* String lower bound */
&builtin_type_char, /* Type of string elements */
default_word_break_characters,
LANG_MAGIC
};
@ -467,9 +601,9 @@ const struct language_defn cplus_language_defn =
range_check_off,
type_check_off,
case_sensitive_on,
c_parse,
&exp_descriptor_standard,
c_preprocess_and_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
c_printstr, /* Function to print string constant */
c_emit_char, /* Print a single char */
@ -477,6 +611,11 @@ const struct language_defn cplus_language_defn =
c_print_type, /* Print a type using appropriate syntax */
c_val_print, /* Print a value using appropriate syntax */
c_value_print, /* Print a top-level value */
NULL, /* Language specific skip_trampoline */
value_of_this, /* value_of_this */
cp_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
cp_lookup_transparent_type, /* lookup_transparent_type */
cplus_demangle, /* Language specific symbol demangler */
{"", "", "", ""}, /* Binary format info */
{"0%lo", "0", "o", ""}, /* Octal format info */
{"%ld", "", "d", ""}, /* Decimal format info */
@ -485,6 +624,7 @@ const struct language_defn cplus_language_defn =
1, /* c-style arrays */
0, /* String lower bound */
&builtin_type_char, /* Type of string elements */
default_word_break_characters,
LANG_MAGIC
};
@ -496,9 +636,9 @@ const struct language_defn asm_language_defn =
range_check_off,
type_check_off,
case_sensitive_on,
c_parse,
&exp_descriptor_standard,
c_preprocess_and_parse,
c_error,
evaluate_subexp_standard,
c_printchar, /* Print a character constant */
c_printstr, /* Function to print string constant */
c_emit_char, /* Print a single char */
@ -506,6 +646,11 @@ const struct language_defn asm_language_defn =
c_print_type, /* Print a type using appropriate syntax */
c_val_print, /* Print a value using appropriate syntax */
c_value_print, /* Print a top-level value */
NULL, /* Language specific skip_trampoline */
NULL, /* value_of_this */
basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
basic_lookup_transparent_type,/* lookup_transparent_type */
NULL, /* Language specific symbol demangler */
{"", "", "", ""}, /* Binary format info */
{"0%lo", "0", "o", ""}, /* Octal format info */
{"%ld", "", "d", ""}, /* Decimal format info */
@ -514,6 +659,47 @@ const struct language_defn asm_language_defn =
1, /* c-style arrays */
0, /* String lower bound */
&builtin_type_char, /* Type of string elements */
default_word_break_characters,
LANG_MAGIC
};
/* The following language_defn does not represent a real language.
It just provides a minimal support a-la-C that should allow users
to do some simple operations when debugging applications that use
a language currently not supported by GDB. */
const struct language_defn minimal_language_defn =
{
"minimal", /* Language name */
language_minimal,
c_builtin_types,
range_check_off,
type_check_off,
case_sensitive_on,
&exp_descriptor_standard,
c_preprocess_and_parse,
c_error,
c_printchar, /* Print a character constant */
c_printstr, /* Function to print string constant */
c_emit_char, /* Print a single char */
c_create_fundamental_type, /* Create fundamental type in this language */
c_print_type, /* Print a type using appropriate syntax */
c_val_print, /* Print a value using appropriate syntax */
c_value_print, /* Print a top-level value */
NULL, /* Language specific skip_trampoline */
NULL, /* value_of_this */
basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
basic_lookup_transparent_type,/* lookup_transparent_type */
NULL, /* Language specific symbol demangler */
{"", "", "", ""}, /* Binary format info */
{"0%lo", "0", "o", ""}, /* Octal format info */
{"%ld", "", "d", ""}, /* Decimal format info */
{"0x%lx", "0x", "x", ""}, /* Hex format info */
c_op_print_tab, /* expression operators for printing */
1, /* c-style arrays */
0, /* String lower bound */
&builtin_type_char, /* Type of string elements */
default_word_break_characters,
LANG_MAGIC
};
@ -523,4 +709,5 @@ _initialize_c_language (void)
add_language (&c_language_defn);
add_language (&cplus_language_defn);
add_language (&asm_language_defn);
add_language (&minimal_language_defn);
}

View file

@ -23,7 +23,10 @@
#if !defined (C_LANG_H)
#define C_LANG_H 1
struct ui_file;
#include "value.h"
#include "macroexp.h"
extern int c_parse (void); /* Defined in c-exp.y */
@ -49,6 +52,13 @@ extern void c_printstr (struct ui_file * stream, char *string,
unsigned int length, int width,
int force_ellipses);
extern void scan_macro_expansion (char *expansion);
extern int scanning_macro_expansion (void);
extern void finished_macro_expansion (void);
extern macro_lookup_ftype *expression_macro_lookup_func;
extern void *expression_macro_lookup_baton;
extern struct type *c_create_fundamental_type (struct objfile *, int);
extern struct type **const (c_builtin_types[]);
@ -57,9 +67,6 @@ extern struct type **const (c_builtin_types[]);
extern void c_type_print_base (struct type *, struct ui_file *, int, int);
extern void c_type_print_varspec_prefix (struct type *, struct ui_file *,
int, int);
/* These are in cp-valprint.c */
extern int vtblprint; /* Controls printing of vtbl's */

View file

@ -1,6 +1,6 @@
/* Support for printing C and C++ types for GDB, the GNU debugger.
Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
1999, 2000, 2001, 2002
1999, 2000, 2001, 2002, 2003
Free Software Foundation, Inc.
This file is part of GDB.
@ -21,7 +21,7 @@
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "obstack.h"
#include "gdb_obstack.h"
#include "bfd.h" /* Binary File Description */
#include "symtab.h"
#include "gdbtypes.h"
@ -41,7 +41,7 @@
/* Flag indicating target was compiled by HP compiler */
extern int hp_som_som_object_present;
static void cp_type_print_method_args (struct type ** args, char *prefix,
static void cp_type_print_method_args (struct type *mtype, char *prefix,
char *varstring, int staticp,
struct ui_file *stream);
@ -49,8 +49,8 @@ static void c_type_print_args (struct type *, struct ui_file *);
static void cp_type_print_derivation_info (struct ui_file *, struct type *);
void c_type_print_varspec_prefix (struct type *, struct ui_file *, int,
int);
static void c_type_print_varspec_prefix (struct type *, struct ui_file *, int,
int, int);
/* Print "const", "volatile", or address space modifiers. */
static void c_type_print_modifier (struct type *, struct ui_file *,
@ -65,8 +65,9 @@ void
c_print_type (struct type *type, char *varstring, struct ui_file *stream,
int show, int level)
{
register enum type_code code;
enum type_code code;
int demangled_args;
int need_post_space;
if (show > 0)
CHECK_TYPEDEF (type);
@ -85,7 +86,8 @@ c_print_type (struct type *type, char *varstring, struct ui_file *stream,
|| code == TYPE_CODE_MEMBER
|| code == TYPE_CODE_REF)))
fputs_filtered (" ", stream);
c_type_print_varspec_prefix (type, stream, show, 0);
need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
c_type_print_varspec_prefix (type, stream, show, 0, need_post_space);
if (varstring != NULL)
{
@ -147,40 +149,40 @@ cp_type_print_derivation_info (struct ui_file *stream, struct type *type)
fputs_filtered (" ", stream);
}
}
/* Print the C++ method arguments ARGS to the file STREAM. */
static void
cp_type_print_method_args (struct type **args, char *prefix, char *varstring,
cp_type_print_method_args (struct type *mtype, char *prefix, char *varstring,
int staticp, struct ui_file *stream)
{
struct field *args = TYPE_FIELDS (mtype);
int nargs = TYPE_NFIELDS (mtype);
int varargs = TYPE_VARARGS (mtype);
int i;
fprintf_symbol_filtered (stream, prefix, language_cplus, DMGL_ANSI);
fprintf_symbol_filtered (stream, varstring, language_cplus, DMGL_ANSI);
fputs_filtered ("(", stream);
if (args && args[!staticp] && args[!staticp]->code != TYPE_CODE_VOID)
/* Skip the class variable. */
i = staticp ? 0 : 1;
if (nargs > i)
{
i = !staticp; /* skip the class variable */
while (1)
while (i < nargs)
{
type_print (args[i++], "", stream, 0);
if (!args[i])
{
fprintf_filtered (stream, " ...");
break;
}
else if (args[i]->code != TYPE_CODE_VOID)
{
fprintf_filtered (stream, ", ");
}
else
break;
type_print (args[i++].type, "", stream, 0);
if (i == nargs && varargs)
fprintf_filtered (stream, ", ...");
else if (i < nargs)
fprintf_filtered (stream, ", ");
}
}
else if (varargs)
fprintf_filtered (stream, "...");
else if (current_language->la_language == language_cplus)
{
fprintf_filtered (stream, "void");
}
fprintf_filtered (stream, "void");
fprintf_filtered (stream, ")");
}
@ -192,11 +194,15 @@ cp_type_print_method_args (struct type **args, char *prefix, char *varstring,
On outermost call, pass 0 for PASSED_A_PTR.
On outermost call, SHOW > 0 means should ignore
any typename for TYPE and show its details.
SHOW is always zero on recursive calls. */
SHOW is always zero on recursive calls.
NEED_POST_SPACE is non-zero when a space will be be needed
between a trailing qualifier and a field, variable, or function
name. */
void
c_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
int show, int passed_a_ptr)
int show, int passed_a_ptr, int need_post_space)
{
char *name;
if (type == 0)
@ -210,15 +216,15 @@ c_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 1, 1);
fprintf_filtered (stream, "*");
c_type_print_modifier (type, stream, 1, 0);
c_type_print_modifier (type, stream, 1, need_post_space);
break;
case TYPE_CODE_MEMBER:
if (passed_a_ptr)
fprintf_filtered (stream, "(");
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
fprintf_filtered (stream, " ");
name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
if (name)
@ -231,7 +237,7 @@ c_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
case TYPE_CODE_METHOD:
if (passed_a_ptr)
fprintf_filtered (stream, "(");
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
if (passed_a_ptr)
{
fprintf_filtered (stream, " ");
@ -241,23 +247,27 @@ c_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
break;
case TYPE_CODE_REF:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 1, 0);
fprintf_filtered (stream, "&");
c_type_print_modifier (type, stream, 1, 0);
c_type_print_modifier (type, stream, 1, need_post_space);
break;
case TYPE_CODE_FUNC:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
if (passed_a_ptr)
fprintf_filtered (stream, "(");
break;
case TYPE_CODE_ARRAY:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
if (passed_a_ptr)
fprintf_filtered (stream, "(");
break;
case TYPE_CODE_TYPEDEF:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
break;
case TYPE_CODE_UNDEF:
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
@ -273,8 +283,8 @@ c_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TYPEDEF:
case TYPE_CODE_TEMPLATE:
case TYPE_CODE_NAMESPACE:
/* These types need no prefix. They are listed here so that
gcc -Wall will reveal any types that haven't been handled. */
break;
@ -294,7 +304,7 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
int need_pre_space, int need_post_space)
{
int did_print_modifier = 0;
char *address_space_id;
const char *address_space_id;
/* We don't print `const' qualifiers for references --- since all
operators affect the thing referenced, not the reference itself,
@ -316,7 +326,7 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
did_print_modifier = 1;
}
address_space_id = address_space_int_to_name (TYPE_FLAGS (type));
address_space_id = address_space_int_to_name (TYPE_INSTANCE_FLAGS (type));
if (address_space_id)
{
if (did_print_modifier || need_pre_space)
@ -336,39 +346,31 @@ static void
c_type_print_args (struct type *type, struct ui_file *stream)
{
int i;
struct type **args;
struct field *args;
fprintf_filtered (stream, "(");
args = TYPE_ARG_TYPES (type);
args = TYPE_FIELDS (type);
if (args != NULL)
{
if (args[1] == NULL)
int i;
/* FIXME drow/2002-05-31: Always skips the first argument,
should we be checking for static members? */
for (i = 1; i < TYPE_NFIELDS (type); i++)
{
fprintf_filtered (stream, "...");
}
else if ((args[1]->code == TYPE_CODE_VOID) &&
(current_language->la_language == language_cplus))
{
fprintf_filtered (stream, "void");
}
else
{
for (i = 1;
args[i] != NULL && args[i]->code != TYPE_CODE_VOID;
i++)
c_print_type (args[i].type, "", stream, -1, 0);
if (i != TYPE_NFIELDS (type))
{
c_print_type (args[i], "", stream, -1, 0);
if (args[i + 1] == NULL)
{
fprintf_filtered (stream, "...");
}
else if (args[i + 1]->code != TYPE_CODE_VOID)
{
fprintf_filtered (stream, ",");
wrap_here (" ");
}
fprintf_filtered (stream, ",");
wrap_here (" ");
}
}
if (TYPE_VARARGS (type))
fprintf_filtered (stream, "...");
else if (i == 1
&& (current_language->la_language == language_cplus))
fprintf_filtered (stream, "void");
}
else if (current_language->la_language == language_cplus)
{
@ -545,19 +547,22 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
/ TYPE_LENGTH (TYPE_TARGET_TYPE (type))));
fprintf_filtered (stream, "]");
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
0, 0);
break;
case TYPE_CODE_MEMBER:
if (passed_a_ptr)
fprintf_filtered (stream, ")");
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
0, 0);
break;
case TYPE_CODE_METHOD:
if (passed_a_ptr)
fprintf_filtered (stream, ")");
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
0, 0);
if (passed_a_ptr)
{
c_type_print_args (type, stream);
@ -566,7 +571,8 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
case TYPE_CODE_PTR:
case TYPE_CODE_REF:
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1, 0);
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
1, 0);
break;
case TYPE_CODE_FUNC:
@ -594,7 +600,12 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
}
fprintf_filtered (stream, ")");
}
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
passed_a_ptr, 0);
break;
case TYPE_CODE_TYPEDEF:
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
passed_a_ptr, 0);
break;
@ -613,8 +624,8 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TYPEDEF:
case TYPE_CODE_TEMPLATE:
case TYPE_CODE_NAMESPACE:
/* These types do not need a suffix. They are listed so that
gcc -Wall will report types that may not have been considered. */
break;
@ -848,10 +859,11 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
QUIT;
/* Don't print out virtual function table. */
/* HP ANSI C++ case */
if (TYPE_HAS_VTABLE (type) && (STREQN (TYPE_FIELD_NAME (type, i), "__vfp", 5)))
if (TYPE_HAS_VTABLE (type)
&& (strncmp (TYPE_FIELD_NAME (type, i), "__vfp", 5) == 0))
continue;
/* Other compilers */
if (STREQN (TYPE_FIELD_NAME (type, i), "_vptr", 5)
if (strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5) == 0
&& is_cplus_marker ((TYPE_FIELD_NAME (type, i))[5]))
continue;
@ -933,7 +945,7 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i);
char *method_name = TYPE_FN_FIELDLIST_NAME (type, i);
char *name = type_name_no_tag (type);
int is_constructor = name && STREQ (method_name, name);
int is_constructor = name && strcmp (method_name, name) == 0;
for (j = 0; j < len2; j++)
{
char *physname = TYPE_FN_FIELD_PHYSNAME (f, j);
@ -1010,10 +1022,15 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
Let's try to reconstruct the function signature from
the symbol information */
if (!TYPE_FN_FIELD_STUB (f, j))
cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "",
method_name,
TYPE_FN_FIELD_STATIC_P (f, j),
stream);
{
int staticp = TYPE_FN_FIELD_STATIC_P (f, j);
struct type *mtype = TYPE_FN_FIELD_TYPE (f, j);
cp_type_print_method_args (mtype,
"",
method_name,
staticp,
stream);
}
else
fprintf_filtered (stream, "<badly mangled name '%s'>",
mangled_name);
@ -1168,6 +1185,11 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
}
break;
case TYPE_CODE_NAMESPACE:
fputs_filtered ("namespace ", stream);
fputs_filtered (TYPE_TAG_NAME (type), stream);
break;
default:
/* Handle types not explicitly handled by the other cases,
such as fundamental types. For these, just print whatever

View file

@ -1,7 +1,7 @@
/* Support for printing C values for GDB, the GNU debugger.
Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
1998, 1999, 2000, 2001
Free Software Foundation, Inc.
Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
1997, 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
This file is part of GDB.
@ -21,6 +21,7 @@
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdb_string.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "expression.h"
@ -29,6 +30,7 @@
#include "language.h"
#include "c-lang.h"
#include "cp-abi.h"
#include "target.h"
/* Print function pointer with inferior address ADDRESS onto stdio
@ -37,7 +39,9 @@
static void
print_function_pointer_address (CORE_ADDR address, struct ui_file *stream)
{
CORE_ADDR func_addr = CONVERT_FROM_FUNC_PTR_ADDR (address);
CORE_ADDR func_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
address,
&current_target);
/* If the function pointer is represented by a description, print the
address of the description. */
@ -69,7 +73,7 @@ c_val_print (struct type *type, char *valaddr, int embedded_offset,
CORE_ADDR address, struct ui_file *stream, int format,
int deref_ref, int recurse, enum val_prettyprint pretty)
{
register unsigned int i = 0; /* Number of characters printed */
unsigned int i = 0; /* Number of characters printed */
unsigned len;
struct type *elttype;
unsigned eltlen;
@ -204,7 +208,7 @@ c_val_print (struct type *type, char *valaddr, int embedded_offset,
(vt_address == SYMBOL_VALUE_ADDRESS (msymbol)))
{
fputs_filtered (" <", stream);
fputs_filtered (SYMBOL_SOURCE_NAME (msymbol), stream);
fputs_filtered (SYMBOL_PRINT_NAME (msymbol), stream);
fputs_filtered (">", stream);
}
if (vt_address && vtblprint)
@ -212,13 +216,12 @@ c_val_print (struct type *type, char *valaddr, int embedded_offset,
struct value *vt_val;
struct symbol *wsym = (struct symbol *) NULL;
struct type *wtype;
struct symtab *s;
struct block *block = (struct block *) NULL;
int is_this_fld;
if (msymbol != NULL)
wsym = lookup_symbol (SYMBOL_NAME (msymbol), block,
VAR_NAMESPACE, &is_this_fld, &s);
wsym = lookup_symbol (DEPRECATED_SYMBOL_NAME (msymbol), block,
VAR_DOMAIN, &is_this_fld, NULL);
if (wsym)
{
@ -514,7 +517,7 @@ c_value_print (struct value *val, struct ui_file *stream, int format,
if (TYPE_CODE (type) == TYPE_CODE_PTR &&
TYPE_NAME (type) == NULL &&
TYPE_NAME (TYPE_TARGET_TYPE (type)) != NULL &&
STREQ (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char"))
strcmp (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char") == 0)
{
/* Print nothing */
}
@ -592,7 +595,8 @@ c_value_print (struct value *val, struct ui_file *stream, int format,
/* Otherwise, we end up at the return outside this "if" */
}
return val_print (type, VALUE_CONTENTS_ALL (val), VALUE_EMBEDDED_OFFSET (val),
VALUE_ADDRESS (val),
return val_print (type, VALUE_CONTENTS_ALL (val),
VALUE_EMBEDDED_OFFSET (val),
VALUE_ADDRESS (val) + VALUE_OFFSET (val),
stream, format, 1, 0, pretty);
}

1277
contrib/gdb/gdb/charset.c Normal file

File diff suppressed because it is too large Load diff

109
contrib/gdb/gdb/charset.h Normal file
View file

@ -0,0 +1,109 @@
/* Character set conversion support for GDB.
Copyright 2001 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef CHARSET_H
#define CHARSET_H
/* If the target program uses a different character set than the host,
GDB has some support for translating between the two; GDB converts
characters and strings to the host character set before displaying
them, and converts characters and strings appearing in expressions
entered by the user to the target character set.
At the moment, GDB only supports single-byte, stateless character
sets. This includes the ISO-8859 family (ASCII extended with
accented characters, and (I think) Cyrillic, for European
languages), and the EBCDIC family (used on IBM's mainframes).
Unfortunately, it excludes many Asian scripts, the fixed- and
variable-width Unicode encodings, and other desireable things.
Patches are welcome! (For example, it would be nice if the Java
string support could simply get absorbed into some more general
multi-byte encoding support.)
Furthermore, GDB's code pretty much assumes that the host character
set is some superset of ASCII; there are plenty if ('0' + n)
expressions and the like.
When the `iconv' library routine supports a character set meeting
the requirements above, it's easy to plug an entry into GDB's table
that uses iconv to handle the details. */
/* Return the name of the current host/target character set. The
result is owned by the charset module; the caller should not free
it. */
const char *host_charset (void);
const char *target_charset (void);
/* In general, the set of C backslash escapes (\n, \f) is specific to
the character set. Not all character sets will have form feed
characters, for example.
The following functions allow GDB to parse and print control
characters in a character-set-independent way. They are both
language-specific (to C and C++) and character-set-specific.
Putting them here is a compromise. */
/* If the target character TARGET_CHAR have a backslash escape in the
C language (i.e., a character like 'n' or 't'), return the host
character string that should follow the backslash. Otherwise,
return zero.
When this function returns non-zero, the string it returns is
statically allocated; the caller is not responsible for freeing it. */
const char *c_target_char_has_backslash_escape (int target_char);
/* If the host character HOST_CHAR is a valid backslash escape in the
C language for the target character set, return non-zero, and set
*TARGET_CHAR to the target character the backslash escape represents.
Otherwise, return zero. */
int c_parse_backslash (int host_char, int *target_char);
/* Return non-zero if the host character HOST_CHAR can be printed
literally --- that is, if it can be readably printed as itself in a
character or string constant. Return zero if it should be printed
using some kind of numeric escape, like '\031' in C, '^(25)' in
Chill, or #25 in Pascal. */
int host_char_print_literally (int host_char);
/* If the host character HOST_CHAR has an equivalent in the target
character set, set *TARGET_CHAR to that equivalent, and return
non-zero. Otherwise, return zero. */
int host_char_to_target (int host_char, int *target_char);
/* If the target character TARGET_CHAR has an equivalent in the host
character set, set *HOST_CHAR to that equivalent, and return
non-zero. Otherwise, return zero. */
int target_char_to_host (int target_char, int *host_char);
/* If the target character TARGET_CHAR has a corresponding control
character (also in the target character set), set *TARGET_CTRL_CHAR
to the control character, and return non-zero. Otherwise, return
zero. */
int target_char_to_control_char (int target_char, int *target_ctrl_char);
#endif /* CHARSET_H */

View file

@ -1,5 +1,7 @@
/* Output generating routines for GDB CLI.
Copyright 1999, 2000 Free Software Foundation, Inc.
Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
Written by Fernando Nasser for Cygnus.
@ -26,17 +28,13 @@
#include "gdb_string.h"
#include "gdb_assert.h"
/* Convenience macro for allocting typesafe memory. */
#ifndef XMALLOC
#define XMALLOC(TYPE) (TYPE*) xmalloc (sizeof (TYPE))
#endif
struct ui_out_data
{
struct ui_file *stream;
struct ui_file *original_stream;
int suppress_output;
};
typedef struct ui_out_data cli_out_data;
/* These are the CLI output functions */
@ -67,6 +65,7 @@ static void cli_message (struct ui_out *uiout, int verbosity,
const char *format, va_list args);
static void cli_wrap_hint (struct ui_out *uiout, char *identstring);
static void cli_flush (struct ui_out *uiout);
static int cli_redirect (struct ui_out *uiout, struct ui_file *outstream);
/* This is the CLI ui-out implementation functions vector */
@ -90,6 +89,7 @@ static struct ui_out_impl cli_ui_out_impl =
cli_message,
cli_wrap_hint,
cli_flush,
cli_redirect,
0, /* Does not need MI hacks (i.e. needs CLI hacks). */
};
@ -114,11 +114,11 @@ cli_table_begin (struct ui_out *uiout, int nbrofcols,
int nr_rows,
const char *tblid)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (nr_rows == 0)
data->suppress_output = 1;
else
/* Only the table suppresses the output and, fortunatly, a table
/* Only the table suppresses the output and, fortunately, a table
is not a recursive data structure. */
gdb_assert (data->suppress_output == 0);
}
@ -128,7 +128,7 @@ cli_table_begin (struct ui_out *uiout, int nbrofcols,
void
cli_table_body (struct ui_out *uiout)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
/* first, close the table header line */
@ -140,7 +140,7 @@ cli_table_body (struct ui_out *uiout)
void
cli_table_end (struct ui_out *uiout)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
data->suppress_output = 0;
}
@ -151,7 +151,7 @@ cli_table_header (struct ui_out *uiout, int width, enum ui_align alignment,
const char *col_name,
const char *colhdr)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
cli_field_string (uiout, 0, width, alignment, 0, colhdr);
@ -165,7 +165,7 @@ cli_begin (struct ui_out *uiout,
int level,
const char *id)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
}
@ -177,7 +177,7 @@ cli_end (struct ui_out *uiout,
enum ui_out_type type,
int level)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
}
@ -191,7 +191,7 @@ cli_field_int (struct ui_out *uiout, int fldno, int width,
{
char buffer[20]; /* FIXME: how many chars long a %d can become? */
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
sprintf (buffer, "%d", value);
@ -205,7 +205,7 @@ cli_field_skip (struct ui_out *uiout, int fldno, int width,
enum ui_align alignment,
const char *fldname)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
cli_field_string (uiout, fldno, width, alignment, fldname, "");
@ -225,7 +225,7 @@ cli_field_string (struct ui_out *uiout,
int before = 0;
int after = 0;
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
@ -272,7 +272,7 @@ cli_field_fmt (struct ui_out *uiout, int fldno,
const char *format,
va_list args)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
@ -285,7 +285,7 @@ cli_field_fmt (struct ui_out *uiout, int fldno,
void
cli_spaces (struct ui_out *uiout, int numspaces)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
print_spaces_filtered (numspaces, data->stream);
@ -294,7 +294,7 @@ cli_spaces (struct ui_out *uiout, int numspaces)
void
cli_text (struct ui_out *uiout, const char *string)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
fputs_filtered (string, data->stream);
@ -304,7 +304,7 @@ void
cli_message (struct ui_out *uiout, int verbosity,
const char *format, va_list args)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
if (ui_out_get_verblvl (uiout) >= verbosity)
@ -314,7 +314,7 @@ cli_message (struct ui_out *uiout, int verbosity,
void
cli_wrap_hint (struct ui_out *uiout, char *identstring)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
if (data->suppress_output)
return;
wrap_here (identstring);
@ -323,10 +323,28 @@ cli_wrap_hint (struct ui_out *uiout, char *identstring)
void
cli_flush (struct ui_out *uiout)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
gdb_flush (data->stream);
}
int
cli_redirect (struct ui_out *uiout, struct ui_file *outstream)
{
struct ui_out_data *data = ui_out_data (uiout);
if (outstream != NULL)
{
data->original_stream = data->stream;
data->stream = outstream;
}
else if (data->original_stream != NULL)
{
data->stream = data->original_stream;
data->original_stream = NULL;
}
return 0;
}
/* local functions */
/* Like cli_field_fmt, but takes a variable number of args
@ -338,7 +356,7 @@ out_field_fmt (struct ui_out *uiout, int fldno,
const char *fldname,
const char *format,...)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
va_list args;
va_start (args, format);
@ -352,7 +370,7 @@ out_field_fmt (struct ui_out *uiout, int fldno,
static void
field_separator (void)
{
struct ui_out_data *data = ui_out_data (uiout);
cli_out_data *data = ui_out_data (uiout);
fputc_filtered (' ', data->stream);
}
@ -363,12 +381,22 @@ cli_out_new (struct ui_file *stream)
{
int flags = ui_source_list;
struct ui_out_data *data = XMALLOC (struct ui_out_data);
cli_out_data *data = XMALLOC (cli_out_data);
data->stream = stream;
data->original_stream = NULL;
data->suppress_output = 0;
return ui_out_new (&cli_ui_out_impl, data, flags);
}
struct ui_file *
cli_out_set_stream (struct ui_out *uiout, struct ui_file *stream)
{
cli_out_data *data = ui_out_data (uiout);
struct ui_file *old = data->stream;
data->stream = stream;
return old;
}
/* standard gdb initialization hook */
void
_initialize_cli_out (void)

View file

@ -22,6 +22,11 @@
#ifndef CLI_OUT_H
#define CLI_OUT_H
struct ui_file;
extern struct ui_out *cli_out_new (struct ui_file *stream);
extern struct ui_file *cli_out_set_stream (struct ui_out *uiout,
struct ui_file *stream);
#endif

View file

@ -1,6 +1,6 @@
/* GDB CLI commands.
Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
@ -20,11 +20,23 @@
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "readline/readline.h"
#include "readline/tilde.h"
#include "completer.h"
#include "target.h" /* For baud_rate, remote_debug and remote_timeout */
#include "gdb_wait.h" /* For shell escape implementation */
#include "gdb_regex.h" /* Used by apropos_command */
#include "gdb_string.h"
#include "gdb_vfork.h"
#include "linespec.h"
#include "expression.h"
#include "frame.h"
#include "value.h"
#include "language.h"
#include "filenames.h" /* for DOSish file names */
#include "objfiles.h"
#include "source.h"
#include "disasm.h"
#include "ui-out.h"
@ -34,23 +46,15 @@
#include "cli/cli-setshow.h"
#include "cli/cli-cmds.h"
#ifdef TUI
#include "tui/tui.h" /* For tui_active et.al. */
#endif
#ifndef GDBINIT_FILENAME
#define GDBINIT_FILENAME ".gdbinit"
#endif
/* From gdb/top.c */
extern void dont_repeat (void);
extern void set_verbose (char *, int, struct cmd_list_element *);
extern void show_history (char *, int);
extern void set_history (char *, int);
extern void show_commands (char *, int);
/* Prototypes for local functions */
/* Prototypes for local command functions */
static void complete_command (char *, int);
@ -60,8 +64,6 @@ static void pwd_command (char *, int);
static void show_version (char *, int);
static void validate_comname (char *);
static void help_command (char *, int);
static void show_command (char *, int);
@ -78,8 +80,19 @@ static void make_command (char *, int);
static void shell_escape (char *, int);
static void edit_command (char *, int);
static void list_command (char *, int);
void apropos_command (char *, int);
/* Prototypes for local utility functions */
static void ambiguous_line_spec (struct symtabs_and_lines *);
/* Limit the call depth of user-defined commands */
int max_user_call_depth;
/* Define all cmd_list_elements. */
/* Chain containing all defined commands. */
@ -174,7 +187,6 @@ error_no_arg (char *why)
/* The "info" command is defined as a prefix, with allow_unknown = 0.
Therefore, its own definition is called only for "info" with no args. */
/* ARGSUSED */
static void
info_command (char *arg, int from_tty)
{
@ -184,7 +196,6 @@ info_command (char *arg, int from_tty)
/* The "show" command with no arguments shows all the settings. */
/* ARGSUSED */
static void
show_command (char *arg, int from_tty)
{
@ -194,7 +205,6 @@ show_command (char *arg, int from_tty)
/* Provide documentation on command or list given by COMMAND. FROM_TTY
is ignored. */
/* ARGSUSED */
static void
help_command (char *command, int from_tty)
{
@ -212,13 +222,12 @@ compare_strings (const void *arg1, const void *arg2)
/* The "complete" command is used by Emacs to implement completion. */
/* ARGSUSED */
static void
complete_command (char *arg, int from_tty)
{
int i;
int argpoint;
char **completions;
char **completions, *point, *arg_prefix;
dont_repeat ();
@ -226,7 +235,23 @@ complete_command (char *arg, int from_tty)
arg = "";
argpoint = strlen (arg);
completions = complete_line (arg, arg, argpoint);
/* complete_line assumes that its first argument is somewhere within,
and except for filenames at the beginning of, the word to be completed.
The following crude imitation of readline's word-breaking tries to
accomodate this. */
point = arg + argpoint;
while (point > arg)
{
if (strchr (rl_completer_word_break_characters, point[-1]) != 0)
break;
point--;
}
arg_prefix = alloca (point - arg + 1);
memcpy (arg_prefix, arg, point - arg);
arg_prefix[point - arg] = 0;
completions = complete_line (point, arg, argpoint);
if (completions)
{
@ -242,7 +267,7 @@ complete_command (char *arg, int from_tty)
while (item < size)
{
int next_item;
printf_unfiltered ("%s\n", completions[item]);
printf_unfiltered ("%s%s\n", arg_prefix, completions[item]);
next_item = item + 1;
while (next_item < size
&& ! strcmp (completions[item], completions[next_item]))
@ -265,7 +290,6 @@ is_complete_command (struct cmd_list_element *c)
return cmd_cfunc_eq (c, complete_command);
}
/* ARGSUSED */
static void
show_version (char *args, int from_tty)
{
@ -285,7 +309,6 @@ quit_command (char *args, int from_tty)
quit_force (args, from_tty);
}
/* ARGSUSED */
static void
pwd_command (char *args, int from_tty)
{
@ -293,7 +316,7 @@ pwd_command (char *args, int from_tty)
error ("The \"pwd\" command does not take an argument: %s", args);
getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
if (!STREQ (gdb_dirbuf, current_directory))
if (strcmp (gdb_dirbuf, current_directory) != 0)
printf_unfiltered ("Working directory %s\n (canonically %s).\n",
current_directory, gdb_dirbuf);
else
@ -429,12 +452,11 @@ source_command (char *args, int from_tty)
do_cleanups (old_cleanups);
}
/* ARGSUSED */
static void
echo_command (char *text, int from_tty)
{
char *p = text;
register int c;
int c;
if (text)
while ((c = *p++) != '\0')
@ -459,7 +481,6 @@ echo_command (char *text, int from_tty)
gdb_flush (gdb_stdout);
}
/* ARGSUSED */
static void
shell_escape (char *arg, int from_tty)
{
@ -489,23 +510,24 @@ shell_escape (char *arg, int from_tty)
#endif
#else /* Can fork. */
int rc, status, pid;
char *p, *user_shell;
if ((user_shell = (char *) getenv ("SHELL")) == NULL)
user_shell = "/bin/sh";
/* Get the name of the shell for arg0 */
if ((p = strrchr (user_shell, '/')) == NULL)
p = user_shell;
else
p++; /* Get past '/' */
if ((pid = fork ()) == 0)
if ((pid = vfork ()) == 0)
{
if (!arg)
execl (user_shell, p, 0);
char *p, *user_shell;
if ((user_shell = (char *) getenv ("SHELL")) == NULL)
user_shell = "/bin/sh";
/* Get the name of the shell for arg0 */
if ((p = strrchr (user_shell, '/')) == NULL)
p = user_shell;
else
execl (user_shell, p, "-c", arg, 0);
p++; /* Get past '/' */
if (!arg)
execl (user_shell, p, (char *) 0);
else
execl (user_shell, p, "-c", arg, (char *) 0);
fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", user_shell,
safe_strerror (errno));
@ -521,6 +543,378 @@ shell_escape (char *arg, int from_tty)
#endif /* Can fork. */
}
static void
edit_command (char *arg, int from_tty)
{
struct symtabs_and_lines sals;
struct symtab_and_line sal;
struct symbol *sym;
char *arg1;
int cmdlen, log10;
unsigned m;
char *editor;
char *p;
/* Pull in the current default source line if necessary */
if (arg == 0)
{
set_default_source_symtab_and_line ();
sal = get_current_source_symtab_and_line ();
}
/* bare "edit" edits file with present line. */
if (arg == 0)
{
if (sal.symtab == 0)
error ("No default source file yet.");
sal.line += get_lines_to_list () / 2;
}
else
{
/* Now should only be one argument -- decode it in SAL */
arg1 = arg;
sals = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
if (! sals.nelts) return; /* C++ */
if (sals.nelts > 1) {
ambiguous_line_spec (&sals);
xfree (sals.sals);
return;
}
sal = sals.sals[0];
xfree (sals.sals);
if (*arg1)
error ("Junk at end of line specification.");
/* if line was specified by address,
first print exactly which line, and which file.
In this case, sal.symtab == 0 means address is outside
of all known source files, not that user failed to give a filename. */
if (*arg == '*')
{
if (sal.symtab == 0)
/* FIXME-32x64--assumes sal.pc fits in long. */
error ("No source file for address %s.",
local_hex_string((unsigned long) sal.pc));
sym = find_pc_function (sal.pc);
if (sym)
{
print_address_numeric (sal.pc, 1, gdb_stdout);
printf_filtered (" is in ");
fputs_filtered (SYMBOL_PRINT_NAME (sym), gdb_stdout);
printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
}
else
{
print_address_numeric (sal.pc, 1, gdb_stdout);
printf_filtered (" is at %s:%d.\n",
sal.symtab->filename, sal.line);
}
}
/* If what was given does not imply a symtab, it must be an undebuggable
symbol which means no source code. */
if (sal.symtab == 0)
error ("No line number known for %s.", arg);
}
if ((editor = (char *) getenv ("EDITOR")) == NULL)
editor = "/bin/ex";
/* Approximate base-10 log of line to 1 unit for digit count */
for(log10=32, m=0x80000000; !(sal.line & m) && log10>0; log10--, m=m>>1);
log10 = 1 + (int)((log10 + (0 == ((m-1) & sal.line)))/3.32192809);
cmdlen = strlen(editor) + 1
+ (NULL == sal.symtab->dirname ? 0 : strlen(sal.symtab->dirname) + 1)
+ (NULL == sal.symtab->filename? 0 : strlen(sal.symtab->filename)+ 1)
+ log10 + 2;
p = xmalloc(cmdlen);
sprintf(p,"%s +%d %s%s",editor,sal.line,
(NULL == sal.symtab->dirname ? "./" :
(NULL != sal.symtab->filename && *(sal.symtab->filename) != '/') ?
sal.symtab->dirname : ""),
(NULL == sal.symtab->filename ? "unknown" : sal.symtab->filename)
);
shell_escape(p, from_tty);
xfree(p);
}
static void
list_command (char *arg, int from_tty)
{
struct symtabs_and_lines sals, sals_end;
struct symtab_and_line sal, sal_end, cursal;
struct symbol *sym;
char *arg1;
int no_end = 1;
int dummy_end = 0;
int dummy_beg = 0;
int linenum_beg = 0;
char *p;
/* Pull in the current default source line if necessary */
if (arg == 0 || arg[0] == '+' || arg[0] == '-')
{
set_default_source_symtab_and_line ();
cursal = get_current_source_symtab_and_line ();
}
/* "l" or "l +" lists next ten lines. */
if (arg == 0 || strcmp (arg, "+") == 0)
{
print_source_lines (cursal.symtab, cursal.line,
cursal.line + get_lines_to_list (), 0);
return;
}
/* "l -" lists previous ten lines, the ones before the ten just listed. */
if (strcmp (arg, "-") == 0)
{
print_source_lines (cursal.symtab,
max (get_first_line_listed () - get_lines_to_list (), 1),
get_first_line_listed (), 0);
return;
}
/* Now if there is only one argument, decode it in SAL
and set NO_END.
If there are two arguments, decode them in SAL and SAL_END
and clear NO_END; however, if one of the arguments is blank,
set DUMMY_BEG or DUMMY_END to record that fact. */
if (!have_full_symbols () && !have_partial_symbols ())
error ("No symbol table is loaded. Use the \"file\" command.");
arg1 = arg;
if (*arg1 == ',')
dummy_beg = 1;
else
{
sals = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
if (!sals.nelts)
return; /* C++ */
if (sals.nelts > 1)
{
ambiguous_line_spec (&sals);
xfree (sals.sals);
return;
}
sal = sals.sals[0];
xfree (sals.sals);
}
/* Record whether the BEG arg is all digits. */
for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
linenum_beg = (p == arg1);
while (*arg1 == ' ' || *arg1 == '\t')
arg1++;
if (*arg1 == ',')
{
no_end = 0;
arg1++;
while (*arg1 == ' ' || *arg1 == '\t')
arg1++;
if (*arg1 == 0)
dummy_end = 1;
else
{
if (dummy_beg)
sals_end = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
else
sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0, 0);
if (sals_end.nelts == 0)
return;
if (sals_end.nelts > 1)
{
ambiguous_line_spec (&sals_end);
xfree (sals_end.sals);
return;
}
sal_end = sals_end.sals[0];
xfree (sals_end.sals);
}
}
if (*arg1)
error ("Junk at end of line specification.");
if (!no_end && !dummy_beg && !dummy_end
&& sal.symtab != sal_end.symtab)
error ("Specified start and end are in different files.");
if (dummy_beg && dummy_end)
error ("Two empty args do not say what lines to list.");
/* if line was specified by address,
first print exactly which line, and which file.
In this case, sal.symtab == 0 means address is outside
of all known source files, not that user failed to give a filename. */
if (*arg == '*')
{
if (sal.symtab == 0)
/* FIXME-32x64--assumes sal.pc fits in long. */
error ("No source file for address %s.",
local_hex_string ((unsigned long) sal.pc));
sym = find_pc_function (sal.pc);
if (sym)
{
print_address_numeric (sal.pc, 1, gdb_stdout);
printf_filtered (" is in ");
fputs_filtered (SYMBOL_PRINT_NAME (sym), gdb_stdout);
printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
}
else
{
print_address_numeric (sal.pc, 1, gdb_stdout);
printf_filtered (" is at %s:%d.\n",
sal.symtab->filename, sal.line);
}
}
/* If line was not specified by just a line number,
and it does not imply a symtab, it must be an undebuggable symbol
which means no source code. */
if (!linenum_beg && sal.symtab == 0)
error ("No line number known for %s.", arg);
/* If this command is repeated with RET,
turn it into the no-arg variant. */
if (from_tty)
*arg = 0;
if (dummy_beg && sal_end.symtab == 0)
error ("No default source file yet. Do \"help list\".");
if (dummy_beg)
print_source_lines (sal_end.symtab,
max (sal_end.line - (get_lines_to_list () - 1), 1),
sal_end.line + 1, 0);
else if (sal.symtab == 0)
error ("No default source file yet. Do \"help list\".");
else if (no_end)
{
int first_line = sal.line - get_lines_to_list () / 2;
if (first_line < 1) first_line = 1;
print_source_lines (sal.symtab,
first_line,
first_line + get_lines_to_list (),
0);
}
else
print_source_lines (sal.symtab, sal.line,
(dummy_end
? sal.line + get_lines_to_list ()
: sal_end.line + 1),
0);
}
/* Dump a specified section of assembly code. With no command line
arguments, this command will dump the assembly code for the
function surrounding the pc value in the selected frame. With one
argument, it will dump the assembly code surrounding that pc value.
Two arguments are interpeted as bounds within which to dump
assembly. */
static void
disassemble_command (char *arg, int from_tty)
{
CORE_ADDR low, high;
char *name;
CORE_ADDR pc, pc_masked;
char *space_index;
#if 0
asection *section;
#endif
name = NULL;
if (!arg)
{
if (!deprecated_selected_frame)
error ("No frame selected.\n");
pc = get_frame_pc (deprecated_selected_frame);
if (find_pc_partial_function (pc, &name, &low, &high) == 0)
error ("No function contains program counter for selected frame.\n");
#if defined(TUI)
/* NOTE: cagney/2003-02-13 The `tui_active' was previously
`tui_version'. */
if (tui_active)
/* FIXME: cagney/2004-02-07: This should be an observer. */
low = tui_get_low_disassembly_address (low, pc);
#endif
low += FUNCTION_START_OFFSET;
}
else if (!(space_index = (char *) strchr (arg, ' ')))
{
/* One argument. */
pc = parse_and_eval_address (arg);
if (find_pc_partial_function (pc, &name, &low, &high) == 0)
error ("No function contains specified address.\n");
#if defined(TUI)
/* NOTE: cagney/2003-02-13 The `tui_active' was previously
`tui_version'. */
if (tui_active)
/* FIXME: cagney/2004-02-07: This should be an observer. */
low = tui_get_low_disassembly_address (low, pc);
#endif
low += FUNCTION_START_OFFSET;
}
else
{
/* Two arguments. */
*space_index = '\0';
low = parse_and_eval_address (arg);
high = parse_and_eval_address (space_index + 1);
}
#if defined(TUI)
if (!tui_is_window_visible (DISASSEM_WIN))
#endif
{
printf_filtered ("Dump of assembler code ");
if (name != NULL)
{
printf_filtered ("for function %s:\n", name);
}
else
{
printf_filtered ("from ");
print_address_numeric (low, 1, gdb_stdout);
printf_filtered (" to ");
print_address_numeric (high, 1, gdb_stdout);
printf_filtered (":\n");
}
/* Dump the specified range. */
gdb_disassembly (uiout, 0, 0, 0, -1, low, high);
printf_filtered ("End of assembler dump.\n");
gdb_flush (gdb_stdout);
}
#if defined(TUI)
else
{
tui_show_assembly (low);
}
#endif
}
static void
make_command (char *arg, int from_tty)
{
@ -538,7 +932,6 @@ make_command (char *arg, int from_tty)
shell_escape (p, from_tty);
}
/* ARGSUSED */
static void
show_user (char *args, int from_tty)
{
@ -590,6 +983,21 @@ apropos_command (char *searchstr, int from_tty)
xfree (pattern_fastmap);
}
/* Print a list of files and line numbers which a user may choose from
in order to list a function which was specified ambiguously (as with
`list classname::overloadedfuncname', for example). The vector in
SALS provides the filenames and line numbers. */
static void
ambiguous_line_spec (struct symtabs_and_lines *sals)
{
int i;
for (i = 0; i < sals->nelts; ++i)
printf_filtered ("file: \"%s\", line number: %d\n",
sals->sals[i].symtab->filename, sals->sals[i].line);
}
static void
set_debug (char *arg, int from_tty)
{
@ -606,6 +1014,8 @@ show_debug (char *args, int from_tty)
void
init_cmd_lists (void)
{
max_user_call_depth = 1024;
cmdlist = NULL;
infolist = NULL;
enablelist = NULL;
@ -673,7 +1083,7 @@ The commands below can be used to select other frames by number or address.",
"Set working directory to DIR for debugger and program being debugged.\n\
The change does not take effect for the program being debugged\n\
until the next time it is started.", &cmdlist);
c->completer = filename_completer;
set_cmd_completer (c, filename_completer);
add_com ("echo", class_support, echo_command,
"Print a constant string. Give string as argument.\n\
@ -698,11 +1108,11 @@ Commands defined in this way may have up to ten arguments.");
"Read commands from a file named FILE.\n\
Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\
when gdb is started.", &cmdlist);
c->completer = filename_completer;
set_cmd_completer (c, filename_completer);
add_com ("quit", class_support, quit_command, "Exit gdb.");
c = add_com ("help", class_support, help_command, "Print list of commands.");
c->completer = command_completer;
set_cmd_completer (c, command_completer);
add_com_alias ("q", "quit", class_support, 1);
add_com_alias ("h", "help", class_support, 1);
@ -802,9 +1212,54 @@ from the target.", &setlist),
&showdebuglist, "show debug ", 0, &showlist);
c = add_com ("shell", class_support, shell_escape,
"Execute the rest of the line as a shell command. \n\
"Execute the rest of the line as a shell command.\n\
With no arguments, run an inferior shell.");
c->completer = filename_completer;
set_cmd_completer (c, filename_completer);
c = add_com ("edit", class_files, edit_command,
concat ("Edit specified file or function.\n\
With no argument, edits file containing most recent line listed.\n\
", "\
Editing targets can be specified in these ways:\n\
FILE:LINENUM, to edit at that line in that file,\n\
FUNCTION, to edit at the beginning of that function,\n\
FILE:FUNCTION, to distinguish among like-named static functions.\n\
*ADDRESS, to edit at the line containing that address.\n\
Uses EDITOR environment variable contents as editor (or ex as default).",NULL));
c->completer = location_completer;
add_com ("list", class_files, list_command,
concat ("List specified function or line.\n\
With no argument, lists ten more lines after or around previous listing.\n\
\"list -\" lists the ten lines before a previous ten-line listing.\n\
One argument specifies a line, and ten lines are listed around that line.\n\
Two arguments with comma between specify starting and ending lines to list.\n\
", "\
Lines can be specified in these ways:\n\
LINENUM, to list around that line in current file,\n\
FILE:LINENUM, to list around that line in that file,\n\
FUNCTION, to list around beginning of that function,\n\
FILE:FUNCTION, to distinguish among like-named static functions.\n\
*ADDRESS, to list around the line containing that address.\n\
With two args if one is empty it stands for ten lines away from the other arg.", NULL));
if (!xdb_commands)
add_com_alias ("l", "list", class_files, 1);
else
add_com_alias ("v", "list", class_files, 1);
if (dbx_commands)
add_com_alias ("file", "list", class_files, 1);
c = add_com ("disassemble", class_vars, disassemble_command,
"Disassemble a specified section of memory.\n\
Default is the function surrounding the pc of the selected frame.\n\
With a single argument, the function surrounding that address is dumped.\n\
Two arguments are taken as a range of memory to dump.");
set_cmd_completer (c, location_completer);
if (xdb_commands)
add_com_alias ("va", "disassemble", class_xdb, 0);
/* NOTE: cagney/2000-03-20: Being able to enter ``(gdb) !ls'' would
be a really useful feature. Unfortunately, the below wont do
@ -817,10 +1272,17 @@ With no arguments, run an inferior shell.");
c = add_com ("make", class_support, make_command,
"Run the ``make'' program using the rest of the line as arguments.");
c->completer = filename_completer;
set_cmd_completer (c, filename_completer);
add_cmd ("user", no_class, show_user,
"Show definitions of user defined commands.\n\
Argument is the name of the user defined command.\n\
With no argument, show definitions of all user defined commands.", &showlist);
add_com ("apropos", class_support, apropos_command, "Search for commands matching a REGEXP");
add_show_from_set (
add_set_cmd ("max-user-call-depth", no_class, var_integer,
(char *) &max_user_call_depth,
"Set the max call depth for user-defined commands.\n",
&setlist),
&showlist);
}

View file

@ -22,12 +22,19 @@
#include "symtab.h"
#include <ctype.h>
#include "gdb_regex.h"
#include "gdb_string.h"
#include "ui-out.h"
#include "cli/cli-cmds.h"
#include "cli/cli-decode.h"
#ifdef TUI
#include "tui/tui.h" /* For tui_active et.al. */
#endif
#include "gdb_assert.h"
/* Prototypes for local functions */
static void undef_cmd_error (char *, char *);
@ -51,8 +58,7 @@ do_cfunc (struct cmd_list_element *c, char *args, int from_tty)
}
void
set_cmd_cfunc (struct cmd_list_element *cmd,
void (*cfunc) (char *args, int from_tty))
set_cmd_cfunc (struct cmd_list_element *cmd, cmd_cfunc_ftype *cfunc)
{
if (cfunc == NULL)
cmd->func = NULL;
@ -68,9 +74,7 @@ do_sfunc (struct cmd_list_element *c, char *args, int from_tty)
}
void
set_cmd_sfunc (struct cmd_list_element *cmd,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element * c))
set_cmd_sfunc (struct cmd_list_element *cmd, cmd_sfunc_ftype *sfunc)
{
if (sfunc == NULL)
cmd->func = NULL;
@ -86,6 +90,31 @@ cmd_cfunc_eq (struct cmd_list_element *cmd,
return cmd->func == do_cfunc && cmd->function.cfunc == cfunc;
}
void
set_cmd_context (struct cmd_list_element *cmd, void *context)
{
cmd->context = context;
}
void *
get_cmd_context (struct cmd_list_element *cmd)
{
return cmd->context;
}
enum cmd_types
cmd_type (struct cmd_list_element *cmd)
{
return cmd->type;
}
void
set_cmd_completer (struct cmd_list_element *cmd,
char **(*completer) (char *text, char *word))
{
cmd->completer = completer; /* Ok. */
}
/* Add element named NAME.
CLASS is the top level category into which commands are broken down
@ -108,7 +137,7 @@ struct cmd_list_element *
add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
char *doc, struct cmd_list_element **list)
{
register struct cmd_list_element *c
struct cmd_list_element *c
= (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
struct cmd_list_element *p;
@ -133,6 +162,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
c->name = name;
c->class = class;
set_cmd_cfunc (c, fun);
set_cmd_context (c, NULL);
c->doc = doc;
c->flags = 0;
c->replacement = NULL;
@ -144,7 +174,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
c->prefixname = NULL;
c->allow_unknown = 0;
c->abbrev_flag = 0;
c->completer = make_symbol_completion_list;
set_cmd_completer (c, make_symbol_completion_list);
c->type = not_set_cmd;
c->var = NULL;
c->var_type = var_boolean;
@ -157,20 +187,6 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
return c;
}
/* Same as above, except that the abbrev_flag is set. */
/* Note: Doesn't seem to be used anywhere currently. */
struct cmd_list_element *
add_abbrev_cmd (char *name, enum command_class class, void (*fun) (char *, int),
char *doc, struct cmd_list_element **list)
{
register struct cmd_list_element *c
= add_cmd (name, class, fun, doc, list);
c->abbrev_flag = 1;
return c;
}
/* Deprecates a command CMD.
REPLACEMENT is the name of the command which should be used in place
of this command, or NULL if no such command exists.
@ -200,8 +216,8 @@ add_alias_cmd (char *name, char *oldname, enum command_class class,
{
/* Must do this since lookup_cmd tries to side-effect its first arg */
char *copied_name;
register struct cmd_list_element *old;
register struct cmd_list_element *c;
struct cmd_list_element *old;
struct cmd_list_element *c;
copied_name = (char *) alloca (strlen (oldname) + 1);
strcpy (copied_name, oldname);
old = lookup_cmd (&copied_name, *list, "", 1, 1);
@ -235,7 +251,7 @@ add_prefix_cmd (char *name, enum command_class class, void (*fun) (char *, int),
char *prefixname, int allow_unknown,
struct cmd_list_element **list)
{
register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
c->prefixlist = prefixlist;
c->prefixname = prefixname;
c->allow_unknown = allow_unknown;
@ -250,7 +266,7 @@ add_abbrev_prefix_cmd (char *name, enum command_class class,
struct cmd_list_element **prefixlist, char *prefixname,
int allow_unknown, struct cmd_list_element **list)
{
register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
struct cmd_list_element *c = add_cmd (name, class, fun, doc, list);
c->prefixlist = prefixlist;
c->prefixname = prefixname;
c->allow_unknown = allow_unknown;
@ -272,13 +288,90 @@ empty_sfunc (char *args, int from_tty, struct cmd_list_element *c)
{
}
/* Add element named NAME to command list LIST (the list for set
/* Add element named NAME to command list LIST (the list for set/show
or some sublist thereof).
TYPE is set_cmd or show_cmd.
CLASS is as in add_cmd.
VAR_TYPE is the kind of thing we are setting.
VAR is address of the variable being controlled by this command.
DOC is the documentation string. */
static struct cmd_list_element *
add_set_or_show_cmd (char *name,
enum cmd_types type,
enum command_class class,
var_types var_type,
void *var,
char *doc,
struct cmd_list_element **list)
{
struct cmd_list_element *c = add_cmd (name, class, NULL, doc, list);
gdb_assert (type == set_cmd || type == show_cmd);
c->type = type;
c->var_type = var_type;
c->var = var;
/* This needs to be something besides NULL so that this isn't
treated as a help class. */
set_cmd_sfunc (c, empty_sfunc);
return c;
}
/* Add element named NAME to both the command SET_LIST and SHOW_LIST.
CLASS is as in add_cmd. VAR_TYPE is the kind of thing we are
setting. VAR is address of the variable being controlled by this
command. SET_FUNC and SHOW_FUNC are the callback functions (if
non-NULL). SET_DOC and SHOW_DOC are the documentation strings.
SET_RESULT and SHOW_RESULT, if not NULL, are set to the resulting
command structures. */
void
add_setshow_cmd_full (char *name,
enum command_class class,
var_types var_type, void *var,
char *set_doc, char *show_doc,
cmd_sfunc_ftype *set_func, cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list,
struct cmd_list_element **set_result,
struct cmd_list_element **show_result)
{
struct cmd_list_element *set;
struct cmd_list_element *show;
set = add_set_or_show_cmd (name, set_cmd, class, var_type, var,
set_doc, set_list);
if (set_func != NULL)
set_cmd_sfunc (set, set_func);
show = add_set_or_show_cmd (name, show_cmd, class, var_type, var,
show_doc, show_list);
if (show_func != NULL)
set_cmd_sfunc (show, show_func);
if (set_result != NULL)
*set_result = set;
if (show_result != NULL)
*show_result = show;
}
/* Add element named NAME to both the command SET_LIST and SHOW_LIST.
CLASS is as in add_cmd. VAR_TYPE is the kind of thing we are
setting. VAR is address of the variable being controlled by this
command. SET_FUNC and SHOW_FUNC are the callback functions (if
non-NULL). SET_DOC and SHOW_DOC are the documentation strings. */
void
add_setshow_cmd (char *name,
enum command_class class,
var_types var_type, void *var,
char *set_doc, char *show_doc,
cmd_sfunc_ftype *set_func, cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
add_setshow_cmd_full (name, class, var_type, var, set_doc, show_doc,
set_func, show_func, set_list, show_list,
NULL, NULL);
}
struct cmd_list_element *
add_set_cmd (char *name,
enum command_class class,
@ -287,15 +380,7 @@ add_set_cmd (char *name,
char *doc,
struct cmd_list_element **list)
{
struct cmd_list_element *c = add_cmd (name, class, NULL, doc, list);
c->type = set_cmd;
c->var_type = var_type;
c->var = var;
/* This needs to be something besides NULL so that this isn't
treated as a help class. */
set_cmd_sfunc (c, empty_sfunc);
return c;
return add_set_or_show_cmd (name, set_cmd, class, var_type, var, doc, list);
}
/* Add element named NAME to command list LIST (the list for set
@ -321,83 +406,97 @@ add_set_enum_cmd (char *name,
return c;
}
/* Add element named NAME to command list LIST (the list for set
or some sublist thereof).
CLASS is as in add_cmd.
VAR is address of the variable which will contain the value.
DOC is the documentation string. */
struct cmd_list_element *
add_set_auto_boolean_cmd (char *name,
enum command_class class,
enum cmd_auto_boolean *var,
char *doc,
struct cmd_list_element **list)
/* Add an auto-boolean command named NAME to both the set and show
command list lists. CLASS is as in add_cmd. VAR is address of the
variable which will contain the value. DOC is the documentation
string. FUNC is the corresponding callback. */
void
add_setshow_auto_boolean_cmd (char *name,
enum command_class class,
enum auto_boolean *var,
char *set_doc, char *show_doc,
cmd_sfunc_ftype *set_func,
cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
static const char *auto_boolean_enums[] = { "on", "off", "auto", NULL };
struct cmd_list_element *c;
c = add_set_cmd (name, class, var_auto_boolean, var, doc, list);
add_setshow_cmd_full (name, class, var_auto_boolean, var,
set_doc, show_doc, set_func, show_func,
set_list, show_list,
&c, NULL);
c->enums = auto_boolean_enums;
return c;
}
/* Add element named NAME to command list LIST (the list for set
or some sublist thereof).
CLASS is as in add_cmd.
VAR is address of the variable which will contain the value.
DOC is the documentation string. */
struct cmd_list_element *
add_set_boolean_cmd (char *name,
enum command_class class,
int *var,
char *doc,
struct cmd_list_element **list)
/* Add element named NAME to both the set and show command LISTs (the
list for set/show or some sublist thereof). CLASS is as in
add_cmd. VAR is address of the variable which will contain the
value. SET_DOC and SHOW_DOR are the documentation strings. */
void
add_setshow_boolean_cmd (char *name,
enum command_class class,
int *var, char *set_doc, char *show_doc,
cmd_sfunc_ftype *set_func,
cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
static const char *boolean_enums[] = { "on", "off", NULL };
struct cmd_list_element *c;
c = add_set_cmd (name, class, var_boolean, var, doc, list);
add_setshow_cmd_full (name, class, var_boolean, var,
set_doc, show_doc,
set_func, show_func,
set_list, show_list,
&c, NULL);
c->enums = boolean_enums;
return c;
}
/* Add element named NAME to both the set and show command LISTs (the
list for set/show or some sublist thereof). CLASS is as in
add_cmd. VAR is address of the variable which will contain the
value. SET_DOC and SHOW_DOR are the documentation strings. */
void
add_setshow_uinteger_cmd (char *name,
enum command_class class,
unsigned int *var, char *set_doc, char *show_doc,
cmd_sfunc_ftype *set_func,
cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
add_setshow_cmd_full (name, class, var_uinteger, var,
set_doc, show_doc,
set_func, show_func,
set_list, show_list,
NULL, NULL);
}
/* Where SETCMD has already been added, add the corresponding show
command to LIST and return a pointer to the added command (not
command to LIST and return a pointer to the added command (not
necessarily the head of LIST). */
/* NOTE: cagney/2002-03-17: The original version of add_show_from_set
used memcpy() to clone `set' into `show'. This meant that in
addition to all the needed fields (var, name, et.al.) some
unnecessary fields were copied (namely the callback function). The
function explictly copies relevant fields. For a `set' and `show'
command to share the same callback, the caller must set both
explicitly. */
struct cmd_list_element *
add_show_from_set (struct cmd_list_element *setcmd,
struct cmd_list_element **list)
{
struct cmd_list_element *showcmd =
(struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
struct cmd_list_element *p;
char *doc;
const static char setstring[] = "Set ";
memcpy (showcmd, setcmd, sizeof (struct cmd_list_element));
delete_cmd (showcmd->name, list);
showcmd->type = show_cmd;
/* Create a doc string by replacing "Set " at the start of the
`set'' command's doco with "Show ". */
gdb_assert (strncmp (setcmd->doc, setstring, sizeof (setstring) - 1) == 0);
doc = concat ("Show ", setcmd->doc + sizeof (setstring) - 1, NULL);
/* Replace "set " at start of docstring with "show ". */
if (setcmd->doc[0] == 'S' && setcmd->doc[1] == 'e'
&& setcmd->doc[2] == 't' && setcmd->doc[3] == ' ')
showcmd->doc = concat ("Show ", setcmd->doc + 4, NULL);
else
fprintf_unfiltered (gdb_stderr, "GDB internal error: Bad docstring for set command\n");
if (*list == NULL || strcmp ((*list)->name, showcmd->name) >= 0)
{
showcmd->next = *list;
*list = showcmd;
}
else
{
p = *list;
while (p->next && strcmp (p->next->name, showcmd->name) <= 0)
{
p = p->next;
}
showcmd->next = p->next;
p->next = showcmd;
}
return showcmd;
/* Insert the basic command. */
return add_set_or_show_cmd (setcmd->name, show_cmd, setcmd->class,
setcmd->var_type, setcmd->var, doc, list);
}
/* Remove the command named NAME from the command list. */
@ -405,10 +504,10 @@ add_show_from_set (struct cmd_list_element *setcmd,
void
delete_cmd (char *name, struct cmd_list_element **list)
{
register struct cmd_list_element *c;
struct cmd_list_element *c;
struct cmd_list_element *p;
while (*list && STREQ ((*list)->name, name))
while (*list && strcmp ((*list)->name, name) == 0)
{
if ((*list)->hookee_pre)
(*list)->hookee_pre->hook_pre = 0; /* Hook slips out of its mouth */
@ -422,7 +521,7 @@ delete_cmd (char *name, struct cmd_list_element **list)
if (*list)
for (c = *list; c->next;)
{
if (STREQ (c->next->name, name))
if (strcmp (c->next->name, name) == 0)
{
if (c->next->hookee_pre)
c->next->hookee_pre->hook_pre = 0; /* hooked cmd gets away. */
@ -482,7 +581,7 @@ void
apropos_cmd (struct ui_file *stream, struct cmd_list_element *commandlist,
struct re_pattern_buffer *regex, char *prefix)
{
register struct cmd_list_element *c;
struct cmd_list_element *c;
int returnvalue=1; /*Needed to avoid double printing*/
/* Walk through the commands */
for (c=commandlist;c;c=c->next)
@ -645,14 +744,24 @@ help_list (struct cmd_list_element *list, char *cmdtype,
help_cmd_list (list, class, cmdtype, (int) class >= 0, stream);
if (class == all_classes)
fprintf_filtered (stream, "\n\
Type \"help%s\" followed by a class name for a list of commands in that class.",
cmdtype1);
{
fprintf_filtered (stream, "\n\
Type \"help%s\" followed by a class name for a list of commands in ",
cmdtype1);
wrap_here ("");
fprintf_filtered (stream, "that class.");
}
fprintf_filtered (stream, "\n\
Type \"help%s\" followed by %scommand name for full documentation.\n\
Command name abbreviations are allowed if unambiguous.\n",
fprintf_filtered (stream, "\nType \"help%s\" followed by %scommand name ",
cmdtype1, cmdtype2);
wrap_here ("");
fputs_filtered ("for ", stream);
wrap_here ("");
fputs_filtered ("full ", stream);
wrap_here ("");
fputs_filtered ("documentation.\n", stream);
fputs_filtered ("Command name abbreviations are allowed if unambiguous.\n",
stream);
}
static void
@ -681,7 +790,7 @@ print_doc_line (struct ui_file *stream, char *str)
{
static char *line_buffer = 0;
static int line_size;
register char *p;
char *p;
if (!line_buffer)
{
@ -725,7 +834,7 @@ void
help_cmd_list (struct cmd_list_element *list, enum command_class class,
char *prefix, int recurse, struct ui_file *stream)
{
register struct cmd_list_element *c;
struct cmd_list_element *c;
for (c = list; c; c = c->next)
{
@ -824,10 +933,14 @@ lookup_cmd_1 (char **text, struct cmd_list_element *clist,
/* Treating underscores as part of command words is important
so that "set args_foo()" doesn't get interpreted as
"set args _foo()". */
/* NOTE: cagney/2003-02-13 The `tui_active' was previously
`tui_version'. */
for (p = *text;
*p && (isalnum (*p) || *p == '-' || *p == '_' ||
(tui_version &&
#if defined(TUI)
(tui_active &&
(*p == '+' || *p == '<' || *p == '>' || *p == '$')) ||
#endif
(xdb_commands && (*p == '!' || *p == '/' || *p == '?')));
p++)
;
@ -949,7 +1062,7 @@ undef_cmd_error (char *cmdtype, char *q)
cmdtype,
q,
*cmdtype ? " " : "",
strlen (cmdtype) - 1,
(int) strlen (cmdtype) - 1,
cmdtype);
}
@ -1194,10 +1307,14 @@ lookup_cmd_composition (char *text,
/* Treating underscores as part of command words is important
so that "set args_foo()" doesn't get interpreted as
"set args _foo()". */
/* NOTE: cagney/2003-02-13 The `tui_active' was previously
`tui_version'. */
for (p = text;
*p && (isalnum (*p) || *p == '-' || *p == '_' ||
(tui_version &&
#if defined(TUI)
(tui_active &&
(*p == '+' || *p == '<' || *p == '>' || *p == '$')) ||
#endif
(xdb_commands && (*p == '!' || *p == '/' || *p == '?')));
p++)
;
@ -1407,3 +1524,23 @@ complete_on_enum (const char *enumlist[],
return matchlist;
}
/* check function pointer */
int
cmd_func_p (struct cmd_list_element *cmd)
{
return (cmd->func != NULL);
}
/* call the command function */
void
cmd_func (struct cmd_list_element *cmd, char *args, int from_tty)
{
if (cmd_func_p (cmd))
(*cmd->func) (cmd, args, from_tty);
else
error ("Invalid command");
}

View file

@ -1,5 +1,6 @@
/* Header file for GDB command decoding library.
Copyright 2000 Free Software Foundation, Inc.
Copyright 2000, 2003 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
@ -19,25 +20,13 @@
#if !defined (CLI_DECODE_H)
#define CLI_DECODE_H 1
#include "gdb_regex.h" /* Needed by apropos_cmd. */
#include "command.h"
/* Command classes are top-level categories into which commands are broken
down for "help" purposes.
Notes on classes: class_alias is for alias commands which are not
abbreviations of the original command. class-pseudo is for
commands which are not really commands nor help topics ("stop"). */
enum command_class
{
/* Special args to help_list */
class_deprecated, 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_trace,
class_alias, class_obscure, class_user, class_maintenance,
class_pseudo, class_tui, class_xdb
};
struct re_pattern_buffer;
#if 0
/* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum
cmd_types'' can be moved from "command.h" to "cli-decode.h". */
/* 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. */
@ -48,55 +37,7 @@ typedef enum cmd_types
show_cmd
}
cmd_types;
/* Reasonable values for an AUTO_BOOLEAN variable. */
enum cmd_auto_boolean
{
CMD_AUTO_BOOLEAN_TRUE,
CMD_AUTO_BOOLEAN_FALSE,
CMD_AUTO_BOOLEAN_AUTO
};
/* 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,
/* "on" / "true" / "enable" or "off" / "false" / "disable" or
"auto. *VAR is an ``enum cmd_auto_boolean''. NOTE: In general
a custom show command will need to be implemented - one that
for "auto" prints both the "auto" and the current auto-selected
value. */
var_auto_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,
/* Like var_uinteger but signed. *VAR is an int. The user can type 0
to mean "unlimited", which is stored in *VAR as INT_MAX. */
var_integer,
/* 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,
/* Enumerated type. Can only have one of the specified values. *VAR is a
char pointer to the name of the element that we find. */
var_enum
}
var_types;
#endif
/* This structure records one command'd definition. */
@ -130,15 +71,17 @@ struct cmd_list_element
to one of the below. */
union
{
/* If type is not_set_cmd, call it like this: */
void (*cfunc) (char *args, int from_tty);
/* If type is set_cmd or show_cmd, first set the variables, and
then call this. */
void (*sfunc) (char *args, int from_tty, struct cmd_list_element * c);
/* If type is not_set_cmd, call it like this: */
cmd_cfunc_ftype *cfunc;
/* If type is set_cmd or show_cmd, first set the variables,
and then call this: */
cmd_sfunc_ftype *sfunc;
}
function;
/* Local state (context) for this command. This can be anything. */
void *context;
/* 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.
@ -286,11 +229,18 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element * c));
extern void set_cmd_completer (struct cmd_list_element *cmd,
char **(*completer) (char *text, char *word));
/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
around in cmd objects to test the value of the commands sfunc(). */
extern int cmd_cfunc_eq (struct cmd_list_element *cmd,
void (*cfunc) (char *args, int from_tty));
/* Access to the command's local context. */
extern void set_cmd_context (struct cmd_list_element *cmd, void *context);
extern void *get_cmd_context (struct cmd_list_element *cmd);
extern struct cmd_list_element *lookup_cmd (char **,
struct cmd_list_element *, char *,
int, int);
@ -345,18 +295,6 @@ extern struct cmd_list_element *add_set_enum_cmd (char *name,
char *doc,
struct cmd_list_element **list);
extern struct cmd_list_element *add_set_auto_boolean_cmd (char *name,
enum command_class class,
enum cmd_auto_boolean *var,
char *doc,
struct cmd_list_element **list);
extern struct cmd_list_element *add_set_boolean_cmd (char *name,
enum command_class class,
int *var,
char *doc,
struct cmd_list_element **list);
extern struct cmd_list_element *add_show_from_set (struct cmd_list_element *,
struct cmd_list_element
**);

View file

@ -0,0 +1,796 @@
/* Dump-to-file commands, for GDB, the GNU debugger.
Copyright 2002 Free Software Foundation, Inc.
Contributed by Red Hat.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdb_string.h"
#include "cli/cli-decode.h"
#include "cli/cli-cmds.h"
#include "value.h"
#include "completer.h"
#include "cli/cli-dump.h"
#include "gdb_assert.h"
#include <ctype.h>
#include "target.h"
#include "readline/readline.h"
#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
char *
skip_spaces (char *chp)
{
if (chp == NULL)
return NULL;
while (isspace (*chp))
chp++;
return chp;
}
char *
scan_expression_with_cleanup (char **cmd, const char *def)
{
if ((*cmd) == NULL || (**cmd) == '\0')
{
char *exp = xstrdup (def);
make_cleanup (xfree, exp);
return exp;
}
else
{
char *exp;
char *end;
end = (*cmd) + strcspn (*cmd, " \t");
exp = savestring ((*cmd), end - (*cmd));
make_cleanup (xfree, exp);
(*cmd) = skip_spaces (end);
return exp;
}
}
static void
do_fclose_cleanup (void *arg)
{
FILE *file = arg;
fclose (arg);
}
static struct cleanup *
make_cleanup_fclose (FILE *file)
{
return make_cleanup (do_fclose_cleanup, file);
}
char *
scan_filename_with_cleanup (char **cmd, const char *defname)
{
char *filename;
char *fullname;
/* FIXME: Need to get the ``/a(ppend)'' flag from somewhere. */
/* File. */
if ((*cmd) == NULL)
{
if (defname == NULL)
error ("Missing filename.");
filename = xstrdup (defname);
make_cleanup (xfree, filename);
}
else
{
/* FIXME: should parse a possibly quoted string. */
char *end;
(*cmd) = skip_spaces (*cmd);
end = *cmd + strcspn (*cmd, " \t");
filename = savestring ((*cmd), end - (*cmd));
make_cleanup (xfree, filename);
(*cmd) = skip_spaces (end);
}
gdb_assert (filename != NULL);
fullname = tilde_expand (filename);
make_cleanup (xfree, fullname);
return fullname;
}
FILE *
fopen_with_cleanup (char *filename, const char *mode)
{
FILE *file = fopen (filename, mode);
if (file == NULL)
perror_with_name (filename);
make_cleanup_fclose (file);
return file;
}
static bfd *
bfd_openr_with_cleanup (const char *filename, const char *target)
{
bfd *ibfd;
ibfd = bfd_openr (filename, target);
if (ibfd == NULL)
error ("Failed to open %s: %s.", filename,
bfd_errmsg (bfd_get_error ()));
make_cleanup_bfd_close (ibfd);
if (!bfd_check_format (ibfd, bfd_object))
error ("'%s' is not a recognized file format.", filename);
return ibfd;
}
static bfd *
bfd_openw_with_cleanup (char *filename, const char *target, char *mode)
{
bfd *obfd;
if (*mode == 'w') /* Write: create new file */
{
obfd = bfd_openw (filename, target);
if (obfd == NULL)
error ("Failed to open %s: %s.", filename,
bfd_errmsg (bfd_get_error ()));
make_cleanup_bfd_close (obfd);
if (!bfd_set_format (obfd, bfd_object))
error ("bfd_openw_with_cleanup: %s.", bfd_errmsg (bfd_get_error ()));
}
else if (*mode == 'a') /* Append to existing file */
{ /* FIXME -- doesn't work... */
error ("bfd_openw does not work with append.");
}
else
error ("bfd_openw_with_cleanup: unknown mode %s.", mode);
return obfd;
}
struct cmd_list_element *dump_cmdlist;
struct cmd_list_element *append_cmdlist;
struct cmd_list_element *srec_cmdlist;
struct cmd_list_element *ihex_cmdlist;
struct cmd_list_element *tekhex_cmdlist;
struct cmd_list_element *binary_dump_cmdlist;
struct cmd_list_element *binary_append_cmdlist;
static void
dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump\" must be followed by a subcommand.\n\n");
help_list (dump_cmdlist, "dump ", -1, gdb_stdout);
}
static void
append_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"append\" must be followed by a subcommand.\n\n");
help_list (dump_cmdlist, "append ", -1, gdb_stdout);
}
static void
dump_binary_file (char *filename, char *mode,
char *buf, int len)
{
FILE *file;
int status;
file = fopen_with_cleanup (filename, mode);
status = fwrite (buf, len, 1, file);
if (status != 1)
perror_with_name (filename);
}
static void
dump_bfd_file (char *filename, char *mode,
char *target, CORE_ADDR vaddr,
char *buf, int len)
{
bfd *obfd;
asection *osection;
obfd = bfd_openw_with_cleanup (filename, target, mode);
osection = bfd_make_section_anyway (obfd, ".newsec");
bfd_set_section_size (obfd, osection, len);
bfd_set_section_vma (obfd, osection, vaddr);
bfd_set_section_alignment (obfd, osection, 0);
bfd_set_section_flags (obfd, osection, 0x203);
osection->entsize = 0;
bfd_set_section_contents (obfd, osection, buf, 0, len);
}
static void
dump_memory_to_file (char *cmd, char *mode, char *file_format)
{
struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
CORE_ADDR lo;
CORE_ADDR hi;
ULONGEST count;
char *filename;
void *buf;
char *lo_exp;
char *hi_exp;
int len;
/* Open the file. */
filename = scan_filename_with_cleanup (&cmd, NULL);
/* Find the low address. */
if (cmd == NULL || *cmd == '\0')
error ("Missing start address.");
lo_exp = scan_expression_with_cleanup (&cmd, NULL);
/* Find the second address - rest of line. */
if (cmd == NULL || *cmd == '\0')
error ("Missing stop address.");
hi_exp = cmd;
lo = parse_and_eval_address (lo_exp);
hi = parse_and_eval_address (hi_exp);
if (hi <= lo)
error ("Invalid memory address range (start >= end).");
count = hi - lo;
/* FIXME: Should use read_memory_partial() and a magic blocking
value. */
buf = xmalloc (count);
make_cleanup (xfree, buf);
target_read_memory (lo, buf, count);
/* Have everything. Open/write the data. */
if (file_format == NULL || strcmp (file_format, "binary") == 0)
{
dump_binary_file (filename, mode, buf, count);
}
else
{
dump_bfd_file (filename, mode, file_format, lo, buf, count);
}
do_cleanups (old_cleanups);
}
static void
dump_memory_command (char *cmd, char *mode)
{
dump_memory_to_file (cmd, mode, "binary");
}
static void
dump_value_to_file (char *cmd, char *mode, char *file_format)
{
struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
struct value *val;
char *filename;
/* Open the file. */
filename = scan_filename_with_cleanup (&cmd, NULL);
/* Find the value. */
if (cmd == NULL || *cmd == '\0')
error ("No value to %s.", *mode == 'a' ? "append" : "dump");
val = parse_and_eval (cmd);
if (val == NULL)
error ("Invalid expression.");
/* Have everything. Open/write the data. */
if (file_format == NULL || strcmp (file_format, "binary") == 0)
{
dump_binary_file (filename, mode, VALUE_CONTENTS (val),
TYPE_LENGTH (VALUE_TYPE (val)));
}
else
{
CORE_ADDR vaddr;
if (VALUE_LVAL (val))
{
vaddr = VALUE_ADDRESS (val);
}
else
{
vaddr = 0;
warning ("value is not an lval: address assumed to be zero");
}
dump_bfd_file (filename, mode, file_format, vaddr,
VALUE_CONTENTS (val),
TYPE_LENGTH (VALUE_TYPE (val)));
}
do_cleanups (old_cleanups);
}
static void
dump_value_command (char *cmd, char *mode)
{
dump_value_to_file (cmd, mode, "binary");
}
static void
dump_srec_memory (char *args, int from_tty)
{
dump_memory_to_file (args, FOPEN_WB, "srec");
}
static void
dump_srec_value (char *args, int from_tty)
{
dump_value_to_file (args, FOPEN_WB, "srec");
}
static void
dump_ihex_memory (char *args, int from_tty)
{
dump_memory_to_file (args, FOPEN_WB, "ihex");
}
static void
dump_ihex_value (char *args, int from_tty)
{
dump_value_to_file (args, FOPEN_WB, "ihex");
}
static void
dump_tekhex_memory (char *args, int from_tty)
{
dump_memory_to_file (args, FOPEN_WB, "tekhex");
}
static void
dump_tekhex_value (char *args, int from_tty)
{
dump_value_to_file (args, FOPEN_WB, "tekhex");
}
static void
dump_binary_memory (char *args, int from_tty)
{
dump_memory_to_file (args, FOPEN_WB, "binary");
}
static void
dump_binary_value (char *args, int from_tty)
{
dump_value_to_file (args, FOPEN_WB, "binary");
}
static void
append_binary_memory (char *args, int from_tty)
{
dump_memory_to_file (args, FOPEN_AB, "binary");
}
static void
append_binary_value (char *args, int from_tty)
{
dump_value_to_file (args, FOPEN_AB, "binary");
}
struct dump_context
{
void (*func) (char *cmd, char *mode);
char *mode;
};
static void
call_dump_func (struct cmd_list_element *c, char *args, int from_tty)
{
struct dump_context *d = get_cmd_context (c);
d->func (args, d->mode);
}
void
add_dump_command (char *name, void (*func) (char *args, char *mode),
char *descr)
{
struct cmd_list_element *c;
struct dump_context *d;
c = add_cmd (name, all_commands, NULL, descr, &dump_cmdlist);
c->completer = filename_completer;
d = XMALLOC (struct dump_context);
d->func = func;
d->mode = FOPEN_WB;
set_cmd_context (c, d);
c->func = call_dump_func;
c = add_cmd (name, all_commands, NULL, descr, &append_cmdlist);
c->completer = filename_completer;
d = XMALLOC (struct dump_context);
d->func = func;
d->mode = FOPEN_AB;
set_cmd_context (c, d);
c->func = call_dump_func;
/* Replace "Dump " at start of docstring with "Append "
(borrowed from add_show_from_set). */
if ( c->doc[0] == 'W'
&& c->doc[1] == 'r'
&& c->doc[2] == 'i'
&& c->doc[3] == 't'
&& c->doc[4] == 'e'
&& c->doc[5] == ' ')
c->doc = concat ("Append ", c->doc + 6, NULL);
}
/* Opaque data for restore_section_callback. */
struct callback_data {
unsigned long load_offset;
CORE_ADDR load_start;
CORE_ADDR load_end;
};
/* Function: restore_section_callback.
Callback function for bfd_map_over_sections.
Selectively loads the sections into memory. */
static void
restore_section_callback (bfd *ibfd, asection *isec, void *args)
{
struct callback_data *data = args;
bfd_vma sec_start = bfd_section_vma (ibfd, isec);
bfd_size_type size = bfd_section_size (ibfd, isec);
bfd_vma sec_end = sec_start + size;
bfd_size_type sec_offset = 0;
bfd_size_type sec_load_count = size;
struct cleanup *old_chain;
char *buf;
int ret;
/* Ignore non-loadable sections, eg. from elf files. */
if (!(bfd_get_section_flags (ibfd, isec) & SEC_LOAD))
return;
/* Does the section overlap with the desired restore range? */
if (sec_end <= data->load_start
|| (data->load_end > 0 && sec_start >= data->load_end))
{
/* No, no useable data in this section. */
printf_filtered ("skipping section %s...\n",
bfd_section_name (ibfd, isec));
return;
}
/* Compare section address range with user-requested
address range (if any). Compute where the actual
transfer should start and end. */
if (sec_start < data->load_start)
sec_offset = data->load_start - sec_start;
/* Size of a partial transfer: */
sec_load_count -= sec_offset;
if (data->load_end > 0 && sec_end > data->load_end)
sec_load_count -= sec_end - data->load_end;
/* Get the data. */
buf = xmalloc (size);
old_chain = make_cleanup (xfree, buf);
if (!bfd_get_section_contents (ibfd, isec, buf, 0, size))
error ("Failed to read bfd file %s: '%s'.", bfd_get_filename (ibfd),
bfd_errmsg (bfd_get_error ()));
printf_filtered ("Restoring section %s (0x%lx to 0x%lx)",
bfd_section_name (ibfd, isec),
(unsigned long) sec_start,
(unsigned long) sec_end);
if (data->load_offset != 0 || data->load_start != 0 || data->load_end != 0)
printf_filtered (" into memory (0x%s to 0x%s)\n",
paddr_nz ((unsigned long) sec_start
+ sec_offset + data->load_offset),
paddr_nz ((unsigned long) sec_start + sec_offset
+ data->load_offset + sec_load_count));
else
puts_filtered ("\n");
/* Write the data. */
ret = target_write_memory (sec_start + sec_offset + data->load_offset,
buf + sec_offset, sec_load_count);
if (ret != 0)
warning ("restore: memory write failed (%s).", safe_strerror (ret));
do_cleanups (old_chain);
return;
}
static void
restore_binary_file (char *filename, struct callback_data *data)
{
FILE *file = fopen_with_cleanup (filename, FOPEN_RB);
int status;
char *buf;
long len;
/* Get the file size for reading. */
if (fseek (file, 0, SEEK_END) == 0)
len = ftell (file);
else
perror_with_name (filename);
if (len <= data->load_start)
error ("Start address is greater than length of binary file %s.",
filename);
/* Chop off "len" if it exceeds the requested load_end addr. */
if (data->load_end != 0 && data->load_end < len)
len = data->load_end;
/* Chop off "len" if the requested load_start addr skips some bytes. */
if (data->load_start > 0)
len -= data->load_start;
printf_filtered
("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
filename,
(unsigned long) data->load_start + data->load_offset,
(unsigned long) data->load_start + data->load_offset + len);
/* Now set the file pos to the requested load start pos. */
if (fseek (file, data->load_start, SEEK_SET) != 0)
perror_with_name (filename);
/* Now allocate a buffer and read the file contents. */
buf = xmalloc (len);
make_cleanup (xfree, buf);
if (fread (buf, 1, len, file) != len)
perror_with_name (filename);
/* Now write the buffer into target memory. */
len = target_write_memory (data->load_start + data->load_offset, buf, len);
if (len != 0)
warning ("restore: memory write failed (%s).", safe_strerror (len));
return;
}
static void
restore_command (char *args, int from_tty)
{
char *filename;
struct callback_data data;
bfd *ibfd;
int binary_flag = 0;
if (!target_has_execution)
noprocess ();
data.load_offset = 0;
data.load_start = 0;
data.load_end = 0;
/* Parse the input arguments. First is filename (required). */
filename = scan_filename_with_cleanup (&args, NULL);
if (args != NULL && *args != '\0')
{
char *binary_string = "binary";
/* Look for optional "binary" flag. */
if (strncmp (args, binary_string, strlen (binary_string)) == 0)
{
binary_flag = 1;
args += strlen (binary_string);
args = skip_spaces (args);
}
/* Parse offset (optional). */
if (args != NULL && *args != '\0')
data.load_offset =
parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
if (args != NULL && *args != '\0')
{
/* Parse start address (optional). */
data.load_start =
parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
if (args != NULL && *args != '\0')
{
/* Parse end address (optional). */
data.load_end = parse_and_eval_long (args);
if (data.load_end <= data.load_start)
error ("Start must be less than end.");
}
}
}
if (info_verbose)
printf_filtered ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
filename, (unsigned long) data.load_offset,
(unsigned long) data.load_start,
(unsigned long) data.load_end);
if (binary_flag)
{
restore_binary_file (filename, &data);
}
else
{
/* Open the file for loading. */
ibfd = bfd_openr_with_cleanup (filename, NULL);
/* Process the sections. */
bfd_map_over_sections (ibfd, restore_section_callback, &data);
}
return;
}
static void
srec_dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump srec\" must be followed by a subcommand.\n");
help_list (srec_cmdlist, "dump srec ", -1, gdb_stdout);
}
static void
ihex_dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump ihex\" must be followed by a subcommand.\n");
help_list (ihex_cmdlist, "dump ihex ", -1, gdb_stdout);
}
static void
tekhex_dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump tekhex\" must be followed by a subcommand.\n");
help_list (tekhex_cmdlist, "dump tekhex ", -1, gdb_stdout);
}
static void
binary_dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump binary\" must be followed by a subcommand.\n");
help_list (binary_dump_cmdlist, "dump binary ", -1, gdb_stdout);
}
static void
binary_append_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"append binary\" must be followed by a subcommand.\n");
help_list (binary_append_cmdlist, "append binary ", -1, gdb_stdout);
}
extern initialize_file_ftype _initialize_cli_dump; /* -Wmissing-prototypes */
void
_initialize_cli_dump (void)
{
struct cmd_list_element *c;
add_prefix_cmd ("dump", class_vars, dump_command, "\
Dump target code/data to a local file.",
&dump_cmdlist, "dump ",
0/*allow-unknown*/,
&cmdlist);
add_prefix_cmd ("append", class_vars, append_command, "\
Append target code/data to a local file.",
&append_cmdlist, "append ",
0/*allow-unknown*/,
&cmdlist);
add_dump_command ("memory", dump_memory_command, "\
Write contents of memory to a raw binary file.\n\
Arguments are FILE START STOP. Writes the contents of memory within the\n\
range [START .. STOP) to the specifed FILE in raw target ordered bytes.");
add_dump_command ("value", dump_value_command, "\
Write the value of an expression to a raw binary file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION to\n\
the specified FILE in raw target ordered bytes.");
add_prefix_cmd ("srec", all_commands, srec_dump_command, "\
Write target code/data to an srec file.",
&srec_cmdlist, "dump srec ",
0 /*allow-unknown*/,
&dump_cmdlist);
add_prefix_cmd ("ihex", all_commands, ihex_dump_command, "\
Write target code/data to an intel hex file.",
&ihex_cmdlist, "dump ihex ",
0 /*allow-unknown*/,
&dump_cmdlist);
add_prefix_cmd ("tekhex", all_commands, tekhex_dump_command, "\
Write target code/data to a tekhex file.",
&tekhex_cmdlist, "dump tekhex ",
0 /*allow-unknown*/,
&dump_cmdlist);
add_prefix_cmd ("binary", all_commands, binary_dump_command, "\
Write target code/data to a raw binary file.",
&binary_dump_cmdlist, "dump binary ",
0 /*allow-unknown*/,
&dump_cmdlist);
add_prefix_cmd ("binary", all_commands, binary_append_command, "\
Append target code/data to a raw binary file.",
&binary_append_cmdlist, "append binary ",
0 /*allow-unknown*/,
&append_cmdlist);
add_cmd ("memory", all_commands, dump_srec_memory, "\
Write contents of memory to an srec file.\n\
Arguments are FILE START STOP. Writes the contents of memory\n\
within the range [START .. STOP) to the specifed FILE in srec format.",
&srec_cmdlist);
add_cmd ("value", all_commands, dump_srec_value, "\
Write the value of an expression to an srec file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in srec format.",
&srec_cmdlist);
add_cmd ("memory", all_commands, dump_ihex_memory, "\
Write contents of memory to an ihex file.\n\
Arguments are FILE START STOP. Writes the contents of memory within\n\
the range [START .. STOP) to the specifed FILE in intel hex format.",
&ihex_cmdlist);
add_cmd ("value", all_commands, dump_ihex_value, "\
Write the value of an expression to an ihex file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in intel hex format.",
&ihex_cmdlist);
add_cmd ("memory", all_commands, dump_tekhex_memory, "\
Write contents of memory to a tekhex file.\n\
Arguments are FILE START STOP. Writes the contents of memory\n\
within the range [START .. STOP) to the specifed FILE in tekhex format.",
&tekhex_cmdlist);
add_cmd ("value", all_commands, dump_tekhex_value, "\
Write the value of an expression to a tekhex file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in tekhex format.",
&tekhex_cmdlist);
add_cmd ("memory", all_commands, dump_binary_memory, "\
Write contents of memory to a raw binary file.\n\
Arguments are FILE START STOP. Writes the contents of memory\n\
within the range [START .. STOP) to the specifed FILE in binary format.",
&binary_dump_cmdlist);
add_cmd ("value", all_commands, dump_binary_value, "\
Write the value of an expression to a raw binary file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in raw target ordered bytes.",
&binary_dump_cmdlist);
add_cmd ("memory", all_commands, append_binary_memory, "\
Append contents of memory to a raw binary file.\n\
Arguments are FILE START STOP. Writes the contents of memory within the\n\
range [START .. STOP) to the specifed FILE in raw target ordered bytes.",
&binary_append_cmdlist);
add_cmd ("value", all_commands, append_binary_value, "\
Append the value of an expression to a raw binary file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in raw target ordered bytes.",
&binary_append_cmdlist);
c = add_com ("restore", class_vars, restore_command,
"Restore the contents of FILE to target memory.\n\
Arguments are FILE OFFSET START END where all except FILE are optional.\n\
OFFSET will be added to the base address of the file (default zero).\n\
If START and END are given, only the file contents within that range\n\
(file relative) will be restored to target memory.");
c->completer = filename_completer;
/* FIXME: completers for other commands. */
}

View file

@ -0,0 +1,40 @@
/* Dump-to-file commands, for GDB, the GNU debugger.
Copyright 2001 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef CLI_DUMP_H
#define CLI_DUMP_H
extern void add_dump_command (char *name,
void (*func) (char *args, char *mode),
char *descr);
/* Utilities for doing the dump. */
extern char *scan_filename_with_cleanup (char **cmd, const char *defname);
extern char *scan_expression_with_cleanup (char **cmd, const char *defname);
extern FILE *fopen_with_cleanup (char *filename, const char *mode);
extern char *skip_spaces (char *inp);
extern struct value *parse_and_eval_with_error (char *exp, const char *fmt, ...) ATTR_FORMAT (printf, 2, 3);
#endif

View file

@ -0,0 +1,157 @@
/* CLI Definitions for GDB, the GNU debugger.
Copyright 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "interps.h"
#include "wrapper.h"
#include "event-top.h"
#include "ui-out.h"
#include "cli-out.h"
#include "top.h" /* for "execute_command" */
#include "gdb_string.h"
struct ui_out *cli_uiout;
/* These are the ui_out and the interpreter for the console interpreter. */
/* Longjmp-safe wrapper for "execute_command" */
static int do_captured_execute_command (struct ui_out *uiout, void *data);
static enum gdb_rc safe_execute_command (struct ui_out *uiout, char *command,
int from_tty);
struct captured_execute_command_args
{
char *command;
int from_tty;
};
/* These implement the cli out interpreter: */
static void *
cli_interpreter_init (void)
{
return NULL;
}
static int
cli_interpreter_resume (void *data)
{
struct ui_file *stream;
/*sync_execution = 1; */
/* gdb_setup_readline will change gdb_stdout. If the CLI was previously
writing to gdb_stdout, then set it to the new gdb_stdout afterwards. */
stream = cli_out_set_stream (cli_uiout, gdb_stdout);
if (stream != gdb_stdout)
{
cli_out_set_stream (cli_uiout, stream);
stream = NULL;
}
gdb_setup_readline ();
if (stream != NULL)
cli_out_set_stream (cli_uiout, gdb_stdout);
return 1;
}
static int
cli_interpreter_suspend (void *data)
{
gdb_disable_readline ();
return 1;
}
/* Don't display the prompt if we are set quiet. */
static int
cli_interpreter_display_prompt_p (void *data)
{
if (interp_quiet_p (NULL))
return 0;
else
return 1;
}
static int
cli_interpreter_exec (void *data, const char *command_str)
{
int result;
struct ui_file *old_stream;
/* FIXME: cagney/2003-02-01: Need to const char *propogate
safe_execute_command. */
char *str = strcpy (alloca (strlen (command_str) + 1), command_str);
/* gdb_stdout could change between the time cli_uiout was initialized
and now. Since we're probably using a different interpreter which has
a new ui_file for gdb_stdout, use that one instead of the default.
It is important that it gets reset everytime, since the user could
set gdb to use a different interpreter. */
old_stream = cli_out_set_stream (cli_uiout, gdb_stdout);
result = safe_execute_command (cli_uiout, str, 1);
cli_out_set_stream (cli_uiout, old_stream);
return result;
}
static int
do_captured_execute_command (struct ui_out *uiout, void *data)
{
struct captured_execute_command_args *args =
(struct captured_execute_command_args *) data;
execute_command (args->command, args->from_tty);
return GDB_RC_OK;
}
static enum gdb_rc
safe_execute_command (struct ui_out *uiout, char *command, int from_tty)
{
struct captured_execute_command_args args;
args.command = command;
args.from_tty = from_tty;
return catch_exceptions (uiout, do_captured_execute_command, &args,
NULL, RETURN_MASK_ALL);
}
/* standard gdb initialization hook */
extern initialize_file_ftype _initialize_cli_interp; /* -Wmissing-prototypes */
void
_initialize_cli_interp (void)
{
static const struct interp_procs procs = {
cli_interpreter_init, /* init_proc */
cli_interpreter_resume, /* resume_proc */
cli_interpreter_suspend, /* suspend_proc */
cli_interpreter_exec, /* exec_proc */
cli_interpreter_display_prompt_p /* prompt_proc_p */
};
struct interp *cli_interp;
/* Create a default uiout builder for the CLI. */
cli_uiout = cli_out_new (gdb_stdout);
cli_interp = interp_new (INTERP_CONSOLE, NULL, cli_uiout, &procs);
interp_add (cli_interp);
}

View file

@ -0,0 +1,205 @@
/* Command-line output logging for GDB, the GNU debugger.
Copyright 2003
Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdbcmd.h"
#include "ui-out.h"
#include "gdb_string.h"
/* These hold the pushed copies of the gdb output files.
If NULL then nothing has yet been pushed. */
struct saved_output_files
{
struct ui_file *out;
struct ui_file *err;
struct ui_file *log;
struct ui_file *targ;
};
static struct saved_output_files saved_output;
static char *saved_filename;
static char *logging_filename;
int logging_overwrite, logging_redirect;
/* If we've pushed output files, close them and pop them. */
static void
pop_output_files (void)
{
/* Only delete one of the files -- they are all set to the same
value. */
ui_file_delete (gdb_stdout);
gdb_stdout = saved_output.out;
gdb_stderr = saved_output.err;
gdb_stdlog = saved_output.log;
gdb_stdtarg = saved_output.targ;
saved_output.out = NULL;
saved_output.err = NULL;
saved_output.log = NULL;
saved_output.targ = NULL;
ui_out_redirect (uiout, NULL);
}
/* This is a helper for the `set logging' command. */
static void
handle_redirections (int from_tty)
{
struct ui_file *output;
if (saved_filename != NULL)
{
fprintf_unfiltered (gdb_stdout, "Already logging to %s.\n",
saved_filename);
return;
}
output = gdb_fopen (logging_filename, logging_overwrite ? "w" : "a");
if (output == NULL)
perror_with_name ("set logging");
/* Redirects everything to gdb_stdout while this is running. */
if (!logging_redirect)
{
output = tee_file_new (gdb_stdout, 0, output, 1);
if (output == NULL)
perror_with_name ("set logging");
if (from_tty)
fprintf_unfiltered (gdb_stdout, "Copying output to %s.\n",
logging_filename);
}
else if (from_tty)
fprintf_unfiltered (gdb_stdout, "Redirecting output to %s.\n",
logging_filename);
saved_filename = xstrdup (logging_filename);
saved_output.out = gdb_stdout;
saved_output.err = gdb_stderr;
saved_output.log = gdb_stdlog;
saved_output.targ = gdb_stdtarg;
gdb_stdout = output;
gdb_stderr = output;
gdb_stdlog = output;
gdb_stdtarg = output;
if (ui_out_redirect (uiout, gdb_stdout) < 0)
warning ("Current output protocol does not support redirection");
}
static void
set_logging_on (char *args, int from_tty)
{
char *rest = args;
if (rest && *rest)
{
xfree (logging_filename);
logging_filename = xstrdup (rest);
}
handle_redirections (from_tty);
}
static void
set_logging_off (char *args, int from_tty)
{
if (saved_filename == NULL)
return;
pop_output_files ();
if (from_tty)
fprintf_unfiltered (gdb_stdout, "Done logging to %s.\n", saved_filename);
xfree (saved_filename);
saved_filename = NULL;
}
static void
set_logging_command (char *args, int from_tty)
{
printf_unfiltered ("\"set logging\" lets you log output to a file.\n");
printf_unfiltered ("Usage: set logging on [FILENAME]\n");
printf_unfiltered (" set logging off\n");
printf_unfiltered (" set logging file FILENAME\n");
printf_unfiltered (" set logging overwrite [on|off]\n");
printf_unfiltered (" set logging redirect [on|off]\n");
}
void
show_logging_command (char *args, int from_tty)
{
if (saved_filename)
printf_unfiltered ("Currently logging to \"%s\".\n", saved_filename);
if (saved_filename == NULL
|| strcmp (logging_filename, saved_filename) != 0)
printf_unfiltered ("Future logs will be written to %s.\n",
logging_filename);
if (logging_overwrite)
printf_unfiltered ("Logs will overwrite the log file.\n");
else
printf_unfiltered ("Logs will be appended to the log file.\n");
if (logging_redirect)
printf_unfiltered ("Output will be sent only to the log file.\n");
else
printf_unfiltered ("Output will be logged and displayed.\n");
}
void
_initialize_cli_logging (void)
{
static struct cmd_list_element *set_logging_cmdlist, *show_logging_cmdlist;
add_prefix_cmd ("logging", class_support, set_logging_command,
"Set logging options", &set_logging_cmdlist,
"set logging ", 0, &setlist);
add_prefix_cmd ("logging", class_support, show_logging_command,
"Show logging options", &show_logging_cmdlist,
"show logging ", 0, &showlist);
add_setshow_boolean_cmd ("overwrite", class_support, &logging_overwrite,
"Set whether logging overwrites or appends "
"to the log file.\n",
"Show whether logging overwrites or appends "
"to the log file.\n",
NULL, NULL, &set_logging_cmdlist, &show_logging_cmdlist);
add_setshow_boolean_cmd ("redirect", class_support, &logging_redirect,
"Set the logging output mode.\n"
"If redirect is off, output will go to both the "
"screen and the log file.\n"
"If redirect is on, output will go only to the log "
"file.",
"Show the logging output mode.\n"
"If redirect is off, output will go to both the "
"screen and the log file.\n"
"If redirect is on, output will go only to the log "
"file.",
NULL, NULL, &set_logging_cmdlist, &show_logging_cmdlist);
add_setshow_cmd ("file", class_support, var_filename, &logging_filename,
"Set the current logfile.", "Show the current logfile.",
NULL, NULL, &set_logging_cmdlist, &show_logging_cmdlist);
add_cmd ("on", class_support, set_logging_on,
"Enable logging.", &set_logging_cmdlist);
add_cmd ("off", class_support, set_logging_off,
"Disable logging.", &set_logging_cmdlist);
logging_filename = xstrdup ("gdb.txt");
}

View file

@ -27,23 +27,15 @@
#include <ctype.h>
#include "ui-out.h"
#include "gdb_string.h"
#include "top.h"
#include "cli/cli-cmds.h"
#include "cli/cli-decode.h"
#include "cli/cli-script.h"
/* From gdb/top.c */
extern void dont_repeat (void);
extern void do_restore_instream_cleanup (void *stream);
/* Prototypes for local functions */
static struct cleanup *
make_cleanup_free_command_lines (struct command_line **arg);
static enum command_control_type
recurse_read_control_structure (struct command_line *current_cmd);
@ -213,14 +205,58 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
} /* while (list) */
}
/* Handle pre-post hooks. */
static void
clear_hook_in_cleanup (void *data)
{
struct cmd_list_element *c = data;
c->hook_in = 0; /* Allow hook to work again once it is complete */
}
void
execute_cmd_pre_hook (struct cmd_list_element *c)
{
if ((c->hook_pre) && (!c->hook_in))
{
struct cleanup *cleanups = make_cleanup (clear_hook_in_cleanup, c);
c->hook_in = 1; /* Prevent recursive hooking */
execute_user_command (c->hook_pre, (char *) 0);
do_cleanups (cleanups);
}
}
void
execute_cmd_post_hook (struct cmd_list_element *c)
{
if ((c->hook_post) && (!c->hook_in))
{
struct cleanup *cleanups = make_cleanup (clear_hook_in_cleanup, c);
c->hook_in = 1; /* Prevent recursive hooking */
execute_user_command (c->hook_post, (char *) 0);
do_cleanups (cleanups);
}
}
/* Execute the command in CMD. */
static void
do_restore_user_call_depth (void * call_depth)
{
int * depth = call_depth;
/* We will be returning_to_top_level() at this point, so we want to
reset our depth. */
(*depth) = 0;
}
void
execute_user_command (struct cmd_list_element *c, char *args)
{
register struct command_line *cmdlines;
struct command_line *cmdlines;
struct cleanup *old_chain;
enum command_control_type ret;
static int user_call_depth = 0;
extern int max_user_call_depth;
old_chain = setup_user_args (args);
@ -229,6 +265,11 @@ execute_user_command (struct cmd_list_element *c, char *args)
/* Null command */
return;
if (++user_call_depth > max_user_call_depth)
error ("Max user call depth exceeded -- command aborted\n");
old_chain = make_cleanup (do_restore_user_call_depth, &user_call_depth);
/* Set the instream to 0, indicating execution of a
user-defined function. */
old_chain = make_cleanup (do_restore_instream_cleanup, instream);
@ -244,6 +285,8 @@ execute_user_command (struct cmd_list_element *c, char *args)
cmdlines = cmdlines->next;
}
do_cleanups (old_chain);
user_call_depth--;
}
enum command_control_type
@ -251,21 +294,25 @@ execute_control_command (struct command_line *cmd)
{
struct expression *expr;
struct command_line *current;
struct cleanup *old_chain = 0;
struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
struct value *val;
struct value *val_mark;
int loop;
enum command_control_type ret;
char *new_line;
/* Start by assuming failure, if a problem is detected, the code
below will simply "break" out of the switch. */
ret = invalid_control;
switch (cmd->control_type)
{
case simple_control:
/* A simple command, execute it and return. */
new_line = insert_args (cmd->line);
if (!new_line)
return invalid_control;
old_chain = make_cleanup (free_current_contents, &new_line);
break;
make_cleanup (free_current_contents, &new_line);
execute_command (new_line, 0);
ret = cmd->control_type;
break;
@ -282,8 +329,8 @@ execute_control_command (struct command_line *cmd)
/* Parse the loop control expression for the while statement. */
new_line = insert_args (cmd->line);
if (!new_line)
return invalid_control;
old_chain = make_cleanup (free_current_contents, &new_line);
break;
make_cleanup (free_current_contents, &new_line);
expr = parse_expression (new_line);
make_cleanup (free_current_contents, &expr);
@ -342,8 +389,8 @@ execute_control_command (struct command_line *cmd)
{
new_line = insert_args (cmd->line);
if (!new_line)
return invalid_control;
old_chain = make_cleanup (free_current_contents, &new_line);
break;
make_cleanup (free_current_contents, &new_line);
/* Parse the conditional for the if statement. */
expr = parse_expression (new_line);
make_cleanup (free_current_contents, &expr);
@ -381,11 +428,10 @@ execute_control_command (struct command_line *cmd)
default:
warning ("Invalid control type in command structure.");
return invalid_control;
break;
}
if (old_chain)
do_cleanups (old_chain);
do_cleanups (old_chain);
return ret;
}
@ -928,8 +974,8 @@ read_command_lines (char *prompt_arg, int from_tty)
void
free_command_lines (struct command_line **lptr)
{
register struct command_line *l = *lptr;
register struct command_line *next;
struct command_line *l = *lptr;
struct command_line *next;
struct command_line **blist;
int i;
@ -955,16 +1001,46 @@ do_free_command_lines_cleanup (void *arg)
free_command_lines (arg);
}
static struct cleanup *
struct cleanup *
make_cleanup_free_command_lines (struct command_line **arg)
{
return make_cleanup (do_free_command_lines_cleanup, arg);
}
struct command_line *
copy_command_lines (struct command_line *cmds)
{
struct command_line *result = NULL;
if (cmds)
{
result = (struct command_line *) xmalloc (sizeof (struct command_line));
result->next = copy_command_lines (cmds->next);
result->line = xstrdup (cmds->line);
result->control_type = cmds->control_type;
result->body_count = cmds->body_count;
if (cmds->body_count > 0)
{
int i;
result->body_list = (struct command_line **)
xmalloc (sizeof (struct command_line *) * cmds->body_count);
for (i = 0; i < cmds->body_count; i++)
result->body_list[i] = copy_command_lines (cmds->body_list[i]);
}
else
result->body_list = NULL;
}
return result;
}
static void
validate_comname (char *comname)
{
register char *p;
char *p;
if (comname == 0)
error_no_arg ("name of command to define");
@ -994,8 +1070,8 @@ define_command (char *comname, int from_tty)
CMD_PRE_HOOK,
CMD_POST_HOOK
};
register struct command_line *cmds;
register struct cmd_list_element *c, *newc, *oldc, *hookc = 0;
struct command_line *cmds;
struct cmd_list_element *c, *newc, *oldc, *hookc = 0;
char *tem = comname;
char *tem2;
char tmpbuf[MAX_TMPBUF];
@ -1011,16 +1087,17 @@ define_command (char *comname, int from_tty)
/* Look it up, and verify that we got an exact match. */
c = lookup_cmd (&tem, cmdlist, "", -1, 1);
if (c && !STREQ (comname, c->name))
if (c && strcmp (comname, c->name) != 0)
c = 0;
if (c)
{
int q;
if (c->class == class_user || c->class == class_alias)
tem = "Redefine command \"%s\"? ";
q = query ("Redefine command \"%s\"? ", c->name);
else
tem = "Really redefine built-in command \"%s\"? ";
if (!query (tem, c->name))
q = query ("Really redefine built-in command \"%s\"? ", c->name);
if (!q)
error ("Command \"%s\" not redefined.", c->name);
}
@ -1044,7 +1121,7 @@ define_command (char *comname, int from_tty)
/* Look up cmd it hooks, and verify that we got an exact match. */
tem = comname + hook_name_size;
hookc = lookup_cmd (&tem, cmdlist, "", -1, 0);
if (hookc && !STREQ (comname + hook_name_size, hookc->name))
if (hookc && strcmp (comname + hook_name_size, hookc->name) != 0)
hookc = 0;
if (!hookc)
{
@ -1099,7 +1176,7 @@ void
document_command (char *comname, int from_tty)
{
struct command_line *doclines;
register struct cmd_list_element *c;
struct cmd_list_element *c;
char *tem = comname;
char tmpbuf[128];
@ -1117,8 +1194,8 @@ document_command (char *comname, int from_tty)
xfree (c->doc);
{
register struct command_line *cl1;
register int len = 0;
struct command_line *cl1;
int len = 0;
for (cl1 = doclines; cl1; cl1 = cl1->next)
len += strlen (cl1->line) + 1;
@ -1146,7 +1223,7 @@ struct source_cleanup_lines_args
};
static void
source_cleanup_lines (PTR args)
source_cleanup_lines (void *args)
{
struct source_cleanup_lines_args *p =
(struct source_cleanup_lines_args *) args;
@ -1156,7 +1233,6 @@ source_cleanup_lines (PTR args)
error_pre_print = p->old_error_pre_print;
}
/* ARGSUSED */
static void
do_fclose_cleanup (void *stream)
{
@ -1213,7 +1289,7 @@ script_from_file (FILE *stream, char *file)
void
show_user_1 (struct cmd_list_element *c, struct ui_file *stream)
{
register struct command_line *cmdlines;
struct command_line *cmdlines;
cmdlines = c->user_commands;
if (!cmdlines)

View file

@ -19,6 +19,10 @@
#if !defined (CLI_SCRIPT_H)
#define CLI_SCRIPT_H 1
struct ui_file;
struct command_line;
struct cmd_list_element;
/* Exported to cli/cli-cmds.c */
extern void script_from_file (FILE *stream, char *file);
@ -41,6 +45,10 @@ extern enum command_control_type
extern void print_command_lines (struct ui_out *,
struct command_line *, unsigned int);
extern struct command_line * copy_command_lines (struct command_line *cmds);
struct cleanup *make_cleanup_free_command_lines (struct command_line **arg);
/* Exported to gdb/infrun.c */
extern void execute_user_command (struct cmd_list_element *c, char *args);

View file

@ -1,6 +1,6 @@
/* Handle set and show GDB commands.
Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
Copyright 2000, 2001, 2002, 2003 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
@ -18,11 +18,10 @@
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "readline/tilde.h"
#include "value.h"
#include <ctype.h>
#if 0
#include "gdb_string.h"
#endif
#include "ui-out.h"
@ -34,9 +33,8 @@
static int parse_binary_operation (char *);
static enum cmd_auto_boolean parse_auto_binary_operation (const char *arg);
static enum cmd_auto_boolean
static enum auto_boolean
parse_auto_binary_operation (const char *arg)
{
if (arg != NULL && *arg != '\0')
@ -48,18 +46,18 @@ parse_auto_binary_operation (const char *arg)
|| strncmp (arg, "1", length) == 0
|| strncmp (arg, "yes", length) == 0
|| strncmp (arg, "enable", length) == 0)
return CMD_AUTO_BOOLEAN_TRUE;
return AUTO_BOOLEAN_TRUE;
else if (strncmp (arg, "off", length) == 0
|| strncmp (arg, "0", length) == 0
|| strncmp (arg, "no", length) == 0
|| strncmp (arg, "disable", length) == 0)
return CMD_AUTO_BOOLEAN_FALSE;
return AUTO_BOOLEAN_FALSE;
else if (strncmp (arg, "auto", length) == 0
|| (strncmp (arg, "-1", length) == 0 && length > 1))
return CMD_AUTO_BOOLEAN_AUTO;
return AUTO_BOOLEAN_AUTO;
}
error ("\"on\", \"off\" or \"auto\" expected.");
return CMD_AUTO_BOOLEAN_AUTO; /* pacify GCC */
return AUTO_BOOLEAN_AUTO; /* pacify GCC */
}
static int
@ -167,7 +165,7 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
*(int *) c->var = parse_binary_operation (arg);
break;
case var_auto_boolean:
*(enum cmd_auto_boolean *) c->var = parse_auto_binary_operation (arg);
*(enum auto_boolean *) c->var = parse_auto_binary_operation (arg);
break;
case var_uinteger:
if (arg == NULL)
@ -215,7 +213,7 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
strcat (msg, c->enums[i]);
}
strcat (msg, ".");
error (msg);
error ("%s", msg);
}
p = strchr (arg, ' ');
@ -296,15 +294,15 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
fputs_filtered (*(int *) c->var ? "on" : "off", stb->stream);
break;
case var_auto_boolean:
switch (*(enum cmd_auto_boolean*) c->var)
switch (*(enum auto_boolean*) c->var)
{
case CMD_AUTO_BOOLEAN_TRUE:
case AUTO_BOOLEAN_TRUE:
fputs_filtered ("on", stb->stream);
break;
case CMD_AUTO_BOOLEAN_FALSE:
case AUTO_BOOLEAN_FALSE:
fputs_filtered ("off", stb->stream);
break;
case CMD_AUTO_BOOLEAN_AUTO:
case AUTO_BOOLEAN_AUTO:
fputs_filtered ("auto", stb->stream);
break;
default:
@ -355,28 +353,35 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
void
cmd_show_list (struct cmd_list_element *list, int from_tty, char *prefix)
{
ui_out_tuple_begin (uiout, "showlist");
struct cleanup *showlist_chain;
showlist_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "showlist");
for (; list != NULL; list = list->next)
{
/* If we find a prefix, run its list, prefixing our output by its
prefix (with "show " skipped). */
if (list->prefixlist && !list->abbrev_flag)
{
ui_out_tuple_begin (uiout, "optionlist");
struct cleanup *optionlist_chain
= make_cleanup_ui_out_tuple_begin_end (uiout, "optionlist");
ui_out_field_string (uiout, "prefix", list->prefixname + 5);
cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5);
ui_out_tuple_end (uiout);
/* Close the tuple. */
do_cleanups (optionlist_chain);
}
if (list->type == show_cmd)
{
ui_out_tuple_begin (uiout, "option");
struct cleanup *option_chain
= make_cleanup_ui_out_tuple_begin_end (uiout, "option");
ui_out_text (uiout, prefix);
ui_out_field_string (uiout, "name", list->name);
ui_out_text (uiout, ": ");
do_setshow_command ((char *) NULL, from_tty, list);
ui_out_tuple_end (uiout);
/* Close the tuple. */
do_cleanups (option_chain);
}
}
ui_out_tuple_end (uiout);
/* Close the tuple. */
do_cleanups (showlist_chain);
}

View file

@ -19,6 +19,8 @@
#if !defined (CLI_SETSHOW_H)
#define CLI_SETSHOW_H 1
struct cmd_list_element;
/* Exported to cli/cli-cmds.c and gdb/top.c */
/* Do a "set" or "show" command. ARG is NULL if no argument, or the text

View file

@ -0,0 +1,346 @@
/* Read the export table symbols from a portable executable and
convert to internal format, for GDB. Used as a last resort if no
debugging symbols recognized.
Copyright 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */
#include "coff-pe-read.h"
#include "bfd.h"
#include "defs.h"
#include "gdbtypes.h"
#include "symtab.h"
#include "symfile.h"
#include "objfiles.h"
/* Internal section information */
struct read_pe_section_data
{
CORE_ADDR vma_offset; /* Offset to loaded address of section. */
unsigned long rva_start; /* Start offset within the pe. */
unsigned long rva_end; /* End offset within the pe. */
enum minimal_symbol_type ms_type; /* Type to assign symbols in section. */
};
#define PE_SECTION_INDEX_TEXT 0
#define PE_SECTION_INDEX_DATA 1
#define PE_SECTION_INDEX_BSS 2
#define PE_SECTION_TABLE_SIZE 3
#define PE_SECTION_INDEX_INVALID -1
/* Get the index of the named section in our own array, which contains
text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
if passed an unrecognised section name. */
static int
read_pe_section_index (const char *section_name)
{
if (strcmp (section_name, ".text") == 0)
{
return PE_SECTION_INDEX_TEXT;
}
else if (strcmp (section_name, ".data") == 0)
{
return PE_SECTION_INDEX_DATA;
}
else if (strcmp (section_name, ".bss") == 0)
{
return PE_SECTION_INDEX_BSS;
}
else
{
return PE_SECTION_INDEX_INVALID;
}
}
/* Record the virtual memory address of a section. */
static void
get_section_vmas (bfd *abfd, asection *sectp, void *context)
{
struct read_pe_section_data *sections = context;
int sectix = read_pe_section_index (sectp->name);
if (sectix != PE_SECTION_INDEX_INVALID)
{
/* Data within the section start at rva_start in the pe and at
bfd_get_section_vma() within memory. Store the offset. */
sections[sectix].vma_offset
= bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start;
}
}
/* Create a minimal symbol entry for an exported symbol. */
static void
add_pe_exported_sym (char *sym_name,
unsigned long func_rva,
const struct read_pe_section_data *section_data,
const char *dll_name, struct objfile *objfile)
{
/* Add the stored offset to get the loaded address of the symbol. */
CORE_ADDR vma = func_rva + section_data->vma_offset;
char *qualified_name = 0;
int dll_name_len = strlen (dll_name);
int count;
/* Generate a (hopefully unique) qualified name using the first part
of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
used by windbg from the "Microsoft Debugging Tools for Windows". */
qualified_name = xmalloc (dll_name_len + strlen (sym_name) + 2);
strncpy (qualified_name, dll_name, dll_name_len);
qualified_name[dll_name_len] = '!';
strcpy (qualified_name + dll_name_len + 1, sym_name);
prim_record_minimal_symbol (qualified_name,
vma, section_data->ms_type, objfile);
xfree (qualified_name);
/* Enter the plain name as well, which might not be unique. */
prim_record_minimal_symbol (sym_name, vma, section_data->ms_type, objfile);
}
/* Truncate a dll_name at the first dot character. */
static void
read_pe_truncate_name (char *dll_name)
{
while (*dll_name)
{
if ((*dll_name) == '.')
{
*dll_name = '\0'; /* truncates and causes loop exit. */
}
else
{
++dll_name;
}
}
}
/* Low-level support functions, direct from the ld module pe-dll.c. */
static unsigned int
pe_get16 (bfd *abfd, int where)
{
unsigned char b[2];
bfd_seek (abfd, (file_ptr) where, SEEK_SET);
bfd_bread (b, (bfd_size_type) 2, abfd);
return b[0] + (b[1] << 8);
}
static unsigned int
pe_get32 (bfd *abfd, int where)
{
unsigned char b[4];
bfd_seek (abfd, (file_ptr) where, SEEK_SET);
bfd_bread (b, (bfd_size_type) 4, abfd);
return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
}
static unsigned int
pe_as32 (void *ptr)
{
unsigned char *b = ptr;
return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
}
/* Read the (non-debug) export symbol table from a portable
executable. Code originally lifted from the ld function
pe_implied_import_dll in pe-dll.c. */
void
read_pe_exported_syms (struct objfile *objfile)
{
bfd *dll = objfile->obfd;
unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
unsigned long export_rva, export_size, nsections, secptr, expptr;
unsigned long exp_funcbase;
unsigned char *expdata, *erva;
unsigned long name_rvas, ordinals, nexp, ordbase;
char *dll_name;
/* Array elements are for text, data and bss in that order
Initialization with start_rva > end_rva guarantees that
unused sections won't be matched. */
struct read_pe_section_data section_data[PE_SECTION_TABLE_SIZE]
= { {0, 1, 0, mst_text},
{0, 1, 0, mst_data},
{0, 1, 0, mst_bss}
};
struct cleanup *back_to = 0;
char const *target = bfd_get_target (objfile->obfd);
if ((strcmp (target, "pe-i386") != 0) && (strcmp (target, "pei-i386") != 0))
{
/* This is not an i386 format file. Abort now, because the code
is untested on anything else. *FIXME* test on further
architectures and loosen or remove this test. */
return;
}
/* Get pe_header, optional header and numbers of export entries. */
pe_header_offset = pe_get32 (dll, 0x3c);
opthdr_ofs = pe_header_offset + 4 + 20;
num_entries = pe_get32 (dll, opthdr_ofs + 92);
if (num_entries < 1) /* No exports. */
{
return;
}
export_rva = pe_get32 (dll, opthdr_ofs + 96);
export_size = pe_get32 (dll, opthdr_ofs + 100);
nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
secptr = (pe_header_offset + 4 + 20 +
pe_get16 (dll, pe_header_offset + 4 + 16));
expptr = 0;
/* Get the rva and size of the export section. */
for (i = 0; i < nsections; i++)
{
char sname[8];
unsigned long secptr1 = secptr + 40 * i;
unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
unsigned long vsize = pe_get32 (dll, secptr1 + 16);
unsigned long fptr = pe_get32 (dll, secptr1 + 20);
bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
bfd_bread (sname, (bfd_size_type) 8, dll);
if (vaddr <= export_rva && vaddr + vsize > export_rva)
{
expptr = fptr + (export_rva - vaddr);
if (export_rva + export_size > vaddr + vsize)
export_size = vsize - (export_rva - vaddr);
break;
}
}
if (export_size == 0)
{
/* Empty export table. */
return;
}
/* Scan sections and store the base and size of the relevant sections. */
for (i = 0; i < nsections; i++)
{
unsigned long secptr1 = secptr + 40 * i;
unsigned long vsize = pe_get32 (dll, secptr1 + 8);
unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
unsigned long flags = pe_get32 (dll, secptr1 + 36);
char sec_name[9];
int sectix;
sec_name[8] = '\0';
bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
bfd_bread (sec_name, (bfd_size_type) 8, dll);
sectix = read_pe_section_index (sec_name);
if (sectix != PE_SECTION_INDEX_INVALID)
{
section_data[sectix].rva_start = vaddr;
section_data[sectix].rva_end = vaddr + vsize;
}
}
expdata = (unsigned char *) xmalloc (export_size);
back_to = make_cleanup (xfree, expdata);
bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
bfd_bread (expdata, (bfd_size_type) export_size, dll);
erva = expdata - export_rva;
nexp = pe_as32 (expdata + 24);
name_rvas = pe_as32 (expdata + 32);
ordinals = pe_as32 (expdata + 36);
ordbase = pe_as32 (expdata + 16);
exp_funcbase = pe_as32 (expdata + 28);
/* Use internal dll name instead of full pathname. */
dll_name = pe_as32 (expdata + 12) + erva;
bfd_map_over_sections (dll, get_section_vmas, section_data);
/* Adjust the vma_offsets in case this PE got relocated. This
assumes that *all* sections share the same relocation offset
as the text section. */
for (i = 0; i < PE_SECTION_TABLE_SIZE; i++)
{
section_data[i].vma_offset
+= ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
}
printf_filtered ("Minimal symbols from %s...", dll_name);
wrap_here ("");
/* Truncate name at first dot. Should maybe also convert to all
lower case for convenience on Windows. */
read_pe_truncate_name (dll_name);
/* Iterate through the list of symbols. */
for (i = 0; i < nexp; i++)
{
/* Pointer to the names vector. */
unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
/* Pointer to the function address vector. */
unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4);
/* Find this symbol's section in our own array. */
int sectix = 0;
for (sectix = 0; sectix < PE_SECTION_TABLE_SIZE; ++sectix)
{
if ((func_rva >= section_data[sectix].rva_start)
&& (func_rva < section_data[sectix].rva_end))
{
add_pe_exported_sym (erva + name_rva,
func_rva,
section_data + sectix, dll_name, objfile);
break;
}
}
}
/* discard expdata. */
do_cleanups (back_to);
}

View file

@ -0,0 +1,32 @@
/* Interface to coff-pe-read.c (portable-executable-specific symbol reader).
Copyright 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */
#if !defined (COFF_PE_READ_H)
#define COFF_PE_READ_H
struct objfile;
/* Read the export table and convert it to minimal symbol table entries */
extern void read_pe_exported_syms (struct objfile *objfile);
#endif /* !defined (COFF_PE_READ_H) */

View file

@ -1,13 +1,7 @@
/* ***DEPRECATED*** The gdblib files must not be calling/using things in any
of the possible command languages. If necessary, a hook (that may be
present or not) must be used and set to the appropriate routine by any
command language that cares about it. If you are having to include this
file you are possibly doing things the old way. This file will disapear.
2000-12-01 fnasser@redhat.com */
/* Header file for command-reading library command.c.
Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000
Free Software Foundation, Inc.
Copyright 1986, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1999,
2000, 2002 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
@ -44,6 +38,8 @@ enum command_class
class_pseudo, class_tui, class_xdb
};
/* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum
cmd_types'' can be moved from "command.h" to "cli-decode.h". */
/* 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. */
@ -55,14 +51,6 @@ typedef enum cmd_types
}
cmd_types;
/* Reasonable values for an AUTO_BOOLEAN variable. */
enum cmd_auto_boolean
{
CMD_AUTO_BOOLEAN_TRUE,
CMD_AUTO_BOOLEAN_FALSE,
CMD_AUTO_BOOLEAN_AUTO
};
/* Types of "set" or "show" command. */
typedef enum var_types
{
@ -71,9 +59,9 @@ typedef enum var_types
var_boolean,
/* "on" / "true" / "enable" or "off" / "false" / "disable" or
"auto. *VAR is an ``enum cmd_auto_boolean''. NOTE: In general
a custom show command will need to be implemented - one that
for "auto" prints both the "auto" and the current auto-selected
"auto. *VAR is an ``enum auto_boolean''. NOTE: In general a
custom show command will need to be implemented - one that for
"auto" prints both the "auto" and the current auto-selected
value. */
var_auto_boolean,
@ -105,156 +93,7 @@ typedef enum var_types
var_types;
/* This structure records one command'd definition. */
/* This flag is used by the code executing commands to warn the user
the first time a deprecated command is used, see the 'flags' field in
the following struct.
*/
#define CMD_DEPRECATED 0x1
#define DEPRECATED_WARN_USER 0x2
#define MALLOCED_REPLACEMENT 0x4
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. NULL for command class
names and for help topics that are not really commands. NOTE:
cagney/2002-02-02: This function signature is evolving. For
the moment suggest sticking with either set_cmd_cfunc() or
set_cmd_sfunc(). */
void (*func) (struct cmd_list_element *c, char *args, int from_tty);
/* The command's real callback. At present func() bounces through
to one of the below. */
union
{
/* If type is not_set_cmd, call it like this: */
void (*cfunc) (char *args, int from_tty);
/* If type is set_cmd or show_cmd, first set the variables, and
then call this. */
void (*sfunc) (char *args, int from_tty, struct cmd_list_element * c);
}
function;
/* 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;
/* flags : a bitfield
bit 0: (LSB) CMD_DEPRECATED, when 1 indicated that this command
is deprecated. It may be removed from gdb's command set in the
future.
bit 1: DEPRECATED_WARN_USER, the user needs to be warned that
this is a deprecated command. The user should only be warned
the first time a command is used.
bit 2: MALLOCED_REPLACEMENT, when functions are deprecated at
compile time (this is the way it should, in general, be done)
the memory containing the replacement string is statically
allocated. In some cases it makes sense to deprecate commands
at runtime (the testsuite is one example). In this case the
memory for replacement is malloc'ed. When a command is
undeprecated or re-deprecated at runtime we don't want to risk
calling free on statically allocated memory, so we check this
flag.
*/
int flags;
/* if this command is deprecated, this is the replacement name */
char *replacement;
/* If this command represents a show command, then this function
is called before the variable's value is examined. */
void (*pre_show_hook) (struct cmd_list_element *c);
/* Hook for another command to be executed before this command. */
struct cmd_list_element *hook_pre;
/* Hook for another command to be executed after this command. */
struct cmd_list_element *hook_post;
/* Flag that specifies if this command is already running it's hook. */
/* Prevents the possibility of hook recursion. */
int hook_in;
/* 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. TEXT is the text beyond
what was matched for the command itself (leading whitespace is
skipped). It stops where we are supposed to stop completing
(rl_point) and is '\0' terminated.
Return value is a malloc'd vector of pointers to possible completions
terminated with NULL. If there are no completions, returning a pointer
to a NULL would work but returning NULL itself is also valid.
WORD points in the same buffer as TEXT, and completions should be
returned relative to this position. For example, suppose TEXT is "foo"
and we want to complete to "foobar". If WORD is "oo", return
"oobar"; if WORD is "baz/foo", return "baz/foobar". */
char **(*completer) (char *text, char *word);
/* 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. */
void *var;
/* What kind of variable is *VAR? */
var_types var_type;
/* Pointer to NULL terminated list of enumerated values (like argv). */
const char **enums;
/* Pointer to command strings of user-defined commands */
struct command_line *user_commands;
/* Pointer to command that is hooked by this one, (by hook_pre)
so the hook can be removed when this one is deleted. */
struct cmd_list_element *hookee_pre;
/* Pointer to command that is hooked by this one, (by hook_post)
so the hook can be removed when this one is deleted. */
struct cmd_list_element *hookee_post;
/* Pointer to command that is aliased by this one, so the
aliased command can be located in case it has been hooked. */
struct cmd_list_element *cmd_pointer;
};
struct cmd_list_element;
/* Forward-declarations of the entry-points of cli/cli-decode.c. */
@ -285,18 +124,46 @@ extern struct cmd_list_element *add_abbrev_prefix_cmd (char *,
/* Set the commands corresponding callback. */
typedef void cmd_cfunc_ftype (char *args, int from_tty);
extern void set_cmd_cfunc (struct cmd_list_element *cmd,
void (*cfunc) (char *args, int from_tty));
cmd_cfunc_ftype *cfunc);
typedef void cmd_sfunc_ftype (char *args, int from_tty,
struct cmd_list_element *c);
extern void set_cmd_sfunc (struct cmd_list_element *cmd,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element * c));
cmd_sfunc_ftype *sfunc);
extern void set_cmd_completer (struct cmd_list_element *cmd,
char **(*completer) (char *text, char *word));
/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
around in cmd objects to test the value of the commands sfunc(). */
extern int cmd_cfunc_eq (struct cmd_list_element *cmd,
void (*cfunc) (char *args, int from_tty));
/* Each command object has a local context attached to it. . */
extern void set_cmd_context (struct cmd_list_element *cmd, void *context);
extern void *get_cmd_context (struct cmd_list_element *cmd);
/* Execute CMD's pre/post hook. Throw an error if the command fails.
If already executing this pre/post hook, or there is no pre/post
hook, the call is silently ignored. */
extern void execute_cmd_pre_hook (struct cmd_list_element *cmd);
extern void execute_cmd_post_hook (struct cmd_list_element *cmd);
/* Return the type of the command. */
/* NOTE: cagney/2002-03-17: The add_show_from_set() function clones
the set command passed as a parameter. The clone operation will
include (BUG?) any ``set'' command callback, if present. Commands
like ``info set'' call all the ``show'' command callbacks.
Unfortunately, for ``show'' commands cloned from ``set'', this
includes callbacks belonging to ``set'' commands. Making this
worse, this only occures if add_show_from_set() is called after
add_cmd_sfunc() (BUG?). */
extern enum cmd_types cmd_type (struct cmd_list_element *cmd);
extern struct cmd_list_element *lookup_cmd (char **,
struct cmd_list_element *, char *,
int, int);
@ -343,6 +210,26 @@ extern void help_list (struct cmd_list_element *, char *,
extern void help_cmd_list (struct cmd_list_element *, enum command_class,
char *, int, struct ui_file *);
extern void add_setshow_cmd (char *name,
enum command_class class,
var_types var_type, void *var,
char *set_doc, char *show_doc,
cmd_sfunc_ftype *set_func,
cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list);
extern void add_setshow_cmd_full (char *name,
enum command_class class,
var_types var_type, void *var,
char *set_doc, char *show_doc,
cmd_sfunc_ftype *set_func,
cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list,
struct cmd_list_element **set_result,
struct cmd_list_element **show_result);
extern struct cmd_list_element *add_set_cmd (char *name, enum
command_class class,
var_types var_type, void *var,
@ -356,17 +243,34 @@ extern struct cmd_list_element *add_set_enum_cmd (char *name,
char *doc,
struct cmd_list_element **list);
extern struct cmd_list_element *add_set_auto_boolean_cmd (char *name,
enum command_class class,
enum cmd_auto_boolean *var,
char *doc,
struct cmd_list_element **list);
extern void add_setshow_auto_boolean_cmd (char *name,
enum command_class class,
enum auto_boolean *var,
char *set_doc, char *show_doc,
cmd_sfunc_ftype *set_func,
cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list);
extern struct cmd_list_element *add_set_boolean_cmd (char *name,
enum command_class class,
int *var,
char *doc,
struct cmd_list_element **list);
extern void add_setshow_boolean_cmd (char *name,
enum command_class class,
int *var,
char *set_doc,
char *show_doc,
cmd_sfunc_ftype *set_func,
cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list);
extern void add_setshow_uinteger_cmd (char *name,
enum command_class class,
unsigned int *var,
char *set_doc,
char *show_doc,
cmd_sfunc_ftype *set_func,
cmd_sfunc_ftype *show_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list);
extern struct cmd_list_element *add_show_from_set (struct cmd_list_element *,
struct cmd_list_element
@ -386,4 +290,10 @@ extern void dont_repeat (void);
extern void not_just_help_class_command (char *, int);
/* check function pointer */
extern int cmd_func_p (struct cmd_list_element *cmd);
/* call the command function */
extern void cmd_func (struct cmd_list_element *cmd, char *args, int from_tty);
#endif /* !defined (COMMAND_H) */

View file

@ -1,6 +1,7 @@
/* Support for complaint handling during symbol reading in GDB.
Copyright 1990, 1991, 1992, 1993, 1995, 1998, 1999, 2000
Free Software Foundation, Inc.
Copyright 1990, 1991, 1992, 1993, 1995, 1998, 1999, 2000, 2002 Free
Software Foundation, Inc.
This file is part of GDB.
@ -21,148 +22,300 @@
#include "defs.h"
#include "complaints.h"
#include "gdb_assert.h"
#include "command.h"
#include "gdbcmd.h"
extern void _initialize_complaints (void);
/* Structure to manage complaints about symbol file contents. */
/* Should each complaint message be self explanatory, or should we assume that
a series of complaints is being produced? */
struct complaint complaint_root[1] =
{
{
(char *) NULL, /* Complaint message */
0, /* Complaint counter */
complaint_root /* Next complaint. */
}
/* case 1: First message of a series that must
start off with explanation. case 2: Subsequent message of a series
that needs no explanation (the user already knows we have a problem
so we can just state our piece). */
enum complaint_series {
/* Isolated self explanatory message. */
ISOLATED_MESSAGE,
/* First message of a series, includes an explanation. */
FIRST_MESSAGE,
/* First message of a series, but does not need to include any sort
of explanation. */
SHORT_FIRST_MESSAGE,
/* Subsequent message of a series that needs no explanation (the
user already knows we have a problem so we can just state our
piece). */
SUBSEQUENT_MESSAGE
};
/* How many complaints about a particular thing should be printed before
we stop whining about it? Default is no whining at all, since so many
systems have ill-constructed symbol files. */
/* Structure to manage complaints about symbol file contents. */
struct complain
{
const char *file;
int line;
const char *fmt;
int counter;
struct complain *next;
};
/* The explanatory message that should accompany the complaint. The
message is in two parts - pre and post - that are printed around
the complaint text. */
struct explanation
{
const char *prefix;
const char *postfix;
};
struct complaints
{
struct complain *root;
/* Should each complaint be self explanatory, or should we assume
that a series of complaints is being produced? case 0: Isolated
self explanatory message. case 1: First message of a series that
must start off with explanation. case 2: Subsequent message of a
series that needs no explanation (the user already knows we have
a problem so we can just state our piece). */
int series;
/* The explanatory messages that should accompany the complaint.
NOTE: cagney/2002-08-14: In a desperate attempt at being vaguely
i18n friendly, this is an array of two messages. When present,
the PRE and POST EXPLANATION[SERIES] are used to wrap the
message. */
const struct explanation *explanation;
};
static struct complain complaint_sentinel;
/* The symbol table complaint table. */
static struct explanation symfile_explanations[] = {
{ "During symbol reading, ", "." },
{ "During symbol reading...", "..."},
{ "", "..."},
{ "", "..."},
{ NULL, NULL }
};
static struct complaints symfile_complaint_book = {
&complaint_sentinel,
0,
symfile_explanations
};
struct complaints *symfile_complaints = &symfile_complaint_book;
/* Wrapper function to, on-demand, fill in a complaints object. */
static struct complaints *
get_complaints (struct complaints **c)
{
if ((*c) != NULL)
return (*c);
(*c) = XMALLOC (struct complaints);
(*c)->root = &complaint_sentinel;
(*c)->series = ISOLATED_MESSAGE;
(*c)->explanation = NULL;
return (*c);
}
static struct complain *
find_complaint (struct complaints *complaints, const char *file,
int line, const char *fmt)
{
struct complain *complaint;
/* Find the complaint in the table. A more efficient search
algorithm (based on hash table or something) could be used. But
that can wait until someone shows evidence that this lookup is
a real bottle neck. */
for (complaint = complaints->root;
complaint != NULL;
complaint = complaint->next)
{
if (complaint->fmt == fmt
&& complaint->file == file
&& complaint->line == line)
return complaint;
}
/* Oops not seen before, fill in a new complaint. */
complaint = XMALLOC (struct complain);
complaint->fmt = fmt;
complaint->file = file;
complaint->line = line;
complaint->counter = 0;
complaint->next = NULL;
/* File it, return it. */
complaint->next = complaints->root;
complaints->root = complaint;
return complaint;
}
/* How many complaints about a particular thing should be printed
before we stop whining about it? Default is no whining at all,
since so many systems have ill-constructed symbol files. */
static unsigned int stop_whining = 0;
/* Should each complaint be self explanatory, or should we assume that
a series of complaints is being produced?
case 0: self explanatory message.
case 1: First message of a series that must start off with explanation.
case 2: Subsequent message, when user already knows we are reading
symbols and we can just state our piece. */
/* Print a complaint, and link the complaint block into a chain for
later handling. */
static int complaint_series = 0;
/* Functions to handle complaints during symbol reading. */
/* Print a complaint about the input symbols, and link the complaint block
into a chain for later handling. */
void
complain (struct complaint *complaint,...)
static void
vcomplaint (struct complaints **c, const char *file, int line, const char *fmt,
va_list args)
{
va_list args;
va_start (args, complaint);
struct complaints *complaints = get_complaints (c);
struct complain *complaint = find_complaint (complaints, file, line, fmt);
enum complaint_series series;
gdb_assert (complaints != NULL);
complaint->counter++;
if (complaint->next == NULL)
{
complaint->next = complaint_root->next;
complaint_root->next = complaint;
}
if (complaint->counter > stop_whining)
return;
if (info_verbose)
series = SUBSEQUENT_MESSAGE;
else
series = complaints->series;
if (complaint->file != NULL)
internal_vwarning (complaint->file, complaint->line, complaint->fmt, args);
else if (warning_hook)
(*warning_hook) (complaint->fmt, args);
else
{
return;
if (complaints->explanation == NULL)
/* A [v]warning() call always appends a newline. */
vwarning (complaint->fmt, args);
else
{
char *msg;
struct cleanup *cleanups;
xvasprintf (&msg, complaint->fmt, args);
cleanups = make_cleanup (xfree, msg);
wrap_here ("");
if (series != SUBSEQUENT_MESSAGE)
begin_line ();
fprintf_filtered (gdb_stderr, "%s%s%s",
complaints->explanation[series].prefix, msg,
complaints->explanation[series].postfix);
/* Force a line-break after any isolated message. For the
other cases, clear_complaints() takes care of any missing
trailing newline, the wrap_here() is just a hint. */
if (series == ISOLATED_MESSAGE)
/* It would be really nice to use begin_line() here.
Unfortunately that function doesn't track GDB_STDERR and
consequently will sometimes supress a line when it
shouldn't. */
fputs_filtered ("\n", gdb_stderr);
else
wrap_here ("");
do_cleanups (cleanups);
}
}
wrap_here ("");
switch (complaint_series + (info_verbose << 1))
switch (series)
{
/* Isolated messages, must be self-explanatory. */
case 0:
if (warning_hook)
(*warning_hook) (complaint->message, args);
else
{
begin_line ();
fputs_filtered ("During symbol reading, ", gdb_stderr);
wrap_here ("");
vfprintf_filtered (gdb_stderr, complaint->message, args);
fputs_filtered (".\n", gdb_stderr);
}
case ISOLATED_MESSAGE:
break;
/* First of a series, without `set verbose'. */
case 1:
if (warning_hook)
(*warning_hook) (complaint->message, args);
else
{
begin_line ();
fputs_filtered ("During symbol reading...", gdb_stderr);
vfprintf_filtered (gdb_stderr, complaint->message, args);
fputs_filtered ("...", gdb_stderr);
wrap_here ("");
complaint_series++;
}
case FIRST_MESSAGE:
complaints->series = SUBSEQUENT_MESSAGE;
break;
case SUBSEQUENT_MESSAGE:
case SHORT_FIRST_MESSAGE:
complaints->series = SUBSEQUENT_MESSAGE;
break;
/* Subsequent messages of a series, or messages under `set verbose'.
(We'll already have produced a "Reading in symbols for XXX..."
message and will clean up at the end with a newline.) */
default:
if (warning_hook)
(*warning_hook) (complaint->message, args);
else
{
vfprintf_filtered (gdb_stderr, complaint->message, args);
fputs_filtered ("...", gdb_stderr);
wrap_here ("");
}
}
/* If GDB dumps core, we'd like to see the complaints first. Presumably
GDB will not be sending so many complaints that this becomes a
performance hog. */
/* If GDB dumps core, we'd like to see the complaints first.
Presumably GDB will not be sending so many complaints that this
becomes a performance hog. */
gdb_flush (gdb_stderr);
}
void
complaint (struct complaints **complaints, const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
vcomplaint (complaints, NULL/*file*/, 0/*line*/, fmt, args);
va_end (args);
}
/* Clear out all complaint counters that have ever been incremented.
If sym_reading is 1, be less verbose about successive complaints,
since the messages are appearing all together during a command that
reads symbols (rather than scattered around as psymtabs get fleshed
out into symtabs at random times). If noisy is 1, we are in a
noisy symbol reading command, and our caller will print enough
context for the user to figure it out. */
void
internal_complaint (struct complaints **complaints, const char *file,
int line, const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
vcomplaint (complaints, file, line, fmt, args);
va_end (args);
}
/* Clear out / initialize all complaint counters that have ever been
incremented. If LESS_VERBOSE is 1, be less verbose about
successive complaints, since the messages are appearing all
together during a command that is reporting a contiguous block of
complaints (rather than being interleaved with other messages). If
noisy is 1, we are in a noisy command, and our caller will print
enough context for the user to figure it out. */
void
clear_complaints (int sym_reading, int noisy)
clear_complaints (struct complaints **c, int less_verbose, int noisy)
{
struct complaint *p;
struct complaints *complaints = get_complaints (c);
struct complain *p;
for (p = complaint_root->next; p != complaint_root; p = p->next)
for (p = complaints->root; p != NULL; p = p->next)
{
p->counter = 0;
}
if (!sym_reading && !noisy && complaint_series > 1 && !warning_hook)
switch (complaints->series)
{
/* Terminate previous series, since caller won't. */
puts_filtered ("\n");
case FIRST_MESSAGE:
/* Haven't yet printed anything. */
break;
case SHORT_FIRST_MESSAGE:
/* Haven't yet printed anything. */
break;
case ISOLATED_MESSAGE:
/* The code above, always forces a line-break. No need to do it
here. */
break;
case SUBSEQUENT_MESSAGE:
/* It would be really nice to use begin_line() here.
Unfortunately that function doesn't track GDB_STDERR and
consequently will sometimes supress a line when it shouldn't. */
fputs_unfiltered ("\n", gdb_stderr);
break;
default:
internal_error (__FILE__, __LINE__, "bad switch");
}
complaint_series = sym_reading ? 1 + noisy : 0;
if (!less_verbose)
complaints->series = ISOLATED_MESSAGE;
else if (!noisy)
complaints->series = FIRST_MESSAGE;
else
complaints->series = SHORT_FIRST_MESSAGE;
}
void
_initialize_complaints (void)
{
add_show_from_set
(add_set_cmd ("complaints", class_support, var_zinteger,
(char *) &stop_whining,
"Set max number of complaints about incorrect symbols.",
&setlist),
&showlist);
add_setshow_cmd ("complaints", class_support, var_zinteger,
&stop_whining,
"Set max number of complaints about incorrect symbols.",
"Show max number of complaints about incorrect symbols.",
NULL, NULL,
&setlist, &showlist);
}

View file

@ -1,6 +1,7 @@
/* Definitions for complaint handling during symbol reading in GDB.
Copyright 1990, 1991, 1992, 1995, 1998, 2000
Free Software Foundation, Inc.
Copyright 1990, 1991, 1992, 1995, 1998, 2000, 2002 Free Software
Foundation, Inc.
This file is part of GDB.
@ -23,31 +24,30 @@
#if !defined (COMPLAINTS_H)
#define COMPLAINTS_H
/* Opaque object used to track the number of complaints of a
particular category. */
struct complaints;
/* Support for complaining about things in the symbol file that aren't
catastrophic.
/* Predefined categories. */
extern struct complaints *symfile_complaints;
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. */
/* Register a complaint. */
extern void complaint (struct complaints **complaints, const char *fmt,
...) ATTR_FORMAT (printf, 2, 3);
extern void internal_complaint (struct complaints **complaints,
const char *file, int line, const char *fmt,
...) ATTR_FORMAT (printf, 4, 5);
struct complaint
{
char *message;
unsigned counter;
struct complaint *next;
};
/* Clear out / initialize all complaint counters that have ever been
incremented. If LESS_VERBOSE is 1, be less verbose about
successive complaints, since the messages are appearing all
together during a command that is reporting a contiguous block of
complaints (rather than being interleaved with other messages). If
noisy is 1, we are in a noisy command, and our caller will print
enough context for the user to figure it out. */
/* 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 complaints.c) */
extern void complain (struct complaint *, ...);
extern void clear_complaints (int, int);
extern void clear_complaints (struct complaints **complaints,
int less_verbose, int noisy);
#endif /* !defined (COMPLAINTS_H) */

View file

@ -23,14 +23,17 @@
#include "gdbtypes.h"
#include "expression.h"
#include "filenames.h" /* for DOSish file names */
#include "language.h"
#include "cli/cli-decode.h"
/* FIXME: This is needed because of lookup_cmd_1().
We should be calling a hook instead so we eliminate the CLI dependency. */
#include "gdbcmd.h"
/* Needed for rl_completer_word_break_characters() and for
filename_completion_function. */
#include <readline/readline.h>
rl_filename_completion_function. */
#include "readline/readline.h"
/* readline defines this. */
#undef savestring
@ -38,7 +41,8 @@
#include "completer.h"
/* Prototypes for local functions */
char *line_completion_function (char *text, int matches, char *line_buffer,
static
char *line_completion_function (const char *text, int matches, char *line_buffer,
int point);
/* readline uses the word breaks for two things:
@ -48,13 +52,11 @@ char *line_completion_function (char *text, int matches, char *line_buffer,
it does affect how much stuff M-? lists.
(2) If one of the matches contains a word break character, readline
will quote it. That's why we switch between
gdb_completer_word_break_characters and
current_language->la_word_break_characters() and
gdb_completer_command_word_break_characters. I'm not sure when
we need this behavior (perhaps for funky characters in C++ symbols?). */
/* Variables which are necessary for fancy command line editing. */
static char *gdb_completer_word_break_characters =
" \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-";
/* When completing on command names, we remove '-' from the list of
word break characters, since we use it in command names. If the
@ -87,12 +89,6 @@ static char *gdb_completer_quote_characters = "'";
/* Accessor for some completer data that may interest other files. */
char *
get_gdb_completer_word_break_characters (void)
{
return gdb_completer_word_break_characters;
}
char *
get_gdb_completer_quote_characters (void)
{
@ -102,7 +98,7 @@ get_gdb_completer_quote_characters (void)
/* Line completion interface function for readline. */
char *
readline_line_completion_function (char *text, int matches)
readline_line_completion_function (const char *text, int matches)
{
return line_completion_function (text, matches, rl_line_buffer, rl_point);
}
@ -133,7 +129,7 @@ filename_completer (char *text, char *word)
while (1)
{
char *p;
p = filename_completion_function (text, subsequent_name);
p = rl_filename_completion_function (text, subsequent_name);
if (return_val_used >= return_val_alloced)
{
return_val_alloced *= 2;
@ -248,7 +244,7 @@ location_completer (char *text, char *word)
colon = p;
symbol_start = p + 1;
}
else if (strchr (gdb_completer_word_break_characters, *p))
else if (strchr (current_language->la_word_break_characters(), *p))
symbol_start = p + 1;
}
@ -380,7 +376,7 @@ command_completer (char *text, char *word)
should pretend that the line ends at POINT. */
char **
complete_line (char *text, char *line_buffer, int point)
complete_line (const char *text, char *line_buffer, int point)
{
char **list = NULL;
char *tmp_command, *p;
@ -396,7 +392,7 @@ complete_line (char *text, char *line_buffer, int point)
'-' character used in some commands. */
rl_completer_word_break_characters =
gdb_completer_word_break_characters;
current_language->la_word_break_characters();
/* Decide whether to complete on a list of gdb commands or on symbols. */
tmp_command = (char *) alloca (point + 1);
@ -626,8 +622,8 @@ complete_line (char *text, char *line_buffer, int point)
which is a possible completion, it is the caller's responsibility to
free the string. */
char *
line_completion_function (char *text, int matches, char *line_buffer, int point)
static char *
line_completion_function (const char *text, int matches, char *line_buffer, int point)
{
static char **list = (char **) NULL; /* Cache of completions */
static int index; /* Next cached completion */
@ -671,21 +667,30 @@ line_completion_function (char *text, int matches, char *line_buffer, int point)
/* Make sure the word break characters are set back to normal for the
next time that readline tries to complete something. */
rl_completer_word_break_characters =
gdb_completer_word_break_characters;
current_language->la_word_break_characters();
#endif
return (output);
}
/* Skip over a possibly quoted word (as defined by the quote characters
and word break characters the completer uses). Returns pointer to the
location after the "word". */
/* Skip over the possibly quoted word STR (as defined by the quote
characters QUOTECHARS and the the word break characters
BREAKCHARS). Returns pointer to the location after the "word". If
either QUOTECHARS or BREAKCHARS is NULL, use the same values used
by the completer. */
char *
skip_quoted (char *str)
skip_quoted_chars (char *str, char *quotechars, char *breakchars)
{
char quote_char = '\0';
char *scan;
if (quotechars == NULL)
quotechars = gdb_completer_quote_characters;
if (breakchars == NULL)
breakchars = current_language->la_word_break_characters();
for (scan = str; *scan != '\0'; scan++)
{
if (quote_char != '\0')
@ -698,16 +703,26 @@ skip_quoted (char *str)
break;
}
}
else if (strchr (gdb_completer_quote_characters, *scan))
else if (strchr (quotechars, *scan))
{
/* Found start of a quoted string. */
quote_char = *scan;
}
else if (strchr (gdb_completer_word_break_characters, *scan))
else if (strchr (breakchars, *scan))
{
break;
}
}
return (scan);
}
/* Skip over the possibly quoted word STR (as defined by the quote
characters and word break characters used by the completer).
Returns pointer to the location after the "word". */
char *
skip_quoted (char *str)
{
return skip_quoted_chars (str, NULL, NULL);
}

View file

@ -19,11 +19,9 @@
#if !defined (COMPLETER_H)
#define COMPLETER_H 1
extern char **complete_line (char *text, char *line_buffer, int point);
extern char **complete_line (const char *text, char *line_buffer, int point);
extern char *line_completion_function (char *, int, char *, int);
extern char *readline_line_completion_function (char *text, int matches);
extern char *readline_line_completion_function (const char *text, int matches);
extern char **noop_completer (char *, char *);
@ -33,12 +31,12 @@ extern char **location_completer (char *, char *);
extern char **command_completer (char *, char *);
extern char *get_gdb_completer_word_break_characters (void);
extern char *get_gdb_completer_quote_characters (void);
/* Exported to linespec.c */
extern char *skip_quoted (char *str);
extern char *skip_quoted_chars (char *, char *, char *);
extern char *skip_quoted (char *);
#endif /* defined (COMPLETER_H) */

View file

@ -0,0 +1,2 @@
TDEPFILES= alpha-tdep.o
TM_FILE= tm-alpha.h

View file

@ -1,3 +1,3 @@
# Target: FreeBSD/Alpha
TDEPFILES= alpha-tdep.o alphafbsd-tdep.o
TDEPFILES= alpha-tdep.o alpha-mdebug-tdep.o alphabsd-tdep.o alphafbsd-tdep.o
TM_FILE= tm-fbsd.h

View file

@ -0,0 +1,4 @@
# Host: Alpha running NetBSD
NAT_CLIBS=
NATDEPFILES= infptrace.o inftarg.o fork-child.o alphabsd-nat.o
NAT_FILE= nm-nbsd.h

View file

@ -0,0 +1,4 @@
# Target: Alpha running NetBSD
TDEPFILES= alpha-tdep.o alpha-mdebug-tdep.o alphabsd-tdep.o alphanbsd-tdep.o \
corelow.o nbsd-tdep.o solib.o solib-svr4.o
TM_FILE= tm-nbsd.h

View file

@ -32,13 +32,11 @@
#define ATTACH_DETACH
/* The Alpha does not step over a breakpoint. */
#define CANNOT_STEP_BREAKPOINT
#define CANNOT_STEP_BREAKPOINT 1
/* Shared library support. */
#define SVR4_SHARED_LIBS
#include "solib.h" /* Support for shared libraries. */
#include "elf/common.h" /* Additional ELF shared library info. */

View file

@ -0,0 +1,31 @@
/* Native-dependent definitions for Alpha running NetBSD, for GDB.
Copyright 2002 Free Software Foundation, Inc.
Contributed by Wasabi Systems, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef NM_NBSD_H
#define NM_NBSD_H
/* Get generic NetBSD native definitions. */
#include "config/nm-nbsd.h"
/* The Alpha does not step over a breakpoint. */
#define CANNOT_STEP_BREAKPOINT 1
#endif /* NM_NBSD_H */

View file

@ -1,5 +1,7 @@
/* Native definitions for alpha running OSF/1.
Copyright 1993, 1994, 1995, 1998, 2000 Free Software Foundation, Inc.
Copyright 1993, 1994, 1995, 1998, 2000, 2004 Free Software
Foundation, Inc.
This file is part of GDB.
@ -18,14 +20,10 @@
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Figure out where the longjmp will land. We expect that we have just entered
longjmp and haven't yet setup the stack frame, so the args are still in the
argument regs. A0_REGNUM points at the jmp_buf structure from which we
extract the pc (JB_PC) that we will land at. The pc is copied into ADDR.
This routine returns true on success */
#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)
extern int get_longjmp_target (CORE_ADDR *);
/* Number of traps that happen between exec'ing the shell
to run an inferior, and when we finally get to
the inferior code. This is 2 on most implementations. */
#define START_INFERIOR_TRAPS_EXPECTED 3
/* ptrace register ``addresses'' are absolute. */
@ -41,11 +39,7 @@ extern int get_longjmp_target (CORE_ADDR *);
/* The alpha does not step over a breakpoint, the manpage is lying again. */
#define CANNOT_STEP_BREAKPOINT
/* OSF/1 has shared libraries. */
#define GDB_TARGET_HAS_SHARED_LIBS
#define CANNOT_STEP_BREAKPOINT 1
/* Support for shared libraries. */

View file

@ -25,9 +25,6 @@
#define USE_PROC_FS
#define HAVE_OPTIONAL_PROC_FS
/* OSF/1 doesn't provide the standard fault definitions, so don't use them. */
#define FAULTED_USE_SIGINFO
/* Don't trace faults under OSF/1, rely on the posting of the appropriate
signal if fault tracing is disabled.
Tracing T_IFAULT under Alpha OSF/1 causes a `floating point enable'

View file

@ -1,5 +1,6 @@
/* Target-dependent definitions for FreeBSD/Alpha.
Copyright 2000, 2001 Free Software Foundation, Inc.
Copyright 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
This file is part of GDB.
@ -23,23 +24,4 @@
#include "alpha/tm-alpha.h"
/* FreeBSD uses the old gcc convention for struct returns. */
#undef USE_STRUCT_CONVENTION
#define USE_STRUCT_CONVENTION(gcc_p, type) \
alphafbsd_use_struct_convention (gcc_p, type)
/* FreeBSD doesn't mark the outermost frame. While some FreeBSD/Alpha
releases include (a minimal amount of) debugging info in its
startup code (crt1.o), the safest thing is to consider the user
code entry point as the outermost frame. */
#define FRAME_CHAIN_VALID(chain, thisframe) \
func_frame_chain_valid(chain, thisframe)
/* Number of traps that happen between exec'ing the shell to run an
inferior, and when we finally get to the inferior code. The
default is right for FreeBSD. */
#undef START_INFERIOR_TRAPS_EXPECTED
#endif /* TM_FBSD_H */

View file

@ -0,0 +1,28 @@
/* Target-dependent definitions for NetBSD/Alpha.
Copyright 2002, 2004 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef TM_NBSD_H
#define TM_NBSD_H
#include "alpha/tm-alpha.h"
#include "solib.h"
#endif /* TM_NBSD_H */

View file

@ -1,2 +1,3 @@
# Target: ARM running NetBSD
TDEPFILES= arm-tdep.o armnbsd-tdep.o solib.o solib-svr4.o solib-sunos.o
TDEPFILES= arm-tdep.o armnbsd-tdep.o solib.o solib-svr4.o nbsd-tdep.o
TM_FILE=tm-nbsd.h

View file

@ -0,0 +1,5 @@
# Host ARM running NetBSD
NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o armnbsd-nat.o \
solib-sunos.o
XM_FILE=xm-nbsd.h
NAT_FILE=nm-nbsdaout.h

View file

@ -0,0 +1,4 @@
# Host ARM running NetBSD
NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o armnbsd-nat.o
XM_FILE=xm-nbsd.h
NAT_FILE=nm-nbsd.h

View file

@ -22,12 +22,6 @@
#define NM_NBSD_H
/* Get generic NetBSD native definitions. */
#include "nm-nbsd.h"
#define REGISTER_U_ADDR(addr, blockend, regno) \
(addr) = arm_register_u_addr ((blockend),(regno));
extern int
arm_register_u_addr (int, int);
#include "config/nm-nbsd.h"
#endif /* NM_NBSD_H */

View file

@ -0,0 +1,29 @@
/* Native-dependent definitions for ARM running NetBSD, for GDB.
Copyright 1986, 1987, 1989, 1992, 1994, 1999 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef NM_NBSDAOUT_H
#define NM_NBSDAOUT_H
#include "arm/nm-nbsd.h"
/* Get generic NetBSD a.out native definitions. */
#include "config/nm-nbsdaout.h"
#endif /* NM_NBSDAOUT_H */

View file

@ -22,9 +22,7 @@
#ifndef TM_ARM_H
#define TM_ARM_H
#ifndef GDB_MULTI_ARCH
#define GDB_MULTI_ARCH 1
#endif
/* Specify that for the native compiler variables for a particular
lexical context are listed after the beginning LBRAC instead of

Some files were not shown because too many files have changed in this diff Show more