]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Initial version of available features support.
authorDaniel Jacobowitz <drow@false.org>
Fri, 3 Mar 2006 20:46:38 +0000 (20:46 +0000)
committerDaniel Jacobowitz <drow@false.org>
Fri, 3 Mar 2006 20:46:38 +0000 (20:46 +0000)
25 files changed:
Makefile.def
Makefile.in
configure
configure.in
gdb/Makefile.in
gdb/arm-tdep.c
gdb/auxv.c
gdb/auxv.h
gdb/available.c [new file with mode: 0644]
gdb/available.h [new file with mode: 0644]
gdb/avr-tdep.c
gdb/features/gdb-target.dtd [new file with mode: 0644]
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/ia64-tdep.c
gdb/infcmd.c
gdb/linux-nat.c
gdb/parse-avail.c [new file with mode: 0644]
gdb/procfs.c
gdb/remote.c
gdb/sparc-tdep.c
gdb/symfile.h
gdb/target.c
gdb/target.h

index 3227a44560208039b031b4fbdbed856d413ad385..3c87dce68dd7ed885d08797d32ac476fe5ec8ab1 100644 (file)
@@ -47,6 +47,7 @@ host_modules= { module= dejagnu; };
 host_modules= { module= diff; };
 host_modules= { module= dosutils; no_check= true; };
 host_modules= { module= etc; };
+host_modules= { module= expat; };
 host_modules= { module= fastjar; no_check_cross= true; };
 host_modules= { module= fileutils; };
 host_modules= { module= findutils; };
@@ -297,6 +298,7 @@ dependencies = { module=all-gdb; on=all-readline; };
 dependencies = { module=all-gdb; on=all-build-bison; };
 dependencies = { module=all-gdb; on=all-build-byacc; };
 dependencies = { module=all-gdb; on=all-sim; };
+dependencies = { module=all-gdb; on=all-expat; };
 
 dependencies = { module=configure-libgui; on=configure-tcl; };
 dependencies = { module=configure-libgui; on=configure-tk; };
index 37d5510053bfc8e596967fc8568ed52a43e3d2a6..15a98abc0b2790721ee1685054c55aecda888905 100644 (file)
@@ -566,6 +566,7 @@ configure-host:  \
     maybe-configure-diff \
     maybe-configure-dosutils \
     maybe-configure-etc \
+    maybe-configure-expat \
     maybe-configure-fastjar \
     maybe-configure-fileutils \
     maybe-configure-findutils \
@@ -694,6 +695,7 @@ all-host: maybe-all-dejagnu
 all-host: maybe-all-diff
 all-host: maybe-all-dosutils
 all-host: maybe-all-etc
+all-host: maybe-all-expat
 all-host: maybe-all-fastjar
 all-host: maybe-all-fileutils
 all-host: maybe-all-findutils
@@ -819,6 +821,7 @@ info-host: maybe-info-dejagnu
 info-host: maybe-info-diff
 info-host: maybe-info-dosutils
 info-host: maybe-info-etc
+info-host: maybe-info-expat
 info-host: maybe-info-fastjar
 info-host: maybe-info-fileutils
 info-host: maybe-info-findutils
@@ -923,6 +926,7 @@ dvi-host: maybe-dvi-dejagnu
 dvi-host: maybe-dvi-diff
 dvi-host: maybe-dvi-dosutils
 dvi-host: maybe-dvi-etc
+dvi-host: maybe-dvi-expat
 dvi-host: maybe-dvi-fastjar
 dvi-host: maybe-dvi-fileutils
 dvi-host: maybe-dvi-findutils
@@ -1027,6 +1031,7 @@ html-host: maybe-html-dejagnu
 html-host: maybe-html-diff
 html-host: maybe-html-dosutils
 html-host: maybe-html-etc
+html-host: maybe-html-expat
 html-host: maybe-html-fastjar
 html-host: maybe-html-fileutils
 html-host: maybe-html-findutils
@@ -1131,6 +1136,7 @@ TAGS-host: maybe-TAGS-dejagnu
 TAGS-host: maybe-TAGS-diff
 TAGS-host: maybe-TAGS-dosutils
 TAGS-host: maybe-TAGS-etc
+TAGS-host: maybe-TAGS-expat
 TAGS-host: maybe-TAGS-fastjar
 TAGS-host: maybe-TAGS-fileutils
 TAGS-host: maybe-TAGS-findutils
@@ -1235,6 +1241,7 @@ install-info-host: maybe-install-info-dejagnu
 install-info-host: maybe-install-info-diff
 install-info-host: maybe-install-info-dosutils
 install-info-host: maybe-install-info-etc
+install-info-host: maybe-install-info-expat
 install-info-host: maybe-install-info-fastjar
 install-info-host: maybe-install-info-fileutils
 install-info-host: maybe-install-info-findutils
@@ -1339,6 +1346,7 @@ installcheck-host: maybe-installcheck-dejagnu
 installcheck-host: maybe-installcheck-diff
 installcheck-host: maybe-installcheck-dosutils
 installcheck-host: maybe-installcheck-etc
+installcheck-host: maybe-installcheck-expat
 installcheck-host: maybe-installcheck-fastjar
 installcheck-host: maybe-installcheck-fileutils
 installcheck-host: maybe-installcheck-findutils
@@ -1443,6 +1451,7 @@ mostlyclean-host: maybe-mostlyclean-dejagnu
 mostlyclean-host: maybe-mostlyclean-diff
 mostlyclean-host: maybe-mostlyclean-dosutils
 mostlyclean-host: maybe-mostlyclean-etc
+mostlyclean-host: maybe-mostlyclean-expat
 mostlyclean-host: maybe-mostlyclean-fastjar
 mostlyclean-host: maybe-mostlyclean-fileutils
 mostlyclean-host: maybe-mostlyclean-findutils
@@ -1547,6 +1556,7 @@ clean-host: maybe-clean-dejagnu
 clean-host: maybe-clean-diff
 clean-host: maybe-clean-dosutils
 clean-host: maybe-clean-etc
+clean-host: maybe-clean-expat
 clean-host: maybe-clean-fastjar
 clean-host: maybe-clean-fileutils
 clean-host: maybe-clean-findutils
@@ -1651,6 +1661,7 @@ distclean-host: maybe-distclean-dejagnu
 distclean-host: maybe-distclean-diff
 distclean-host: maybe-distclean-dosutils
 distclean-host: maybe-distclean-etc
+distclean-host: maybe-distclean-expat
 distclean-host: maybe-distclean-fastjar
 distclean-host: maybe-distclean-fileutils
 distclean-host: maybe-distclean-findutils
@@ -1755,6 +1766,7 @@ maintainer-clean-host: maybe-maintainer-clean-dejagnu
 maintainer-clean-host: maybe-maintainer-clean-diff
 maintainer-clean-host: maybe-maintainer-clean-dosutils
 maintainer-clean-host: maybe-maintainer-clean-etc
+maintainer-clean-host: maybe-maintainer-clean-expat
 maintainer-clean-host: maybe-maintainer-clean-fastjar
 maintainer-clean-host: maybe-maintainer-clean-fileutils
 maintainer-clean-host: maybe-maintainer-clean-findutils
@@ -1912,6 +1924,7 @@ check-host:  \
     maybe-check-diff \
     maybe-check-dosutils \
     maybe-check-etc \
+    maybe-check-expat \
     maybe-check-fastjar \
     maybe-check-fileutils \
     maybe-check-findutils \
@@ -2043,6 +2056,7 @@ install-host-nogcc:  \
     maybe-install-diff \
     maybe-install-dosutils \
     maybe-install-etc \
+    maybe-install-expat \
     maybe-install-fastjar \
     maybe-install-fileutils \
     maybe-install-findutils \
@@ -2113,6 +2127,7 @@ install-host:  \
     maybe-install-diff \
     maybe-install-dosutils \
     maybe-install-etc \
+    maybe-install-expat \
     maybe-install-fastjar \
     maybe-install-fileutils \
     maybe-install-findutils \
@@ -8356,6 +8371,343 @@ maintainer-clean-etc:
 
 
 
+.PHONY: configure-expat maybe-configure-expat
+maybe-configure-expat:
+@if expat
+maybe-configure-expat: configure-expat
+configure-expat: 
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       test ! -f $(HOST_SUBDIR)/expat/Makefile || exit 0; \
+       $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/expat ; \
+       $(HOST_EXPORTS) \
+       echo Configuring in $(HOST_SUBDIR)/expat; \
+       cd "$(HOST_SUBDIR)/expat" || exit 1; \
+       case $(srcdir) in \
+         /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+         *) topdir=`echo $(HOST_SUBDIR)/expat/ | \
+               sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+       esac; \
+       srcdiroption="--srcdir=$${topdir}/expat"; \
+       libsrcdir="$$s/expat"; \
+       $(SHELL) $${libsrcdir}/configure \
+         $(HOST_CONFIGARGS) $${srcdiroption}  \
+         || exit 1
+@endif expat
+
+
+
+
+
+.PHONY: all-expat maybe-all-expat
+maybe-all-expat:
+@if expat
+TARGET-expat=all
+maybe-all-expat: all-expat
+all-expat: configure-expat
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(FLAGS_TO_PASS)  $(TARGET-expat))
+@endif expat
+
+
+
+
+.PHONY: check-expat maybe-check-expat
+maybe-check-expat:
+@if expat
+maybe-check-expat: check-expat
+
+check-expat:
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(FLAGS_TO_PASS)  check)
+
+@endif expat
+
+.PHONY: install-expat maybe-install-expat
+maybe-install-expat:
+@if expat
+maybe-install-expat: install-expat
+
+install-expat: installdirs
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(FLAGS_TO_PASS)  install)
+
+@endif expat
+
+# Other targets (info, dvi, etc.)
+
+.PHONY: maybe-info-expat info-expat
+maybe-info-expat:
+@if expat
+maybe-info-expat: info-expat
+
+info-expat: \
+    configure-expat 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing info in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 info) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-dvi-expat dvi-expat
+maybe-dvi-expat:
+@if expat
+maybe-dvi-expat: dvi-expat
+
+dvi-expat: \
+    configure-expat 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing dvi in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 dvi) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-html-expat html-expat
+maybe-html-expat:
+@if expat
+maybe-html-expat: html-expat
+
+html-expat: \
+    configure-expat 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing html in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 html) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-TAGS-expat TAGS-expat
+maybe-TAGS-expat:
+@if expat
+maybe-TAGS-expat: TAGS-expat
+
+TAGS-expat: \
+    configure-expat 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing TAGS in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 TAGS) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-install-info-expat install-info-expat
+maybe-install-info-expat:
+@if expat
+maybe-install-info-expat: install-info-expat
+
+install-info-expat: \
+    configure-expat \
+    info-expat 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing install-info in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 install-info) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-installcheck-expat installcheck-expat
+maybe-installcheck-expat:
+@if expat
+maybe-installcheck-expat: installcheck-expat
+
+installcheck-expat: \
+    configure-expat 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing installcheck in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 installcheck) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-mostlyclean-expat mostlyclean-expat
+maybe-mostlyclean-expat:
+@if expat
+maybe-mostlyclean-expat: mostlyclean-expat
+
+mostlyclean-expat: 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing mostlyclean in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 mostlyclean) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-clean-expat clean-expat
+maybe-clean-expat:
+@if expat
+maybe-clean-expat: clean-expat
+
+clean-expat: 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing clean in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 clean) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-distclean-expat distclean-expat
+maybe-distclean-expat:
+@if expat
+maybe-distclean-expat: distclean-expat
+
+distclean-expat: 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing distclean in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 distclean) \
+         || exit 1
+
+@endif expat
+
+.PHONY: maybe-maintainer-clean-expat maintainer-clean-expat
+maybe-maintainer-clean-expat:
+@if expat
+maybe-maintainer-clean-expat: maintainer-clean-expat
+
+maintainer-clean-expat: 
+       @: $(MAKE); $(unstage)
+       @[ -f ./expat/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing maintainer-clean in expat" ; \
+       (cd $(HOST_SUBDIR)/expat && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \
+                 maintainer-clean) \
+         || exit 1
+
+@endif expat
+
+
+
 .PHONY: configure-fastjar maybe-configure-fastjar
 maybe-configure-fastjar:
 @if fastjar
@@ -38269,6 +38621,7 @@ all-gdb: maybe-all-readline
 all-gdb: maybe-all-build-bison
 all-gdb: maybe-all-build-byacc
 all-gdb: maybe-all-sim
+all-gdb: maybe-all-expat
 configure-libgui: maybe-configure-tcl
 configure-libgui: maybe-configure-tk
 all-libgui: maybe-all-tcl
index d74e6116d6a928368f5c8fb2507f5ad6985ad053..3f7c5712a01e05599a9cc46471bcd6bd9e821ab8 100755 (executable)
--- a/configure
+++ b/configure
@@ -886,7 +886,7 @@ build_tools="build-texinfo build-byacc build-flex build-bison build-m4 build-fix
 
 # these libraries are used by various programs built for the host environment
 #
-host_libs="intl mmalloc libiberty opcodes bfd readline tcl tk itcl libgui zlib libcpp libdecnumber"
+host_libs="intl mmalloc libiberty opcodes bfd readline tcl tk itcl libgui zlib libcpp libdecnumber expat"
 
 # these tools are built for the host environment
 # Note, the powerpc-eabi build depends on sim occurring before gdb in order to
index adb53b9468ea0fb7b0e4fd3b208de0cff7adb130..f7c50c194efadd97374de2ae9f225ccc6a52cd84 100644 (file)
@@ -123,7 +123,7 @@ build_tools="build-texinfo build-byacc build-flex build-bison build-m4 build-fix
 
 # these libraries are used by various programs built for the host environment
 #
-host_libs="intl mmalloc libiberty opcodes bfd readline tcl tk itcl libgui zlib libcpp libdecnumber"
+host_libs="intl mmalloc libiberty opcodes bfd readline tcl tk itcl libgui zlib libcpp libdecnumber expat"
 
 # these tools are built for the host environment
 # Note, the powerpc-eabi build depends on sim occurring before gdb in order to
index d5abb4f682f1c2fe0c05b4f9fefc5d0a401334c1..ae7d251cb21f2dac76610ca2b5a4f567e82f035b 100644 (file)
@@ -127,6 +127,10 @@ READLINE = $(READLINE_DIR)/libreadline.a
 READLINE_SRC = $(srcdir)/$(READLINE_DIR)
 READLINE_CFLAGS = -I$(READLINE_SRC)/..
 
+# Where is the expat library?  Typically in ../expat.
+EXPAT = ../expat/.libs/libexpat.a
+EXPAT_CFLAGS = -I$(srcdir)/expat/lib -I../expat
+
 WARN_CFLAGS = @WARN_CFLAGS@
 WERROR_CFLAGS = @WERROR_CFLAGS@
 GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -350,6 +354,7 @@ INTERNAL_CFLAGS_BASE = \
        $(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
        $(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
        $(BFD_CFLAGS) $(INCLUDE_CFLAGS) \
+       $(EXPAT_CFLAGS) \
        $(INTL_CFLAGS) $(ENABLE_CFLAGS)
 INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
 INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
@@ -378,9 +383,9 @@ INSTALLED_LIBS=-lbfd -lreadline -lopcodes -liberty \
 CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) \
        $(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ \
        $(LIBICONV) \
-       $(LIBIBERTY) $(WIN32LIBS)
+       $(LIBIBERTY) $(WIN32LIBS) $(EXPAT)
 CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \
-       $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS)
+       $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(EXPAT)
 
 ADD_FILES = $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
 ADD_DEPS = $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
@@ -390,7 +395,7 @@ DIST=gdb
 LINT=/usr/5bin/lint
 LINTFLAGS= $(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
        $(BFD_CFLAGS) $(INCLUDE_CFLAGS) \
-       $(INTL_CFLAGS)
+       $(INTL_CFLAGS) $(EXPAT_CFLAGS)
 
 RUNTEST = runtest
 RUNTESTFLAGS=
@@ -511,6 +516,7 @@ TARGET_FLAGS_TO_PASS = \
 # SFILES is used in building the distribution archive.
 
 SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c  \
+       auxv.c available.c \
        ax-general.c ax-gdb.c \
        bcache.c \
        bfd-target.c \
@@ -542,6 +548,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c  \
        objc-exp.y objc-lang.c \
        objfiles.c osabi.c observer.c \
        p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
+       parse-avail.c \
        regcache.c reggroups.c remote.c remote-fileio.c \
        scm-exp.c scm-lang.c scm-valprint.c \
        sentinel-frame.c \
@@ -638,6 +645,7 @@ annotate_h = annotate.h $(symtab_h) $(gdbtypes_h)
 arch_utils_h = arch-utils.h
 arm_tdep_h = arm-tdep.h
 auxv_h = auxv.h
+available_h = available.h
 ax_gdb_h = ax-gdb.h
 ax_h = ax.h $(doublest_h)
 bcache_h = bcache.h
@@ -786,7 +794,7 @@ sparc_tdep_h = sparc-tdep.h
 srec_h = srec.h
 stabsread_h = stabsread.h
 stack_h = stack.h
-symfile_h = symfile.h
+symfile_h = symfile.h $(symtab_h)
 symtab_h = symtab.h
 target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h)
 terminal_h = terminal.h
@@ -902,6 +910,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
        version.o \
        annotate.o \
        auxv.o \
+       available.o parse-avail.o \
        bfd-target.o \
        blockframe.o breakpoint.o findvar.o regcache.o \
        charset.o disasm.o dummy-frame.o \
@@ -1759,10 +1768,13 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcmd_h) \
        $(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(arm_tdep_h) \
        $(gdb_sim_arm_h) $(elf_bfd_h) $(coff_internal_h) $(elf_arm_h) \
        $(gdb_assert_h) $(bfd_in2_h) $(libcoff_h) $(objfiles_h) \
-       $(dwarf2_frame_h)
+       $(dwarf2_frame_h) $(available_h)
 auxv.o: auxv.c $(defs_h) $(target_h) $(gdbtypes_h) $(command_h) \
        $(inferior_h) $(valprint_h) $(gdb_assert_h) $(auxv_h) \
        $(elf_common_h)
+available.o: available.c $(defs_h) $(symfile_h) $(target_h) $(available_h) \
+       $(arch_utils_h) $(gdbtypes_h) \
+       $(gdb_string) $(gdb_assert) $(gdb_obstack_h)
 avr-tdep.o: avr-tdep.c $(defs_h) $(frame_h) $(frame_unwind_h) \
        $(frame_base_h) $(trad_frame_h) $(gdbcmd_h) $(gdbcore_h) \
        $(inferior_h) $(symfile_h) $(arch_utils_h) $(regcache_h) \
@@ -1982,7 +1994,8 @@ gcore.o: gcore.c $(defs_h) $(elf_bfd_h) $(infcall_h) $(inferior_h) \
        $(gdb_assert_h)
 gdbarch.o: gdbarch.c $(defs_h) $(arch_utils_h) $(gdbcmd_h) $(inferior_h) \
        $(symcat_h) $(floatformat_h) $(gdb_assert_h) $(gdb_string_h) \
-       $(gdb_events_h) $(reggroups_h) $(osabi_h) $(gdb_obstack_h)
+       $(gdb_events_h) $(reggroups_h) $(osabi_h) $(gdb_obstack_h) \
+       $(available_h)
 gdb.o: gdb.c $(defs_h) $(main_h) $(gdb_string_h) $(interps_h)
 gdb-events.o: gdb-events.c $(defs_h) $(gdb_events_h) $(gdbcmd_h)
 gdbtypes.o: gdbtypes.c $(defs_h) $(gdb_string_h) $(bfd_h) $(symtab_h) \
@@ -2126,7 +2139,7 @@ infcmd.o: infcmd.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
        $(symfile_h) $(gdbcore_h) $(target_h) $(language_h) $(symfile_h) \
        $(objfiles_h) $(completer_h) $(ui_out_h) $(event_top_h) \
        $(parser_defs_h) $(regcache_h) $(reggroups_h) $(block_h) \
-       $(solib_h) $(gdb_assert_h) $(observer_h)
+       $(solib_h) $(gdb_assert_h) $(gdb_obstack_h) $(observer_h)
 inf-loop.o: inf-loop.c $(defs_h) $(inferior_h) $(target_h) $(event_loop_h) \
        $(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h)
 inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \
@@ -2376,6 +2389,8 @@ parse.o: parse.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
        $(frame_h) $(expression_h) $(value_h) $(command_h) $(language_h) \
        $(parser_defs_h) $(gdbcmd_h) $(symfile_h) $(inferior_h) \
        $(doublest_h) $(gdb_assert_h) $(block_h)
+parse-avail.o: parse-avail.c $(defs_h) $(available_h) \
+       $(gdb_string) $(gdb_obstack_h)
 p-exp.o: p-exp.c $(defs_h) $(gdb_string_h) $(expression_h) $(value_h) \
        $(parser_defs_h) $(language_h) $(p_lang_h) $(bfd_h) $(symfile_h) \
        $(objfiles_h) $(block_h)
@@ -2450,7 +2465,7 @@ remote.o: remote.c $(defs_h) $(gdb_string_h) $(inferior_h) $(bfd_h) \
        $(gdb_stabs_h) $(gdbthread_h) $(remote_h) $(regcache_h) $(value_h) \
        $(gdb_assert_h) $(event_loop_h) $(event_top_h) $(inf_loop_h) \
        $(serial_h) $(gdbcore_h) $(remote_fileio_h) $(solib_h) $(observer_h) \
-       $(cli_decode_h) $(cli_setshow_h)
+       $(cli_decode_h) $(cli_setshow_h) $(available_h)
 remote-e7000.o: remote-e7000.c $(defs_h) $(gdbcore_h) $(gdbarch_h) \
        $(inferior_h) $(target_h) $(value_h) $(command_h) $(gdb_string_h) \
        $(exceptions_h) $(gdbcmd_h) $(serial_h) $(remote_utils_h) \
index 652be4b7234ef553fdd3db2edd512a7ecaf2321b..a831b653fe507c1d2283c1df271c9ddb9b2d0102 100644 (file)
@@ -40,6 +40,7 @@
 #include "trad-frame.h"
 #include "objfiles.h"
 #include "dwarf2-frame.h"
+#include "available.h"
 
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
@@ -1343,6 +1344,12 @@ arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
 static struct type *
 arm_register_type (struct gdbarch *gdbarch, int regnum)
 {
+  struct type *avail_type;
+
+  avail_type = available_register_type (gdbarch, regnum);
+  if (avail_type)
+    return avail_type;
+
   if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
     {
       if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
@@ -1354,23 +1361,6 @@ arm_register_type (struct gdbarch *gdbarch, int regnum)
     return builtin_type_int32;
 }
 
-/* Index within `registers' of the first byte of the space for
-   register N.  */
-
-static int
-arm_register_byte (int regnum)
-{
-  if (regnum < ARM_F0_REGNUM)
-    return regnum * INT_REGISTER_SIZE;
-  else if (regnum < ARM_PS_REGNUM)
-    return (NUM_GREGS * INT_REGISTER_SIZE
-           + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
-  else
-    return (NUM_GREGS * INT_REGISTER_SIZE
-           + NUM_FREGS * FP_REGISTER_SIZE
-           + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
-}
-
 /* Map GDB internal REGNUM onto the Arm simulator register numbers.  */
 static int
 arm_register_sim_regno (int regnum)
@@ -2466,6 +2456,12 @@ set_disassembly_style_sfunc (char *args, int from_tty,
 static const char *
 arm_register_name (int i)
 {
+  const char *avail_name;
+
+  avail_name = available_register_name (current_gdbarch, i);
+  if (avail_name)
+    return avail_name;
+
   return arm_register_names[i];
 }
 
@@ -2769,10 +2765,14 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM);   /* ??? */
   set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
   set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
-  set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
   set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
+  set_gdbarch_remote_num_g_packet_regs (gdbarch,
+                                       NUM_GREGS + NUM_FREGS + NUM_SREGS);
   set_gdbarch_register_type (gdbarch, arm_register_type);
 
+  if (info.feature_set)
+    record_available_features (gdbarch, info.feature_set);
+
   /* Internal <-> external register number maps.  */
   set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
 
@@ -2840,6 +2840,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                      _("arm_gdbarch_init: bad byte order for float format"));
     }
 
+  set_gdbarch_available_features_support (gdbarch, 1);
+
   return gdbarch;
 }
 
index 557da3d416d03d01bd844df74bba3504517b06d3..8a2c9fc2ddeac3bc82cf34a3f22d10c2f3578bc4 100644 (file)
@@ -76,43 +76,6 @@ procfs_xfer_auxv (struct target_ops *ops,
   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, gdb_byte **data)
-{
-  size_t auxv_alloc = 512, auxv_pos = 0;
-  gdb_byte *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.
@@ -148,7 +111,7 @@ target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
 {
   CORE_ADDR type, val;
   gdb_byte *data;
-  int n = target_auxv_read (ops, &data);
+  LONGEST n = target_read_whole (ops, TARGET_OBJECT_AUXV, NULL, &data);
   gdb_byte *ptr = data;
   int ents = 0;
 
@@ -184,7 +147,7 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
 {
   CORE_ADDR type, val;
   gdb_byte *data;
-  int len = target_auxv_read (ops, &data);
+  LONGEST len = target_read_whole (ops, TARGET_OBJECT_AUXV, NULL, &data);
   gdb_byte *ptr = data;
   int ents = 0;
 
index 92f7b541a6f251f15db396104a163cbfd4faeac8..c3030b0cacd36404826fc1a9424498e30b6fca6e 100644 (file)
 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, gdb_byte **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.
diff --git a/gdb/available.c b/gdb/available.c
new file mode 100644 (file)
index 0000000..b887d09
--- /dev/null
@@ -0,0 +1,367 @@
+/* Support for runtime-defined target features for GDB.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   Contributed by CodeSourcery.
+
+   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., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "gdbtypes.h"
+#include "symfile.h"
+#include "target.h"
+
+#include "available.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "gdb_obstack.h"
+
+/* TODO: Remote target "guess" features from g packet size */
+
+/* TODO: Clarify warning messages.  Remember, they will appear to
+   the user with no context after a "target remote".  The user
+   doesn't know how we got into this code.  */
+
+/* Architecture TODO to support this:
+
+   - Call available_register_type from _register_type method.
+   - Handle unexpected changes to _num_regs.
+   - Call record_available_features from _gdbarch_init.
+   - Do not override the default _register_byte
+   - Provide gdbarch_remote_num_g_packet_regs
+*/
+
+/* FIXME: Everywhere we call internal_error from this file leads to a failure
+   to initialize a gdbarch, which leads to later failures when we expect
+   e.g. current_regcache to have been initialized.  */
+
+/* Read a string representation of available features from the target,
+   using TARGET_OBJECT_AVAILABLE_FEATURES.  The returned string is
+   malloc allocated and NUL-terminated.  If NAME is NULL, the overall
+   feature set is read; otherwise the specified name is read (e.g.
+   resolving xi:include).  */
+
+static char *
+fetch_available_features_from_target (const char *name, void *ops_)
+{
+  struct target_ops *ops = ops_;
+  char *features_str;
+  gdb_byte *features_buf;
+  LONGEST len;
+
+  struct gdb_feature_set *features;
+  struct gdb_available_feature **slot;
+  int ret;
+
+  len = target_read_whole (ops, TARGET_OBJECT_AVAILABLE_FEATURES,
+                          NULL, &features_buf);
+  if (len <= 0)
+    return NULL;
+
+  /* Since we decode this object as a string, simplify processing by
+     making sure it is NUL terminated.  */
+  features_str = (char *) features_buf;
+  if (features_str[len - 1] != '\0')
+    {
+      features_str = xrealloc (features_str, len + 1);
+      features_str[len] = '\0';
+    }
+
+  return features_str;
+}
+
+/* Standard method to convert a string representation of available features
+   to a binary representation.  The string representation is fetched using
+   TARGET_OBJECT_AVAILABLE_FEATURES.  */
+
+struct gdb_feature_set *
+available_features_from_target_object (struct target_ops *ops,
+                                      struct obstack *obstack)
+{
+  struct gdb_feature_set *features;
+  char *features_str, *cur;
+  gdb_byte *features_buf;
+  LONGEST len;
+  struct gdb_available_feature **slot;
+  int ret;
+
+  features_str = fetch_available_features_from_target (NULL, ops);
+
+  features = OBSTACK_ZALLOC (obstack, struct gdb_feature_set);
+  features->obstack = obstack;
+  ret = available_features_from_xml_string (&features->features, obstack,
+                                           features_str,
+                                           fetch_available_features_from_target,
+                                           ops, 0);
+
+  if (ret < 0)
+    {
+      warning (_("Could not parse features XML from target"));
+      return NULL;
+    }
+
+  return features;
+}
+
+/* Return non-zero if LHS and RHS refer to compatible feature sets.  */
+
+int
+features_same_p (const struct gdb_feature_set *lhs,
+                const struct gdb_feature_set *rhs)
+{
+  const struct gdb_available_feature *lhs_p, *rhs_p;
+
+  lhs_p = lhs->features;
+  rhs_p = rhs->features;
+  while (lhs_p && rhs_p)
+    {
+      lhs_p = lhs_p->next;
+      rhs_p = rhs_p->next;
+    }
+  if (lhs_p || rhs_p)
+    return 0;
+
+  /* FIXME: This checking assumes that there are no features with
+     duplicate names in either set; enforce that when creating sets.  */
+
+  for (lhs_p = lhs->features; lhs_p; lhs_p = lhs_p->next)
+    {
+      for (rhs_p = rhs->features; rhs_p; rhs_p = rhs_p->next)
+       if (strcmp (lhs_p->name, rhs_p->name) == 0)
+         break;
+      if (rhs_p == NULL)
+       return 0;
+
+      /* FIXME: Check feature contents, especially for "custom" features
+        which don't have a standard meaning!  */
+    }
+
+  return 1;
+}
+
+/* Switch the architecture (gdbarch) to one which supports FEATURES.  */
+
+void
+arch_set_available_features (const struct gdb_feature_set *features)
+{
+  struct gdbarch_info info;
+
+  gdbarch_info_init (&info);
+  info.feature_set = features;
+  if (!gdbarch_update_p (info))
+    internal_error (__FILE__, __LINE__, "could not update architecture");
+}
+
+static struct gdb_feature_set *
+copy_features_to_obstack (struct obstack *obstack,
+                         const struct gdb_feature_set *features)
+{
+  struct gdb_feature_set *result;
+  struct gdb_available_feature **slot, *orig_feature;
+
+  result = obstack_alloc (obstack, sizeof (struct gdb_feature_set));
+  result->obstack = obstack;
+
+  slot = &result->features;
+  for (orig_feature = features->features;
+       orig_feature;
+       orig_feature = orig_feature->next)
+    {
+      struct gdb_available_feature *feature;
+      struct gdb_available_register **reg_slot, *orig_reg;
+
+      feature = OBSTACK_ZALLOC (obstack, struct gdb_available_feature);
+      *slot = feature;
+      slot = &feature->next;
+
+      memcpy (feature, orig_feature, sizeof (struct gdb_available_feature));
+      feature->name = obsavestring (feature->name, strlen (feature->name),
+                                   obstack);
+      if (feature->arch_data)
+       feature->arch_data = obsavestring (feature->arch_data,
+                                          strlen (feature->arch_data),
+                                          obstack);
+
+      reg_slot = &feature->registers;
+      for (orig_reg = orig_feature->registers;
+          orig_reg;
+          orig_reg = orig_reg->next)
+       {
+         struct gdb_available_register *reg;
+
+         reg = OBSTACK_ZALLOC (obstack, struct gdb_available_register);
+         *reg_slot = reg;
+         reg_slot = &reg->next;
+
+         memcpy (reg, orig_reg, sizeof (struct gdb_available_register));
+         reg->name = obsavestring (reg->name, strlen (reg->name), obstack);
+         if (reg->arch_data)
+           reg->arch_data = obsavestring (reg->arch_data,
+                                          strlen (reg->arch_data),
+                                          obstack);
+         if (reg->group)
+           reg->group = obsavestring (reg->group, strlen (reg->group),
+                                      obstack);
+         if (reg->type)
+           reg->type = obsavestring (reg->type, strlen (reg->type),
+                                     obstack);
+       }
+    }
+
+  return result;
+}
+
+/* Set an architecture's feature set.  Store BASE_FEATURES in GDBARCH,
+   and on the correct obstack.
+
+   This function will update num_regs.  It is the architecture's
+   responsibility to handle this if it has pseudo registers.
+
+   FIXME: This interface may need to go away; what if we want to add
+   a single additional feature to that provided by the target?  */
+
+void
+record_available_features (struct gdbarch *gdbarch,
+                          const struct gdb_feature_set *base_features)
+{
+  struct gdb_available_feature *feature;
+  struct gdb_available_register *reg;
+  struct gdb_feature_set *features;
+  int gdb_regnum, protocol_number;
+
+  features = copy_features_to_obstack (gdbarch_obstack (gdbarch),
+                                      base_features);
+  set_gdbarch_feature_set (gdbarch, features);
+
+  gdb_regnum = gdbarch_num_regs (gdbarch);
+
+  for (feature = features->features; feature; feature = feature->next)
+    {
+      protocol_number = feature->protocol_number;
+      for (reg = feature->registers; reg; reg = reg->next)
+       {
+         reg->gdb_regnum = gdb_regnum++;
+         reg->protocol_number = protocol_number++;
+       }
+    }
+
+  set_gdbarch_num_regs (gdbarch, gdb_regnum);
+}
+
+/* Search FEATURES for a register with GDB register number REGNUM.  */
+
+struct gdb_available_register *
+find_register (const struct gdb_feature_set *features, int regnum)
+{
+  struct gdb_available_feature *feature;
+  struct gdb_available_register *reg;
+
+  if (features == NULL)
+    return NULL;
+
+  for (feature = features->features; feature; feature = feature->next)
+    for (reg = feature->registers; reg; reg = reg->next)
+      if (reg->gdb_regnum == regnum)
+       return reg;
+
+  return NULL;
+}
+
+/* Return the type of target-described register REGNUM, if the feature set
+   for GDBARCH describes that register.  Otherwise return NULL.  */
+
+struct type *
+available_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  struct gdb_available_register *reg;
+
+  reg = find_register (gdbarch_feature_set (gdbarch), regnum);
+  if (reg == NULL)
+    return NULL;
+
+  if (reg->type && strcmp (reg->type, "float") == 0)
+    {
+      if (reg->bitsize == gdbarch_float_bit (gdbarch))
+       return builtin_type_float;
+      else if (reg->bitsize == gdbarch_double_bit (gdbarch))
+       return builtin_type_double;
+      else if (reg->bitsize == gdbarch_long_double_bit (gdbarch))
+       return builtin_type_long_double;
+    }
+
+  if (reg->type && strcmp (reg->type, "int") != 0)
+    {
+      /* FIXME: Warn the user about an unknown type + size?  */
+    }
+
+  /* Use an integer type; default to "long".  */
+  if (reg->bitsize == gdbarch_long_bit (gdbarch))
+    return builtin_type_long;
+  else if (reg->bitsize == TARGET_CHAR_BIT)
+    return builtin_type_signed_char;
+  else if (reg->bitsize == gdbarch_short_bit (gdbarch))
+    return builtin_type_short;
+  else if (reg->bitsize == gdbarch_int_bit (gdbarch))
+    return builtin_type_int;
+  else if (reg->bitsize == gdbarch_long_long_bit (gdbarch))
+    return builtin_type_long_long;
+  else if (reg->bitsize == gdbarch_ptr_bit (gdbarch))
+    /* A bit desperate by this point... */
+    return builtin_type_void_data_ptr;
+  else
+    {
+      /* FIXME: Create a new integer type of the appropriate size?  */
+      internal_error (__FILE__, __LINE__,
+                     _("GDB does not support %ld-bit registers on this target"),
+                     reg->bitsize);
+    }
+}
+
+/* Return the name of target-described register REGNUM, if the feature set
+   for GDBARCH describes that register.  Otherwise return NULL.  */
+
+const char *
+available_register_name (struct gdbarch *gdbarch, int regnum)
+{
+  struct gdb_available_register *reg;
+
+  reg = find_register (gdbarch_feature_set (gdbarch), regnum);
+  if (reg == NULL)
+    return NULL;
+
+  return reg->name;
+}
+
+/* Return the target-supplied register of target-described register
+   REGNUM, if the feature set for GDBARCH describes that register.
+   Otherwise return REGNUM (the legacy 1:1 mapping).  */
+
+int
+available_register_target_regnum (struct gdbarch *gdbarch, int regnum)
+{
+  struct gdb_available_register *reg;
+
+  reg = find_register (gdbarch_feature_set (gdbarch), regnum);
+  if (reg == NULL)
+    return regnum;
+
+  return reg->protocol_number;
+}
diff --git a/gdb/available.h b/gdb/available.h
new file mode 100644 (file)
index 0000000..600722d
--- /dev/null
@@ -0,0 +1,171 @@
+/* Support for runtime-defined target features for GDB.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   Contributed by CodeSourcery.
+
+   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., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifndef AVAILABLE_H
+#define AVAILABLE_H 1
+
+struct obstack;
+
+/* A GDB target interface can use these types to communicate to the
+   architecture support (gdbarch) what new or optional features
+   it supports.
+
+   Each individual gdb_available_feature describes a target-specific
+   unit of functionality, often including a group of registers,
+   possibly including other bits of which the debugger needs
+   explicit knowledge.  GDB may recognize the feature by name,
+   or query the target for additional details.  If it recognizes
+   the feature by name, it may take advantage of the feature's
+   presence in additional ways - e.g. by knowing the calling
+   conventions for functions using the new registers.
+
+   If GDB does not recognize the feature by name, and the feature
+   requests explicit debugger support, GDB may suggest an upgrade
+   to the user.  */
+
+struct gdb_feature_set
+{
+  struct gdb_available_feature *features;
+
+  struct obstack *obstack;
+};
+
+struct gdb_available_feature
+{
+  /* The name of this feature.  For features, the name
+     is recognized by the architecture.  */
+  const char *name;
+
+  /* The protocol number used by this target to provide this feature.
+     For instance, the base register number for a group of raw
+     registers included in a known feature.  If none is necessary this
+     may be set to -1.  */
+  int protocol_number;
+
+  /* Data private to the architecture associated with this feature.
+     This is a NUL-terminated string.  */
+  const char *arch_data;
+
+  /* The registers associated with this feature.  */
+  struct gdb_available_register *registers;
+
+  /* Chain to the next available feature in this set.  */
+  struct gdb_available_feature *next;
+};
+
+struct gdb_available_register
+{
+  /* The name of this feature.  For registers, the name is
+     only used by the user interface.  */
+  const char *name;
+
+  /* The protocol number used by this target to provide this
+     feature.  For instance, the register number used for remote
+     p/P packets to access this register.  */
+  int protocol_number;
+
+  /* Data private to the architecture associated with this feature.
+     This is a NUL-terminated string.  */
+  const char *arch_data;
+
+  /* If this flag is set, GDB should never try to write to this
+     register.  Otherwise, the user may modify the value in the
+     register.  */
+  int readonly;
+
+  /* If this flag is set, GDB should save and restore this register
+     around calls to an inferior function.  */
+  /* FIXME: Richard Earnshaw proposed an alternate, more thourough
+     categorization.  Should we use that instead?  */
+  int save_restore;
+
+  /* The name of the register group containing this register.  If this
+     is "general", "float", or "vector", the corresponding "info" command
+     should display this register's value.  It can be an arbitrary
+     string, but should be limited to alphanumeric characters and internal
+     hyphens.  */
+  const char *group;
+
+  /* The size of the register, in bits.  */
+  long bitsize;
+
+  /* The type of the register.  This is a target-supplied string,
+     corresponding to FIXME FIXME.  */
+  const char *type;
+
+  /* GDB internal state for this register; this may vary per copy
+     of this code in each gdbarch.  */
+
+  /* GDB register number for this register.  */
+  int gdb_regnum;
+
+  /* Chain to the next available register in this feature.  */
+  struct gdb_available_register *next;
+};
+
+/* Standard method to convert a string representation of available features
+   to a binary representation.  The string representation is fetched using
+   TARGET_OBJECT_AVAILABLE_FEATURES.  */
+
+struct gdb_feature_set *available_features_from_target_object
+  (struct target_ops *, struct obstack *);
+
+/* Standard method to update an architecture based on detected available
+   features.  */
+
+void arch_set_available_features (const struct gdb_feature_set *);
+
+/* Compare two sets of available features.  */
+
+int features_same_p (const struct gdb_feature_set *,
+                    const struct gdb_feature_set *);
+
+/* Set an architecture's feature set.  */
+
+void record_available_features (struct gdbarch *,
+                               const struct gdb_feature_set *);
+
+/* Find the type of a target-described register.  */
+
+struct type *available_register_type (struct gdbarch *, int);
+
+/* Find the name of a target-described register.  */
+
+const char *available_register_name (struct gdbarch *, int);
+
+/* Find the target-supplied register number of a target-described register.  */
+
+int available_register_target_regnum (struct gdbarch *, int);
+
+
+/* Internal routines shared by available.c and parse-avail.c.  */
+
+typedef char *(*xml_fetch_another) (const char *, void *);
+
+int available_features_from_xml_string (struct gdb_available_feature **,
+                                       struct obstack *, const char *,
+                                       xml_fetch_another, void *,
+                                       int);
+
+#endif /* AVAILABLE_H */
index 9c6566e9210662376f39297edd210ad7849fcd14..530caa60db1ced91b8e6073a5fccf4d9e13f8a7a 100644 (file)
@@ -1323,35 +1323,22 @@ static void
 avr_io_reg_read_command (char *args, int from_tty)
 {
   LONGEST bufsiz = 0;
-  char buf[400];
+  gdb_byte *buf;
   char query[400];
   char *p;
   unsigned int nreg = 0;
   unsigned int val;
   int i, j, k, step;
 
-  /* Just get the maximum buffer size. */
-  bufsiz = target_read_partial (&current_target, TARGET_OBJECT_AVR,
-                               NULL, NULL, 0, 0);
-  if (bufsiz < 0)
-    {
-      fprintf_unfiltered (gdb_stderr,
-                         _("ERR: info io_registers NOT supported "
-                           "by current target\n"));
-      return;
-    }
-  if (bufsiz > sizeof (buf))
-    bufsiz = sizeof (buf);
-
   /* Find out how many io registers the target has. */
-  strcpy (query, "avr.io_reg");
-  target_read_partial (&current_target, TARGET_OBJECT_AVR, query, buf, 0,
-                      bufsiz);
+  bufsiz = target_read_whole (&current_target, TARGET_OBJECT_AVR,
+                             "avr.io_reg", &buf);
 
-  if (strncmp (buf, "", bufsiz) == 0)
+  if (bufsiz <= 0)
     {
       fprintf_unfiltered (gdb_stderr,
-                         _("info io_registers NOT supported by target\n"));
+                         _("ERR: info io_registers NOT supported "
+                           "by current target\n"));
       return;
     }
 
@@ -1359,9 +1346,12 @@ avr_io_reg_read_command (char *args, int from_tty)
     {
       fprintf_unfiltered (gdb_stderr,
                          _("Error fetching number of io registers\n"));
+      xfree (buf);
       return;
     }
 
+  xfree (buf);
+
   reinitialize_more_filter ();
 
   printf_unfiltered (_("Target has %u io registers:\n\n"), nreg);
@@ -1377,8 +1367,8 @@ avr_io_reg_read_command (char *args, int from_tty)
         j = nreg - i;           /* last block is less than 8 registers */
 
       snprintf (query, sizeof (query) - 1, "avr.io_reg:%x,%x", i, j);
-      target_read_partial (&current_target, TARGET_OBJECT_AVR, query, buf,
-                          0, bufsiz);
+      bufsiz = target_read_whole (&current_target, TARGET_OBJECT_AVR, query,
+                                 &buf);
 
       p = buf;
       for (k = i; k < (i + j); k++)
@@ -1393,6 +1383,8 @@ avr_io_reg_read_command (char *args, int from_tty)
                break;
            }
        }
+
+      xfree (buf);
     }
 }
 
diff --git a/gdb/features/gdb-target.dtd b/gdb/features/gdb-target.dtd
new file mode 100644 (file)
index 0000000..54b865a
--- /dev/null
@@ -0,0 +1,50 @@
+<!-- The root element of a GDB target description is <target>.  It
+     contains a list of feature definitions, followed by a feature-set.
+     This is also the only point at which xi:include is supported;
+     it must be used with xpointer to fetch a feature, from a
+     document whose root element is either target or feature.  -->
+
+<!ELEMENT target       (feature*, feature-set)>
+<!ATTLIST target
+       xmlns:xi        CDATA   #FIXED "http://www.w3.org/2001/XInclude">
+
+<!ELEMENT feature-set  (description*, feature-ref+)>
+
+<!-- QUESTION: Is there any reason for feature-ref to have its own
+     descriptions?  Or a short name field (descriptive)?  -->
+<!ELEMENT feature-ref  EMPTY>
+<!ATTLIST feature-ref
+       name            IDREF   #REQUIRED
+       base-regnum     CDATA   #IMPLIED>
+
+<!-- TODO: Handle arch_data, maybe as unvalidated fields; do we want
+    to define a namespace for arch-specific fields?  Issue for feature
+    and for reg.  -->
+
+<!-- QUESTION: Should the feature also have a short description to identify
+     it?  The format of its "name" field is restricted and probably not
+     user-appropriate.  -->
+<!ELEMENT feature      (description*, reg*)>
+<!ATTLIST feature
+       name            ID      #REQUIRED>
+
+<!-- TODO: GDB does not yet support descriptions.  -->
+
+<!-- Registers do not have an explicit register number field; they
+     are numbered sequentially from the containing feature's base-regnum
+     when the feature is referenced.  -->
+<!-- arch_data; see above -->
+<!-- Kill save-restore in favor of a more complete scheme -->
+<!ELEMENT reg          (description*)>
+<!ATTLIST reg
+       name            CDATA   #REQUIRED
+       bitsize         CDATA   #REQUIRED
+       readonly        (yes | no) 'no'
+       save-restore    (yes | no) 'yes'
+       type            CDATA   'int'
+       group           CDATA   #IMPLIED
+       >
+
+<!ELEMENT description  (#PCDATA)>
+<!ATTLIST description
+       xml:lang        CDATA   #IMPLIED>
index 4fa5ea4a3ec58e11140ea8d5b52496bab46c0d19..d5490845a87c345ff9045d5c921746fca851e63e 100644 (file)
@@ -41,6 +41,7 @@
 #include "gdbcmd.h"
 #include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
 #include "symcat.h"
+#include "available.h"
 
 #include "floatformat.h"
 
@@ -152,6 +153,7 @@ struct gdbarch
   gdbarch_pseudo_register_write_ftype *pseudo_register_write;
   int num_regs;
   int num_pseudo_regs;
+  int remote_num_g_packet_regs;
   int sp_regnum;
   int pc_regnum;
   int ps_regnum;
@@ -235,6 +237,8 @@ struct gdbarch
   gdbarch_register_reggroup_p_ftype *register_reggroup_p;
   gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
   gdbarch_regset_from_core_section_ftype *regset_from_core_section;
+  int available_features_support;
+  const struct gdb_feature_set * feature_set;
 };
 
 
@@ -278,6 +282,7 @@ struct gdbarch startup_gdbarch =
   0,  /* pseudo_register_write */
   0,  /* num_regs */
   0,  /* num_pseudo_regs */
+  0,  /* remote_num_g_packet_regs */
   -1,  /* sp_regnum */
   -1,  /* pc_regnum */
   -1,  /* ps_regnum */
@@ -361,6 +366,8 @@ struct gdbarch startup_gdbarch =
   default_register_reggroup_p,  /* register_reggroup_p */
   0,  /* fetch_pointer_argument */
   0,  /* regset_from_core_section */
+  0,  /* available_features_support */
+  0,  /* feature_set */
   /* startup_gdbarch() */
 };
 
@@ -536,6 +543,7 @@ verify_gdbarch (struct gdbarch *current_gdbarch)
   if (current_gdbarch->num_regs == -1)
     fprintf_unfiltered (log, "\n\tnum_regs");
   /* Skip verify of num_pseudo_regs, invalid_p == 0 */
+  /* Skip verify of remote_num_g_packet_regs, has predicate */
   /* Skip verify of sp_regnum, invalid_p == 0 */
   /* Skip verify of pc_regnum, invalid_p == 0 */
   /* Skip verify of ps_regnum, invalid_p == 0 */
@@ -719,6 +727,9 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: adjust_breakpoint_address = <0x%lx>\n",
                       (long) current_gdbarch->adjust_breakpoint_address);
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: available_features_support = %s\n",
+                      paddr_d (current_gdbarch->available_features_support));
 #ifdef BELIEVE_PCC_PROMOTION
   fprintf_unfiltered (file,
                       "gdbarch_dump: BELIEVE_PCC_PROMOTION # %s\n",
@@ -1054,6 +1065,9 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: extract_return_value = <0x%lx>\n",
                       (long) current_gdbarch->extract_return_value);
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: feature_set = %s\n",
+                      paddr_nz ((long) current_gdbarch->feature_set));
 #ifdef FETCH_POINTER_ARGUMENT_P
   fprintf_unfiltered (file,
                       "gdbarch_dump: %s # %s\n",
@@ -1474,6 +1488,12 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: regset_from_core_section = <0x%lx>\n",
                       (long) current_gdbarch->regset_from_core_section);
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_remote_num_g_packet_regs_p() = %d\n",
+                      gdbarch_remote_num_g_packet_regs_p (current_gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: remote_num_g_packet_regs = %s\n",
+                      paddr_d (current_gdbarch->remote_num_g_packet_regs));
   fprintf_unfiltered (file,
                       "gdbarch_dump: remote_translate_xfer_address = <0x%lx>\n",
                       (long) current_gdbarch->remote_translate_xfer_address);
@@ -1640,6 +1660,14 @@ gdbarch_tdep (struct gdbarch *gdbarch)
   return gdbarch->tdep;
 }
 
+struct obstack *
+gdbarch_obstack (struct gdbarch *gdbarch)
+{
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_obstack called\n");
+  return gdbarch->obstack;
+}
+
 
 const struct bfd_arch_info *
 gdbarch_bfd_arch_info (struct gdbarch *gdbarch)
@@ -2070,6 +2098,29 @@ set_gdbarch_num_pseudo_regs (struct gdbarch *gdbarch,
   gdbarch->num_pseudo_regs = num_pseudo_regs;
 }
 
+int
+gdbarch_remote_num_g_packet_regs_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->remote_num_g_packet_regs != 0;
+}
+
+int
+gdbarch_remote_num_g_packet_regs (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_remote_num_g_packet_regs called\n");
+  return gdbarch->remote_num_g_packet_regs;
+}
+
+void
+set_gdbarch_remote_num_g_packet_regs (struct gdbarch *gdbarch,
+                                      int remote_num_g_packet_regs)
+{
+  gdbarch->remote_num_g_packet_regs = remote_num_g_packet_regs;
+}
+
 int
 gdbarch_sp_regnum (struct gdbarch *gdbarch)
 {
@@ -3683,6 +3734,38 @@ set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch,
   gdbarch->regset_from_core_section = regset_from_core_section;
 }
 
+int
+gdbarch_available_features_support (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_available_features_support called\n");
+  return gdbarch->available_features_support;
+}
+
+void
+set_gdbarch_available_features_support (struct gdbarch *gdbarch,
+                                        int available_features_support)
+{
+  gdbarch->available_features_support = available_features_support;
+}
+
+const struct gdb_feature_set *
+gdbarch_feature_set (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_feature_set called\n");
+  return gdbarch->feature_set;
+}
+
+void
+set_gdbarch_feature_set (struct gdbarch *gdbarch,
+                         const struct gdb_feature_set * feature_set)
+{
+  gdbarch->feature_set = feature_set;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules. */
@@ -4006,8 +4089,7 @@ register_gdbarch_init (enum bfd_architecture bfd_architecture,
 }
 
 
-/* Look for an architecture using gdbarch_info.  Base search on only
-   BFD_ARCH_INFO and BYTE_ORDER. */
+/* Look for an architecture using gdbarch_info.  */
 
 struct gdbarch_list *
 gdbarch_list_lookup_by_info (struct gdbarch_list *arches,
@@ -4021,6 +4103,15 @@ gdbarch_list_lookup_by_info (struct gdbarch_list *arches,
        continue;
       if (info->osabi != arches->gdbarch->osabi)
        continue;
+
+      if (info->feature_set && !arches->gdbarch->feature_set)
+       continue;
+      if (!info->feature_set && arches->gdbarch->feature_set)
+       continue;
+      if (info->feature_set
+         && !features_same_p (info->feature_set, arches->gdbarch->feature_set))
+       continue;
+
       return arches;
     }
   return NULL;
index 75ac81fd6251b02b8229e9041b37e02d78dcdb2a..1d11fb70b06e1bd3cd75d903e22b860108a71b38 100644 (file)
@@ -49,6 +49,7 @@ struct regset;
 struct disassemble_info;
 struct target_ops;
 struct obstack;
+struct gdb_feature_set;
 
 extern struct gdbarch *current_gdbarch;
 
@@ -355,6 +356,16 @@ extern void set_gdbarch_num_pseudo_regs (struct gdbarch *gdbarch, int num_pseudo
 #define NUM_PSEUDO_REGS (gdbarch_num_pseudo_regs (current_gdbarch))
 #endif
 
+/* The number of registers fetched or stored using this target's
+   traditional g/G packet.
+   FIXME: Could we do without this by asking the target for a
+   g packet, and just seeing what's there?  We surely could! */
+
+extern int gdbarch_remote_num_g_packet_regs_p (struct gdbarch *gdbarch);
+
+extern int gdbarch_remote_num_g_packet_regs (struct gdbarch *gdbarch);
+extern void set_gdbarch_remote_num_g_packet_regs (struct gdbarch *gdbarch, int remote_num_g_packet_regs);
+
 /* GDB's standard (or well known) register numbers.  These can map onto
    a real register or a pseudo (computed) register or not be defined at
    all (-1).
@@ -1403,8 +1414,19 @@ typedef const struct regset * (gdbarch_regset_from_core_section_ftype) (struct g
 extern const struct regset * gdbarch_regset_from_core_section (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size);
 extern void set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch, gdbarch_regset_from_core_section_ftype *regset_from_core_section);
 
+/* Non-zero if the architecture supports target feature sets. */
+
+extern int gdbarch_available_features_support (struct gdbarch *gdbarch);
+extern void set_gdbarch_available_features_support (struct gdbarch *gdbarch, int available_features_support);
+
+/* The architecture's currently associated feature set. */
+
+extern const struct gdb_feature_set * gdbarch_feature_set (struct gdbarch *gdbarch);
+extern void set_gdbarch_feature_set (struct gdbarch *gdbarch, const struct gdb_feature_set * feature_set);
+
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 
+extern struct obstack *gdbarch_obstack (struct gdbarch *gdbarch);
 
 /* Mechanism for co-ordinating the selection of a specific
    architecture.
@@ -1487,6 +1509,9 @@ struct gdbarch_info
 
   /* Use default: GDB_OSABI_UNINITIALIZED (-1).  */
   enum gdb_osabi osabi;
+
+  /* Use default: NULL.  */
+  const struct gdb_feature_set *feature_set;
 };
 
 typedef struct gdbarch *(gdbarch_init_ftype) (struct gdbarch_info info, struct gdbarch_list *arches);
@@ -1511,11 +1536,11 @@ extern const char **gdbarch_printable_names (void);
 /* Helper function.  Search the list of ARCHES for a GDBARCH that
    matches the information provided by INFO. */
 
-extern struct gdbarch_list *gdbarch_list_lookup_by_info (struct gdbarch_list *arches,  const struct gdbarch_info *info);
+extern struct gdbarch_list *gdbarch_list_lookup_by_info (struct gdbarch_list *arches, const struct gdbarch_info *info);
 
 
 /* Helper function.  Create a preliminary ``struct gdbarch''.  Perform
-   basic initialization using values obtained from the INFO andTDEP
+   basic initialization using values obtained from the INFO and TDEP
    parameters.  set_gdbarch_*() functions are called to complete the
    initialization of the object. */
 
index afcfd82b5d9727b4eb98682461956f3bfe72e401..fb26e901d7607d0a436765d5714602674577ba9f 100755 (executable)
@@ -433,6 +433,11 @@ v:=:int:num_regs:::0:-1
 # These pseudo-registers may be aliases for other registers,
 # combinations of other registers, or they may be computed by GDB.
 v:=:int:num_pseudo_regs:::0:0::0
+# The number of registers fetched or stored using this target's
+# traditional g/G packet.
+# FIXME: Could we do without this by asking the target for a
+# g packet, and just seeing what's there?  We surely could!
+V::int:remote_num_g_packet_regs
 
 # GDB's standard (or well known) register numbers.  These can map onto
 # a real register or a pseudo (computed) register or not be defined at
@@ -662,6 +667,12 @@ F:=:CORE_ADDR:fetch_pointer_argument:struct frame_info *frame, int argi, struct
 # Return the appropriate register set for a core file section with
 # name SECT_NAME and size SECT_SIZE.
 M::const struct regset *:regset_from_core_section:const char *sect_name, size_t sect_size:sect_name, sect_size
+
+# Non-zero if the architecture supports target feature sets.
+v::int:available_features_support
+
+# The architecture's currently associated feature set.
+v::const struct gdb_feature_set *:feature_set:::::::paddr_nz ((long) current_gdbarch->feature_set)
 EOF
 }
 
@@ -771,6 +782,7 @@ struct regset;
 struct disassemble_info;
 struct target_ops;
 struct obstack;
+struct gdb_feature_set;
 
 extern struct gdbarch *current_gdbarch;
 EOF
@@ -904,6 +916,7 @@ cat <<EOF
 
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 
+extern struct obstack *gdbarch_obstack (struct gdbarch *gdbarch);
 
 /* Mechanism for co-ordinating the selection of a specific
    architecture.
@@ -986,6 +999,9 @@ struct gdbarch_info
 
   /* Use default: GDB_OSABI_UNINITIALIZED (-1).  */
   enum gdb_osabi osabi;
+
+  /* Use default: NULL.  */
+  const struct gdb_feature_set *feature_set;
 };
 
 typedef struct gdbarch *(gdbarch_init_ftype) (struct gdbarch_info info, struct gdbarch_list *arches);
@@ -1010,11 +1026,11 @@ extern const char **gdbarch_printable_names (void);
 /* Helper function.  Search the list of ARCHES for a GDBARCH that
    matches the information provided by INFO. */
 
-extern struct gdbarch_list *gdbarch_list_lookup_by_info (struct gdbarch_list *arches,  const struct gdbarch_info *info);
+extern struct gdbarch_list *gdbarch_list_lookup_by_info (struct gdbarch_list *arches, const struct gdbarch_info *info);
 
 
 /* Helper function.  Create a preliminary \`\`struct gdbarch''.  Perform
-   basic initialization using values obtained from the INFO andTDEP
+   basic initialization using values obtained from the INFO and TDEP
    parameters.  set_gdbarch_*() functions are called to complete the
    initialization of the object. */
 
@@ -1157,6 +1173,7 @@ cat <<EOF
 #include "gdbcmd.h"
 #include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
 #include "symcat.h"
+#include "available.h"
 
 #include "floatformat.h"
 
@@ -1590,6 +1607,14 @@ gdbarch_tdep (struct gdbarch *gdbarch)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_tdep called\\n");
   return gdbarch->tdep;
 }
+
+struct obstack *
+gdbarch_obstack (struct gdbarch *gdbarch)
+{
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_obstack called\\n");
+  return gdbarch->obstack;
+}
 EOF
 printf "\n"
 function_list | while do_read
@@ -2024,8 +2049,7 @@ register_gdbarch_init (enum bfd_architecture bfd_architecture,
 }
 
 
-/* Look for an architecture using gdbarch_info.  Base search on only
-   BFD_ARCH_INFO and BYTE_ORDER. */
+/* Look for an architecture using gdbarch_info.  */
 
 struct gdbarch_list *
 gdbarch_list_lookup_by_info (struct gdbarch_list *arches,
@@ -2039,6 +2063,15 @@ gdbarch_list_lookup_by_info (struct gdbarch_list *arches,
        continue;
       if (info->osabi != arches->gdbarch->osabi)
        continue;
+
+      if (info->feature_set && !arches->gdbarch->feature_set)
+       continue;
+      if (!info->feature_set && arches->gdbarch->feature_set)
+       continue;
+      if (info->feature_set
+         && !features_same_p (info->feature_set, arches->gdbarch->feature_set))
+       continue;
+
       return arches;
     }
   return NULL;
index 4ec5a955cdbdf0c69aa6ebf36d50c31179007ac4..f302142e9fec18c05382d1c58f59c199cea7df87 100644 (file)
@@ -2455,8 +2455,8 @@ ia64_access_mem (unw_addr_space_t as,
 }
 
 /* Call low-level function to access the kernel unwind table.  */
-static int
-getunwind_table (void *buf, size_t len)
+static LONGEST
+getunwind_table (gdb_byte **buf_p)
 {
   LONGEST x;
 
@@ -2467,10 +2467,11 @@ getunwind_table (void *buf, size_t len)
      we want to preserve fall back to the running kernel's table, then
      we should find a way to override the corefile layer's
      xfer_partial method.  */
-  x = target_read_partial (&current_target, TARGET_OBJECT_UNWIND_TABLE, NULL,
-                          buf, 0, len);
 
-  return (int)x;
+  x = target_read_whole (&current_target, TARGET_OBJECT_UNWIND_TABLE,
+                        NULL, buf_p);
+
+  return x;
 }
 
 /* Get the kernel unwind table.  */                             
@@ -2481,14 +2482,15 @@ get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
 
   if (!ktab) 
     {
+      gdb_byte *ktab_buf;
       size_t size;
-      size = getunwind_table (NULL, 0);
-      if ((int)size < 0)
-        return -UNW_ENOINFO;
-      ktab_size = size;
-      ktab = xmalloc (ktab_size);
-      getunwind_table (ktab, ktab_size);
-                         
+
+      ktab_size = getunwind_table (&ktab_buf);
+      if (ktab_size <= 0)
+       return -UNW_ENOINFO;
+      else
+       ktab = (struct ia64_table_entry *) ktab_buf;
+
       for (etab = ktab; etab->start_offset; ++etab)
         etab->info_offset += KERNEL_START;
     }
index 12a305de2c3380bbaac2ef35407a80fe9695c0b9..09732ff4a46e8f39d9ecb2f0c8c4fda3cd461b9a 100644 (file)
@@ -48,6 +48,9 @@
 #include <ctype.h>
 #include "gdb_assert.h"
 #include "observer.h"
+#include "available.h"
+
+#include "gdb_obstack.h"
 
 /* Functions exported for general use, in inferior.h: */
 
@@ -405,6 +408,25 @@ tty_command (char *file, int from_tty)
 void
 post_create_inferior (struct target_ops *target, int from_tty)
 {
+  /* The first thing we do after creating an inferior is update the
+     architecture with information provided by the target.
+
+     FIXME: In some cases we could do this after target_open
+     instead; should we?  */
+  if (gdbarch_available_features_support (current_gdbarch))
+    {
+      struct gdb_feature_set *features;
+      struct obstack tmp_obstack;
+
+      obstack_init (&tmp_obstack);
+      features = target_available_features (target, &tmp_obstack);
+
+      if (features)
+       arch_set_available_features (features);
+
+      obstack_free (&tmp_obstack, NULL);
+    }
+
   if (exec_bfd)
     {
       /* Sometimes the platform-specific hook loads initial shared
index 0710ac718acbbadee3883b8999b6f849cd733cbe..0c1dc1b81fe55ee49109931a0f146f5e1a56f254 100644 (file)
@@ -2849,7 +2849,8 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
       note_data = thread_args.note_data;
     }
 
-  auxv_len = target_auxv_read (&current_target, &auxv);
+  auxv_len = target_read_whole (&current_target, TARGET_OBJECT_AUXV, NULL,
+                               &auxv);
   if (auxv_len > 0)
     {
       note_data = elfcore_write_note (obfd, note_data, note_size,
diff --git a/gdb/parse-avail.c b/gdb/parse-avail.c
new file mode 100644 (file)
index 0000000..b331d8a
--- /dev/null
@@ -0,0 +1,989 @@
+/* Support for runtime-defined target features for GDB.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   Contributed by CodeSourcery.
+
+   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., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+
+#include "available.h"
+
+#include "filenames.h"
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "gdb_obstack.h"
+
+#include <expat.h>
+
+/* General notes for this file:
+
+   Do not call error while parsing supplied features.  If something is
+   unrecognizable, fail gracefully.  Calling error may lead to a
+   failure to initialize a gdbarch, and internal errors down the road.
+   Also, it's hard to predict with XML what's meaningless today but
+   might make sense tomorrow :-)
+
+   Warnings are OK; so are true internal errors, e.g. impossible states
+   in the parsing finite state machine.  Also, we will reach
+   internal_error if there is a memory allocation failure.  */
+
+/* Parse a field VALSTR that we expect to contain an integer value.
+   The integer is returned in *VALP.
+
+   Returns 0 for success, -1 for error.  */
+
+static int
+xml_parse_one_integer (const char *valstr, long *valp)
+{
+  char *endptr;
+  long result;
+
+  if (*valstr == '\0')
+    return -1;
+
+  result = strtol (valstr, &endptr, 0);
+  if (*endptr != '\0')
+    return -1;
+
+  *valp = result;
+  return 0;
+}
+
+/* Parse a field VALSTR that we expect to contain a boolean value.
+   The value is returned in *VALP.
+
+   Returns 0 for success, -1 for error.  */
+
+static int
+xml_parse_one_boolean (const char *valstr, int *valp)
+{
+  if (strcmp (valstr, "yes") == 0)
+    *valp = 1;
+  else if (strcmp (valstr, "no") == 0)
+    *valp = 0;
+  else
+    return -1;
+
+  return 0;
+}
+
+/* Save STR on OBSTACK, and return the new copy.  */
+
+static char *
+obstrdup (struct obstack *obstack, const char *str)
+{
+  char *result;
+  size_t len;
+
+  len = strlen (str);
+  result = obstack_alloc (obstack, len + 1);
+  memcpy (result, str, len);
+  result[len] = '\0';
+
+  return result;
+}
+
+/* Duplicate a provided ORIG_FEATURE, allocating the new copy from
+   OBSTACK.  Return the new copy.  */
+
+static struct gdb_available_feature *
+copy_feature_to_obstack (struct obstack *obstack,
+                        const struct gdb_available_feature *orig_feature)
+{
+  struct gdb_available_feature *feature;
+  struct gdb_available_register **reg_slot, *orig_reg;
+
+  feature = OBSTACK_ZALLOC (obstack, struct gdb_available_feature);
+
+  memcpy (feature, orig_feature, sizeof (struct gdb_available_feature));
+  feature->name = obstrdup (obstack, feature->name);
+  if (feature->arch_data)
+    feature->arch_data = obstrdup (obstack, feature->arch_data);
+
+  reg_slot = &feature->registers;
+  for (orig_reg = orig_feature->registers;
+       orig_reg;
+       orig_reg = orig_reg->next)
+    {
+      struct gdb_available_register *reg;
+
+      reg = OBSTACK_ZALLOC (obstack, struct gdb_available_register);
+      *reg_slot = reg;
+      reg_slot = &reg->next;
+
+      memcpy (reg, orig_reg, sizeof (struct gdb_available_register));
+      reg->name = obstrdup (obstack, reg->name);
+      if (reg->arch_data)
+       reg->arch_data = obstrdup (obstack, reg->arch_data);
+      if (reg->group)
+       reg->group = obstrdup (obstack, reg->group);
+      if (reg->type)
+       reg->type = obstrdup (obstack, reg->type);
+    }
+
+  return feature;
+}
+
+
+
+/* FIXME item: Warnings versus errors?  Where to issue warnings?  */
+
+enum xml_phase {
+  PHASE_TOP,
+  PHASE_IN_TARGET,
+  PHASE_IN_FEATURE,
+  PHASE_IN_DESCRIPTION,
+  PHASE_IN_REG,
+  PHASE_IN_FEATURE_SET,
+  PHASE_IN_FEATURE_REF,
+  PHASE_IN_XINCLUDE,
+  PHASE_UNKNOWN
+};
+
+struct xml_state_stack
+{
+  enum xml_phase phase;
+
+  union
+  {
+    struct
+    {
+      int seen_target;
+      int nested;
+    } top;
+    struct
+    {
+      int seen_feature_set;
+      int features_only;
+    } target;
+    struct
+    {
+      struct gdb_available_feature *feature;
+      int seen_reg;
+    } feature;
+    struct
+    {
+      struct gdb_available_register *reg;
+    } reg;
+    struct
+    {
+      int depth;
+    } unknown;
+  } u;
+
+  struct xml_state_stack *prev;
+};
+
+struct xml_feature_parse_data
+{
+  /* The obstack to allocate new features from.  */
+  struct obstack *obstack;
+
+  /* A function to call to obtain additional features, and its
+     baton.  */
+  xml_fetch_another fetcher;
+  void *fetcher_baton;
+
+  struct gdb_available_feature *seen_features;
+
+  struct gdb_available_feature *target_features;
+
+  /* Rough count of unrecognized or invalid items found while
+     processing.  These are non-fatal; however, some data from the
+     input has been skipped.  */
+  int unhandled;
+
+  struct xml_state_stack *state;
+};
+
+static void
+xml_start_xinclude (struct xml_feature_parse_data *data,
+                   const XML_Char **attrs)
+{
+  struct gdb_available_feature *features, *f;
+  struct cleanup *back_to;
+  char *text;
+  int ret;
+  const char *href, *id, **p;
+
+  href = id = NULL;
+  for (p = attrs; *p; p += 2)
+    {
+      const char *name = p[0], *val = p[1];
+
+      if (strcmp (name, "href") == 0)
+       href = val;
+      else if (strcmp (name, "xpointer") == 0)
+       id = val;
+      else
+       data->unhandled++;
+    }
+
+  if (id == NULL)
+    {
+      data->unhandled++;
+      return;
+    }
+
+  for (f = data->seen_features; f; f = f->next)
+    if (strcmp (f->name, id) == 0)
+      /* Success.  We found a match already loaded; we don't need to
+        include the document.  */
+      return;
+
+  if (href == NULL || data->fetcher == NULL)
+    {
+      data->unhandled++;
+      return;
+    }
+
+  text = data->fetcher (href, data->fetcher_baton);
+  if (text == NULL)
+    {
+      data->unhandled++;
+      return;
+    }
+
+  back_to = make_cleanup (xfree, text);
+
+  ret = available_features_from_xml_string (&features, data->obstack,
+                                           text, data->fetcher,
+                                           data->fetcher_baton, 1);
+  if (ret == 0)
+    {
+      f = features;
+      while (f->next)
+       f = f->next;
+      f->next = data->seen_features;
+      data->seen_features = f;
+    }
+  else
+    /* Something went wrong parsing the document.  */
+    data->unhandled++;
+
+  do_cleanups (back_to);
+}
+
+static void
+xml_start_feature (struct xml_feature_parse_data *data,
+                  const XML_Char **attrs)
+{
+  struct gdb_available_feature *feature;
+  const XML_Char **p;
+
+  feature = obstack_alloc (data->obstack,
+                          sizeof (struct gdb_available_feature));
+  memset (feature, 0, sizeof (struct gdb_available_feature));
+
+  feature->protocol_number = -1;
+
+  for (p = attrs; *p; p += 2)
+    {
+      const char *name = p[0];
+      const char *val = p[1];
+
+      if (strcmp (name, "name") == 0)
+       feature->name = obstrdup (data->obstack, val);
+
+      else
+       data->unhandled++;
+    }
+
+  /* Verify that mandatory fields were supplied.  */
+  if (feature->name == NULL)
+    {
+      data->unhandled++;
+      return;
+    }
+
+  data->state->u.feature.feature = feature;
+}
+
+static void
+xml_start_reg (struct xml_feature_parse_data *data,
+              const XML_Char **attrs)
+{
+  struct gdb_available_register *reg;
+  const XML_Char **p;
+
+  reg = obstack_alloc (data->obstack,
+                      sizeof (struct gdb_available_register));
+  memset (reg, 0, sizeof (struct gdb_available_register));
+
+  reg->bitsize = -1;
+  reg->readonly = -1;
+  reg->save_restore = -1;
+
+  for (p = attrs; *p; p += 2)
+    {
+      const char *name = p[0];
+      const char *val = p[1];
+
+      if (*val == 0)
+       data->unhandled++;
+
+      else if (strcmp (name, "name") == 0)
+       reg->name = obstrdup (data->obstack, val);
+
+      else if (strcmp (name, "bitsize") == 0)
+       {
+         if (xml_parse_one_integer (val, &reg->bitsize) < 0)
+           data->unhandled++;
+       }
+
+      else if (strcmp (name, "type") == 0)
+       reg->type = obstrdup (data->obstack, val);
+
+      else if (strcmp (name, "group") == 0)
+       reg->group = obstrdup (data->obstack, val);
+
+      else if (strcmp (name, "readonly") == 0)
+       {
+         if (xml_parse_one_boolean (val, &reg->readonly) < 0)
+           data->unhandled++;
+       }
+
+      else if (strcmp (name, "save-restore") == 0)
+       {
+         if (xml_parse_one_boolean (val, &reg->save_restore) < 0)
+           data->unhandled++;
+       }
+
+      else
+       data->unhandled++;
+    }
+
+  /* Fill in optional fields with defaults.  */
+  /* FIXME: If we always provide the DTD, we don't need to do this.  */
+  if (reg->readonly == -1)
+    reg->readonly = 0;
+  if (reg->save_restore == -1)
+    reg->save_restore = 1;
+  if (reg->type == NULL)
+    reg->type = obstrdup (data->obstack, "int");
+
+  /* Verify that mandatory fields were supplied.  */
+  if (reg->name == NULL || reg->bitsize == -1)
+    {
+      data->unhandled++;
+      return;
+    }
+
+  data->state->u.reg.reg = reg;
+}
+
+static void
+xml_start_feature_ref (struct xml_feature_parse_data *data,
+                      const XML_Char **attrs)
+{
+  struct gdb_available_feature *feature, *new_feature;
+  struct gdb_available_register *reg;
+  const XML_Char **p;
+  const char *feature_name = NULL;
+  int i;
+
+  for (p = attrs; *p; p += 2)
+    {
+      const char *name = p[0];
+      const char *val = p[1];
+
+      if (strcmp (name, "name") == 0)
+       {
+         feature_name = val;
+         break;
+       }
+    }
+
+  if (feature_name == NULL)
+    {
+      data->unhandled++;
+      return;
+    }
+
+  for (feature = data->seen_features; feature; feature = feature->next)
+    if (strcmp (feature->name, feature_name) == 0)
+      break;
+
+  /* TODO: Look for the feature elsewhere - on the target and in our
+     database.  */
+
+  /* If we couldn't find the feature, stop.  */
+  if (feature == NULL)
+    {
+      data->unhandled++;
+      return;
+    }
+
+  new_feature = copy_feature_to_obstack (data->obstack, feature);
+
+  new_feature->protocol_number = -1;
+
+  for (p = attrs; *p; p += 2)
+    {
+      const char *name = p[0];
+      const char *val = p[1];
+
+      if (strcmp (name, "name") == 0)
+       continue;
+      else if (strcmp (name, "base-regnum") == 0)
+       new_feature->protocol_number = strtol (val, NULL, 0);
+      else
+       data->unhandled++;
+    }
+
+  /* The protocol number is only optional if there are no registers.  */
+  if (new_feature->protocol_number == -1 && new_feature->registers != NULL)
+    {
+      data->unhandled++;
+      return;
+    }
+
+  /* Set register numbers in the new feature.  */
+  for (i = new_feature->protocol_number, reg = new_feature->registers;
+       reg != NULL;
+       i++, reg = reg->next)
+    reg->protocol_number = i;
+
+  new_feature->next = data->target_features;
+  data->target_features = new_feature;
+}
+
+static void XMLCALL
+xml_feature_start_element (void *data_, const XML_Char *name,
+                          const XML_Char **attrs)
+{
+  struct xml_feature_parse_data *data = data_;
+  const XML_Char **p;
+  struct xml_state_stack *next_state;
+  enum xml_phase next_phase;
+
+  if (data->state->phase == PHASE_UNKNOWN)
+    {
+#if 1
+      fprintf_unfiltered (gdb_stderr, "skipping, name %s\n", name);
+#endif
+      data->state->u.unknown.depth++;
+      return;
+    }
+
+#if 1
+  fprintf_unfiltered (gdb_stderr, "entering, name %s\n", name);
+  for (p = attrs; *p; p += 2)
+    fprintf_unfiltered (gdb_stderr, "  attr %s=\"%s\"\n", p[0], p[1]);
+#endif
+
+  next_state = xmalloc (sizeof (struct xml_state_stack));
+  memset (next_state, 0, sizeof (struct xml_state_stack));
+
+  /* Map the element we're entering to our known elements.  */
+  if (strcmp (name, "target") == 0)
+    next_phase = PHASE_IN_TARGET;
+  else if (strcmp (name, "feature") == 0)
+    next_phase = PHASE_IN_FEATURE;
+  else if (strcmp (name, "description") == 0)
+    next_phase = PHASE_IN_DESCRIPTION;
+  else if (strcmp (name, "reg") == 0)
+    next_phase = PHASE_IN_REG;
+  else if (strcmp (name, "feature-set") == 0)
+    next_phase = PHASE_IN_FEATURE_SET;
+  else if (strcmp (name, "feature-ref") == 0)
+    next_phase = PHASE_IN_FEATURE_REF;
+  else if (strcmp (name, "http://www.w3.org/2001/XInclude!include") == 0)
+    next_phase = PHASE_IN_XINCLUDE;
+  else
+    next_phase = PHASE_UNKNOWN;
+
+  /* Make sure that the next phase is sensible.  */
+  switch (data->state->phase)
+    {
+    case PHASE_TOP:
+      if (next_phase == PHASE_IN_TARGET
+         && !data->state->u.top.seen_target)
+       {
+         data->state->u.top.seen_target = 1;
+         break;
+       }
+      if (next_phase == PHASE_IN_FEATURE
+         && !data->state->u.top.seen_target
+         && data->state->u.top.nested)
+       {
+         data->state->u.top.seen_target = 1;
+         break;
+       }
+      next_phase = PHASE_UNKNOWN;
+      break;
+
+    case PHASE_IN_TARGET:
+      if (next_phase == PHASE_IN_FEATURE
+         && !data->state->u.target.seen_feature_set)
+       break;
+      if (next_phase == PHASE_IN_XINCLUDE
+         && !data->state->u.target.seen_feature_set)
+       break;
+      if (next_phase == PHASE_IN_FEATURE_SET
+         && !data->state->u.target.seen_feature_set)
+       {
+         if (data->state->u.target.features_only)
+           {
+             /* Skip parsing the feature set.  This is not an
+                error, so counteract the increment of data->unhandled
+                below.  */
+             next_phase = PHASE_UNKNOWN;
+             data->unhandled--;
+           }
+
+         data->state->u.target.seen_feature_set = 1;
+         break;
+       }
+      next_phase = PHASE_UNKNOWN;
+      break;
+
+    case PHASE_IN_FEATURE:
+      if (next_phase == PHASE_IN_DESCRIPTION
+         && !data->state->u.feature.seen_reg)
+       break;
+      if (next_phase == PHASE_IN_REG)
+       {
+         data->state->u.feature.seen_reg = 1;
+         break;
+       }
+      next_phase = PHASE_UNKNOWN;
+      break;
+
+    case PHASE_IN_DESCRIPTION:
+      next_phase = PHASE_UNKNOWN;
+      break;
+
+    case PHASE_IN_REG:
+      if (next_phase == PHASE_IN_DESCRIPTION)
+       break;
+      next_phase = PHASE_UNKNOWN;
+      break;
+
+    case PHASE_IN_FEATURE_SET:
+      if (next_phase == PHASE_IN_FEATURE_REF)
+       break;
+      next_phase = PHASE_UNKNOWN;
+      break;
+
+    case PHASE_IN_FEATURE_REF:
+    case PHASE_IN_XINCLUDE:
+      next_phase = PHASE_UNKNOWN;
+      break;
+
+    case PHASE_UNKNOWN:
+    default:
+      internal_error (__FILE__, __LINE__, "unexpected current state");
+      break;
+    }
+
+  next_state->phase = next_phase;
+  next_state->prev = data->state;
+  data->state = next_state;
+
+  /* FIXME: Check for unknown attributes in more elements, e.g. target.  */
+  /* FIXME: Check for missing mandatory elements more thoroughly.  */
+
+  switch (next_phase)
+    {
+    case PHASE_TOP:
+      internal_error (__FILE__, __LINE__, "unexpected next state");
+      break;
+
+    case PHASE_IN_TARGET:
+      if (data->state->prev->u.top.nested)
+       data->state->u.target.features_only = 1;
+      break;
+
+    case PHASE_IN_FEATURE:
+      xml_start_feature (data, attrs);
+      break;
+
+    case PHASE_IN_DESCRIPTION:
+      /* FIXME: Currently, descriptions are ignored.  */
+      break;
+
+    case PHASE_IN_REG:
+      xml_start_reg (data, attrs);
+      break;
+
+    case PHASE_IN_FEATURE_SET:
+      /* Nothing needed.  */
+      break;
+
+    case PHASE_IN_FEATURE_REF:
+      xml_start_feature_ref (data, attrs);
+      break;
+
+    case PHASE_IN_XINCLUDE:
+      xml_start_xinclude (data, attrs);
+      break;
+
+    case PHASE_UNKNOWN:
+      data->unhandled++;
+      next_state->u.unknown.depth++;
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__, "unexpected next state");
+      break;
+    }
+}
+
+static void XMLCALL
+xml_feature_end_element (void *data_, const XML_Char *name)
+{
+  struct xml_feature_parse_data *data = data_;
+  struct xml_state_stack *state;
+  struct gdb_available_feature *feature;
+  struct gdb_available_register *reg;
+
+#if 1
+  fprintf_unfiltered (gdb_stderr, "leaving, name %s\n", name);
+#endif
+
+  switch (data->state->phase)
+    {
+    case PHASE_UNKNOWN:
+      data->state->u.unknown.depth--;
+      if (data->state->u.unknown.depth)
+       return;
+      break;
+
+    case PHASE_IN_TARGET:
+      break;
+
+    case PHASE_IN_FEATURE:
+      feature = data->state->u.feature.feature;
+
+      /* Do nothing if a fatal error occured.  */
+      if (feature == NULL)
+       break;
+
+      /* Record the feature.  */
+      feature->next = data->seen_features;
+      data->seen_features = feature;
+
+      /* Reverse the list of registers.  */
+      if (feature->registers)
+       {
+         struct gdb_available_register *reg1, *reg2, *reg3;
+
+         reg1 = NULL;
+         reg2 = feature->registers;
+
+         while (reg2)
+           {
+             reg3 = reg2->next;
+             reg2->next = reg1;
+             reg1 = reg2;
+             reg2 = reg3;
+           }
+
+         feature->registers = reg1;
+       }
+
+      break;
+
+    case PHASE_IN_DESCRIPTION:
+      /* FIXME: Currently, descriptions are ignored.  */
+      break;
+
+    case PHASE_IN_REG:
+      gdb_assert (data->state->prev->phase == PHASE_IN_FEATURE);
+
+      feature = data->state->prev->u.feature.feature;
+      reg = data->state->u.reg.reg;
+
+      /* Do nothing if a fatal error occured, either here
+        or in the containing feature.  */
+      if (reg == NULL || feature == NULL)
+       break;
+
+      reg->next = feature->registers;
+      feature->registers = reg;
+      break;
+
+    case PHASE_IN_FEATURE_SET:
+      /* Reverse the list of features.  */
+      if (data->target_features)
+       {
+         struct gdb_available_feature *feat1, *feat2, *feat3;
+
+         feat1 = NULL;
+         feat2 = data->target_features;
+
+         while (feat2)
+           {
+             feat3 = feat2->next;
+             feat2->next = feat1;
+             feat1 = feat2;
+             feat2 = feat3;
+           }
+
+         data->target_features = feat1;
+       }
+      break;
+
+    case PHASE_IN_FEATURE_REF:
+    case PHASE_IN_XINCLUDE:
+      /* Nothing needed.  */
+      break;
+
+    case PHASE_TOP:
+    default:
+      internal_error (__FILE__, __LINE__, "unexpected ending state");
+      break;
+    }
+
+  state = data->state;
+  data->state = data->state->prev;
+  xfree (state);
+}
+
+static void
+xml_parser_cleanup (void *parser)
+{
+  struct xml_feature_parse_data *data;
+
+  data = XML_GetUserData (parser);
+  while (data->state)
+    {
+      struct xml_state_stack *prev;
+
+      prev = data->state->prev;
+      xfree (data->state);
+      data->state = prev;
+    }
+
+  XML_ParserFree (parser);
+}
+
+static int XMLCALL
+xml_feature_external_entity (XML_Parser parser,
+                            const XML_Char *context,
+                            const XML_Char *base,
+                            const XML_Char *systemId,
+                            const XML_Char *publicId)
+{
+  struct xml_feature_parse_data *data;
+  XML_Parser entity_parser;
+  char *text;
+  struct cleanup *back_to;
+
+  data = XML_GetUserData (parser);
+  if (data->fetcher == NULL)
+    return XML_STATUS_ERROR;
+
+  text = data->fetcher (systemId, data->fetcher_baton);
+  if (text == NULL)
+    return XML_STATUS_ERROR;
+
+  entity_parser = XML_ExternalEntityParserCreate (parser, context, NULL);
+  back_to = make_cleanup (xml_parser_cleanup, entity_parser);
+
+  XML_SetElementHandler (entity_parser, NULL, NULL);
+
+  if (XML_Parse (entity_parser, text, strlen (text), 1) != XML_STATUS_OK)
+    {
+      do_cleanups (back_to);
+      return XML_STATUS_ERROR;
+    }
+
+  do_cleanups (back_to);
+  return XML_STATUS_OK;
+}
+
+/* FIXME: Error check more XML_* calls.  */
+
+int
+available_features_from_xml_string (struct gdb_available_feature **features_p,
+                                   struct obstack *obstack,
+                                   const char *text, xml_fetch_another fetcher,
+                                   void *fetcher_baton,
+                                   int nested)
+{
+  XML_Parser parser;
+  struct xml_feature_parse_data *data;
+  struct cleanup *back_to;
+
+  parser = XML_ParserCreateNS (NULL, '!');
+  if (parser == NULL)
+    return -1;
+  back_to = make_cleanup (xml_parser_cleanup, parser);
+
+  data = XCALLOC (1, struct xml_feature_parse_data);
+  make_cleanup (xfree, data);
+  XML_SetUserData (parser, data);
+
+  data->obstack = obstack;
+  data->state = XCALLOC (1, struct xml_state_stack);
+  data->state->phase = PHASE_TOP;
+  data->state->u.top.nested = nested;
+
+  data->fetcher = fetcher;
+  data->fetcher_baton = fetcher_baton;
+
+  XML_SetElementHandler (parser, xml_feature_start_element,
+                        xml_feature_end_element);
+
+  XML_SetParamEntityParsing (parser,
+                            XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
+  XML_SetExternalEntityRefHandler (parser, xml_feature_external_entity);
+
+  /* FIXME: Enable this after we compile in the DTD?  */
+  /* XML_UseForeignDTD (parser, XML_TRUE); */
+
+  if (XML_Parse (parser, text, strlen (text), 1) != XML_STATUS_OK)
+    {
+      enum XML_Error err = XML_GetErrorCode (parser);
+
+      warning (_("XML parsing error: %s"), XML_ErrorString (err));
+      return -1;
+    }
+
+  if (nested)
+    *features_p = data->seen_features;
+  else
+    *features_p = data->target_features;
+
+  /* TODO: If data->unhandled, warn?  */
+  /* TODO: Can other errors be fatal?  */
+  /* TODO: Should *features_p == NULL be an error?  */
+
+  do_cleanups (back_to);
+
+  return 0;
+}
+
+static void
+do_cleanup_fclose (void *file)
+{
+  fclose (file);
+}
+
+static char *
+fetch_available_features_from_file (const char *filename, void *base_)
+{
+  const char *base = base_;
+  FILE *file;
+  struct cleanup *back_to;
+  char *text;
+  size_t len, offset;
+
+  if (base && *base)
+    {
+      char *fullname = concat (base, "/", filename, NULL);
+      if (fullname == NULL)
+       nomem (0);
+      file = fopen (fullname, FOPEN_RT);
+      xfree (fullname);
+    }
+  else
+    file = fopen (filename, FOPEN_RT);
+
+  if (file == NULL)
+    return NULL;
+  back_to = make_cleanup (do_cleanup_fclose, file);
+
+  /* Read in the whole file.  */
+  len = 4096;
+  offset = 0;
+  text = xmalloc (len);
+  make_cleanup (free_current_contents, &text);
+  while (1)
+    {
+      size_t bytes_read;
+
+      bytes_read = fread (text + offset, 1, len - offset, file);
+      if (ferror (file))
+       {
+         warning (_("Could not read from \"%s\""), filename);
+         do_cleanups (back_to);
+         return NULL;
+       }
+
+      if (feof (file))
+       break;
+
+      offset += bytes_read;
+      len += len;
+      text = xrealloc (text, len);
+    }
+
+  fclose (file);
+  discard_cleanups (back_to);
+
+  return text;
+}
+
+int
+available_features_from_xml_file (struct gdb_available_feature **feature_p,
+                                 struct obstack *obstack,
+                                 const char *filename)
+{
+  struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+  const char *p;
+  char *dirname, *text;
+
+  text = fetch_available_features_from_file (filename, NULL);
+  if (text == NULL)
+    return -1;
+
+  /* Simple, portable version of dirname that does not modify its
+     argument.  */
+  p = lbasename (filename);
+  while (p > filename && IS_DIR_SEPARATOR (p[-1]))
+    --p;
+  if (p > filename)
+    {
+      dirname = xmalloc (p - filename + 1);
+      memcpy (dirname, filename, p - filename);
+      dirname[p - filename] = '\0';
+      make_cleanup (xfree, dirname);
+    }
+  else
+    dirname = NULL;
+
+  available_features_from_xml_string (feature_p, obstack, text,
+                                     fetch_available_features_from_file,
+                                     dirname, 0);
+
+  do_cleanups (back_to);
+
+  return 0;
+}
+
+/* For debugging.  */
+
+int
+try_available_features_from_xml_file (const char *filename)
+{
+  struct obstack obstack;
+  struct gdb_available_feature *feature;
+  int ret;
+
+  obstack_init (&obstack);
+  ret = available_features_from_xml_file (&feature, &obstack, filename);
+  obstack_free (&obstack, NULL);
+
+  return ret;
+}
index 1fd45a3cfc30ce84fdb58099b744a49714430e2f..143a63975dcc55eaa3111eb0e6f4d6b1b6324f68 100644 (file)
@@ -6122,7 +6122,8 @@ procfs_make_note_section (bfd *obfd, int *note_size)
       note_data = thread_args.note_data;
     }
 
-  auxv_len = target_auxv_read (&current_target, &auxv);
+  auxv_len = target_read_whole (&current_target, TARGET_OBJECT_AUXV, NULL,
+                               &auxv);
   if (auxv_len > 0)
     {
       note_data = elfcore_write_note (obfd, note_data, note_size,
index 5dc7ab43601712c9c3cfebc912cec5c16e9fcf5e..1a01cc0b7481ad72023607ed4ca4787eb1746d10 100644 (file)
@@ -45,6 +45,7 @@
 #include "solib.h"
 #include "cli/cli-decode.h"
 #include "cli/cli-setshow.h"
+#include "available.h"
 
 #include <ctype.h>
 #include <sys/time.h>
@@ -214,7 +215,7 @@ struct remote_state
   long sizeof_g_packet;
 
   /* Description of the remote protocol registers indexed by REGNUM
-     (making an array of NUM_REGS + NUM_PSEUDO_REGS in size).  */
+     (making an array NUM_REGS in size).  */
   struct packet_reg *regs;
 
   /* This is the size (in chars) of the first response to the ``g''
@@ -245,23 +246,29 @@ init_remote_state (struct gdbarch *gdbarch)
 {
   int regnum;
   struct remote_state *rs = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct remote_state);
+  int num_g_regs;
+
+  if (gdbarch_remote_num_g_packet_regs_p (gdbarch))
+    num_g_regs = gdbarch_remote_num_g_packet_regs (gdbarch);
+  else
+    num_g_regs = NUM_REGS;
 
   rs->sizeof_g_packet = 0;
 
-  /* Assume a 1:1 regnum<->pnum table.  */
-  rs->regs = GDBARCH_OBSTACK_CALLOC (gdbarch, NUM_REGS + NUM_PSEUDO_REGS,
-                                    struct packet_reg);
-  for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
+  /* Assume a 1:1 regnum<->pnum table unless the available registers
+     interface informs us otherwise.  */
+  rs->regs = GDBARCH_OBSTACK_CALLOC (gdbarch, NUM_REGS, struct packet_reg);
+  for (regnum = 0; regnum < NUM_REGS; regnum++)
     {
       struct packet_reg *r = &rs->regs[regnum];
-      r->pnum = regnum;
+      r->pnum = available_register_target_regnum (gdbarch, regnum);
       r->regnum = regnum;
       r->offset = DEPRECATED_REGISTER_BYTE (regnum);
-      r->in_g_packet = (regnum < NUM_REGS);
+      r->in_g_packet = (regnum < num_g_regs);
       /* ...name = REGISTER_NAME (regnum); */
 
       /* Compute packet size by accumulating the size of all registers.  */
-      if (regnum < NUM_REGS)
+      if (r->in_g_packet)
        rs->sizeof_g_packet += register_size (current_gdbarch, regnum);
     }
 
@@ -292,7 +299,7 @@ init_remote_state (struct gdbarch *gdbarch)
 static struct packet_reg *
 packet_reg_from_regnum (struct remote_state *rs, long regnum)
 {
-  if (regnum < 0 && regnum >= NUM_REGS + NUM_PSEUDO_REGS)
+  if (regnum < 0 && regnum >= NUM_REGS)
     return NULL;
   else
     {
@@ -306,7 +313,7 @@ static struct packet_reg *
 packet_reg_from_pnum (struct remote_state *rs, LONGEST pnum)
 {
   int i;
-  for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+  for (i = 0; i < NUM_REGS; i++)
     {
       struct packet_reg *r = &rs->regs[i];
       if (r->pnum == pnum)
@@ -741,6 +748,7 @@ enum {
   PACKET_Z3,
   PACKET_Z4,
   PACKET_qPart_auxv,
+  PACKET_qPart_features,
   PACKET_qGetTLSAddr,
   PACKET_MAX
 };
@@ -3031,60 +3039,64 @@ got_status:
   return inferior_ptid;
 }
 
-/* Number of bytes of registers this stub implements.  */
-
-static int register_bytes_found;
-
-/* Read the remote registers into the block REGS.  */
-/* Currently we just read all the registers, so we don't use regnum.  */
+/* Fetch a single register using a 'p' packet.  */
 
 static int
-fetch_register_using_p (int regnum)
+fetch_register_using_p (struct packet_reg *reg)
 {
   struct remote_state *rs = get_remote_state ();
   char *buf = alloca (rs->remote_packet_size), *p;
   char regp[MAX_REGISTER_SIZE];
   int i;
 
+  if (remote_protocol_packets[PACKET_p].support == PACKET_DISABLE)
+    return 0;
+
   p = buf;
   *p++ = 'p';
-  p += hexnumstr (p, regnum);
+  p += hexnumstr (p, reg->pnum);
   *p++ = '\0';
   remote_send (buf, rs->remote_packet_size);
 
-  /* If the stub didn't recognize the packet, or if we got an error,
-     tell our caller.  */
-  if (buf[0] == '\0' || buf[0] == 'E')
-    return 0;
+  switch (packet_ok (buf, &remote_protocol_packets[PACKET_p]))
+    {
+    case PACKET_OK:
+      break;
+    case PACKET_UNKNOWN:
+      return 0;
+    case PACKET_ERROR:
+      error (_("Could not fetch register \"%s\""),
+            gdbarch_register_name (current_gdbarch, reg->regnum));
+    }
 
-  /* If this register is unfetchable, tell the regcache.  */
   if (buf[0] == 'x')
     {
-      regcache_raw_supply (current_regcache, regnum, NULL);
-      set_register_cached (regnum, -1);
+      regcache_raw_supply (current_regcache, reg->regnum, NULL);
+      set_register_cached (reg->regnum, -1);
       return 1;
     }
 
-  /* Otherwise, parse and supply the value.  */
   p = buf;
   i = 0;
   while (p[0] != 0)
     {
       if (p[1] == 0)
-        {
-          error (_("fetch_register_using_p: early buf termination"));
-          return 0;
-        }
-
+       error (_("fetch_register_using_p: early buf termination"));
       regp[i++] = fromhex (p[0]) * 16 + fromhex (p[1]);
       p += 2;
     }
-  regcache_raw_supply (current_regcache, regnum, regp);
+  regcache_raw_supply (current_regcache, reg->regnum, regp);
   return 1;
 }
 
+/* Number of bytes of registers this stub implements.  */
+
+static int register_bytes_found;
+
+/* Fetch the registers included in the target's 'g' packet.  */
+
 static void
-remote_fetch_registers (int regnum)
+fetch_registers_using_g (void)
 {
   struct remote_state *rs = get_remote_state ();
   char *buf = alloca (rs->remote_packet_size);
@@ -3094,41 +3106,6 @@ remote_fetch_registers (int regnum)
 
   set_thread (PIDGET (inferior_ptid), 1);
 
-  if (regnum >= 0)
-    {
-      struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
-      gdb_assert (reg != NULL);
-      if (!reg->in_g_packet)
-       internal_error (__FILE__, __LINE__,
-                       _("Attempt to fetch a non G-packet register when this "
-                       "remote.c does not support the p-packet."));
-    }
-      switch (remote_protocol_packets[PACKET_p].support)
-       {
-       case PACKET_DISABLE:
-         break;
-       case PACKET_ENABLE:
-         if (fetch_register_using_p (regnum))
-           return;
-         else
-           error (_("Protocol error: p packet not recognized by stub"));
-       case PACKET_SUPPORT_UNKNOWN:
-         if (fetch_register_using_p (regnum))
-           {
-             /* The stub recognized the 'p' packet.  Remember this.  */
-             remote_protocol_packets[PACKET_p].support = PACKET_ENABLE;
-             return;
-           }
-         else
-           {
-             /* The stub does not support the 'P' packet.  Use 'G'
-                instead, and don't try using 'P' in the future (it
-                will just waste our time).  */
-             remote_protocol_packets[PACKET_p].support = PACKET_DISABLE;
-             break;
-           }
-       }
-
   sprintf (buf, "g");
   remote_send (buf, rs->remote_packet_size);
 
@@ -3189,7 +3166,7 @@ remote_fetch_registers (int regnum)
  supply_them:
   {
     int i;
-    for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+    for (i = 0; i < NUM_REGS; i++)
       {
        struct packet_reg *r = &rs->regs[i];
        if (r->in_g_packet)
@@ -3216,6 +3193,39 @@ remote_fetch_registers (int regnum)
   }
 }
 
+static void
+remote_fetch_registers (int regnum)
+{
+  struct remote_state *rs = get_remote_state ();
+  int i;
+
+  set_thread (PIDGET (inferior_ptid), 1);
+
+  if (regnum >= 0)
+    {
+      struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
+      gdb_assert (reg != NULL);
+
+      if (fetch_register_using_p (reg))
+       return;
+
+      if (!reg->in_g_packet)
+       error (_("Protocol error: register \"%s\" not supported by stub"),
+              gdbarch_register_name (current_gdbarch, reg->regnum));
+
+      fetch_registers_using_g ();
+      return;
+    }
+
+  fetch_registers_using_g ();
+
+  for (i = 0; i < NUM_REGS; i++)
+    if (!rs->regs[i].in_g_packet)
+      if (!fetch_register_using_p (&rs->regs[i]))
+       error (_("Protocol error: register \"%s\" not supported by stub"),
+              gdbarch_register_name (current_gdbarch, rs->regs[i].regnum));
+}
+
 /* Prepare to store registers.  Since we may send them all (using a
    'G' request), we have to read out the ones we don't want to change
    first.  */
@@ -3246,74 +3256,55 @@ remote_prepare_to_store (void)
    packet was not recognized.  */
 
 static int
-store_register_using_P (int regnum)
+store_register_using_P (struct packet_reg *reg)
 {
   struct remote_state *rs = get_remote_state ();
-  struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
   /* Try storing a single register.  */
   char *buf = alloca (rs->remote_packet_size);
   gdb_byte regp[MAX_REGISTER_SIZE];
   char *p;
 
+  if (remote_protocol_packets[PACKET_P].support == PACKET_DISABLE)
+    return 0;
+
   xsnprintf (buf, rs->remote_packet_size, "P%s=", phex_nz (reg->pnum, 0));
   p = buf + strlen (buf);
   regcache_raw_collect (current_regcache, reg->regnum, regp);
   bin2hex (regp, p, register_size (current_gdbarch, reg->regnum));
   remote_send (buf, rs->remote_packet_size);
 
-  return buf[0] != '\0';
+  switch (packet_ok (buf, &remote_protocol_packets[PACKET_P]))
+    {
+    case PACKET_OK:
+      return 1;
+    case PACKET_ERROR:
+      error (_("Could not write register \"%s\""),
+            gdbarch_register_name (current_gdbarch, reg->regnum));
+    case PACKET_UNKNOWN:
+      return 0;
+    default:
+      internal_error (__FILE__, __LINE__, _("Bad result from packet_ok"));
+    }
 }
 
-
 /* Store register REGNUM, or all registers if REGNUM == -1, from the
    contents of the register cache buffer.  FIXME: ignores errors.  */
 
 static void
-remote_store_registers (int regnum)
+store_registers_using_G ()
 {
   struct remote_state *rs = get_remote_state ();
   char *buf;
   gdb_byte *regs;
   char *p;
 
-  set_thread (PIDGET (inferior_ptid), 1);
-
-  if (regnum >= 0)
-    {
-      switch (remote_protocol_packets[PACKET_P].support)
-       {
-       case PACKET_DISABLE:
-         break;
-       case PACKET_ENABLE:
-         if (store_register_using_P (regnum))
-           return;
-         else
-           error (_("Protocol error: P packet not recognized by stub"));
-       case PACKET_SUPPORT_UNKNOWN:
-         if (store_register_using_P (regnum))
-           {
-             /* The stub recognized the 'P' packet.  Remember this.  */
-             remote_protocol_packets[PACKET_P].support = PACKET_ENABLE;
-             return;
-           }
-         else
-           {
-             /* The stub does not support the 'P' packet.  Use 'G'
-                instead, and don't try using 'P' in the future (it
-                will just waste our time).  */
-             remote_protocol_packets[PACKET_P].support = PACKET_DISABLE;
-             break;
-           }
-       }
-    }
-
   /* Extract all the registers in the regcache copying them into a
      local buffer.  */
   {
     int i;
     regs = alloca (rs->sizeof_g_packet);
     memset (regs, 0, rs->sizeof_g_packet);
-    for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+    for (i = 0; i < NUM_REGS; i++)
       {
        struct packet_reg *r = &rs->regs[i];
        if (r->in_g_packet)
@@ -3330,6 +3321,42 @@ remote_store_registers (int regnum)
   bin2hex (regs, p, register_bytes_found);
   remote_send (buf, rs->remote_packet_size);
 }
+
+/* Store register REGNUM, or all registers if REGNUM == -1, from the contents
+   of the register cache buffer.  FIXME: ignores errors.  */
+
+static void
+remote_store_registers (int regnum)
+{
+  struct remote_state *rs = get_remote_state ();
+  int i;
+
+  set_thread (PIDGET (inferior_ptid), 1);
+
+  if (regnum >= 0)
+    {
+      struct packet_reg *reg = packet_reg_from_regnum (rs, regnum);
+      gdb_assert (reg != NULL);
+
+      if (store_register_using_P (reg))
+       return;
+
+      if (!reg->in_g_packet)
+       error (_("Protocol error: register \"%s\" not supported by stub"),
+              gdbarch_register_name (current_gdbarch, reg->regnum));
+
+      store_registers_using_G ();
+      return;
+    }
+
+  store_registers_using_G ();
+
+  for (i = 0; i < NUM_REGS; i++)
+    if (!rs->regs[i].in_g_packet)
+      if (!store_register_using_P (&rs->regs[i]))
+       error (_("Protocol error: register \"%s\" not supported by stub"),
+              gdbarch_register_name (current_gdbarch, rs->regs[i].regnum));
+}
 \f
 
 /* Return the number of hex digits in num.  */
@@ -4763,6 +4790,49 @@ the loaded file\n"));
     printf_filtered (_("No loaded section named '%s'.\n"), args);
 }
 
+/* Read OBJECT_NAME/ANNEX from the remote target using a qPart packet.
+   Data at OFFSET, of up to LEN bytes, is read into READBUF; the
+   number of bytes read is returned, or 0 for EOF, or -1 for error.
+   The number of bytes read may be less than LEN without indicating an
+   EOF.  PACKET is checked and updated to indicate whether the remote
+   target supports this object.  */
+
+static LONGEST
+remote_read_qpart (struct target_ops *ops, const char *object_name,
+                  const char *annex,
+                  gdb_byte *readbuf, ULONGEST offset, LONGEST len,
+                  struct packet_config *packet)
+{
+  struct remote_state *rs = get_remote_state ();
+  char *buf2 = alloca (rs->remote_packet_size);
+  unsigned int total = 0;
+  LONGEST i, n;
+
+  if (packet->support == PACKET_DISABLE)
+    return -1;
+
+  n = min ((rs->remote_packet_size - 2) / 2, len);
+  snprintf (buf2, rs->remote_packet_size, "qPart:%s:read:%s:%s,%s",
+           object_name, annex ? annex : "",
+           phex_nz (offset, sizeof offset),
+           phex_nz (n, sizeof n));
+  i = putpkt (buf2);
+  if (i < 0)
+    return -1;
+
+  buf2[0] = '\0';
+  getpkt (buf2, rs->remote_packet_size, 0);
+  if (packet_ok (buf2, packet) != PACKET_OK)
+    return -1;
+
+  if (buf2[0] == 'O' && buf2[1] == 'K' && buf2[2] == '\0')
+    return 0;          /* Got EOF indicator.  */
+
+  /* Got some data.  */
+  i = hex2bin (buf2, readbuf, len);
+  return i;
+}
+
 static LONGEST
 remote_xfer_partial (struct target_ops *ops, enum target_object object,
                     const char *annex, gdb_byte *readbuf,
@@ -4770,8 +4840,7 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
 {
   struct remote_state *rs = get_remote_state ();
   int i;
-  char *buf2 = alloca (rs->remote_packet_size);
-  char *p2 = &buf2[0];
+  char *buf2, *p2;
   char query_type;
 
   /* Handle memory using remote_xfer_memory.  */
@@ -4815,39 +4884,13 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
       break;
 
     case TARGET_OBJECT_AUXV:
-      if (remote_protocol_packets[PACKET_qPart_auxv].support != PACKET_DISABLE)
-       {
-         unsigned int total = 0;
-         while (len > 0)
-           {
-             LONGEST n = min ((rs->remote_packet_size - 2) / 2, len);
-             snprintf (buf2, rs->remote_packet_size,
-                       "qPart:auxv:read::%s,%s",
-                       phex_nz (offset, sizeof offset),
-                       phex_nz (n, sizeof n));
-             i = putpkt (buf2);
-             if (i < 0)
-               return total > 0 ? total : i;
-             buf2[0] = '\0';
-             getpkt (buf2, rs->remote_packet_size, 0);
-             if (packet_ok (buf2, &remote_protocol_packets[PACKET_qPart_auxv])
-                 != PACKET_OK)
-               return total > 0 ? total : -1;
-             if (buf2[0] == 'O' && buf2[1] == 'K' && buf2[2] == '\0')
-               break;          /* Got EOF indicator.  */
-             /* Got some data.  */
-             i = hex2bin (buf2, readbuf, len);
-             if (i > 0)
-               {
-                 readbuf = (void *) ((char *) readbuf + i);
-                 offset += i;
-                 len -= i;
-                 total += i;
-               }
-           }
-         return total;
-       }
-      return -1;
+      gdb_assert (annex == NULL);
+      return remote_read_qpart (ops, "auxv", annex, readbuf, offset, len,
+                               &remote_protocol_packets[PACKET_qPart_auxv]);
+
+    case TARGET_OBJECT_AVAILABLE_FEATURES:
+      return remote_read_qpart (ops, "features", annex, readbuf, offset, len,
+                               &remote_protocol_packets[PACKET_qPart_features]);
 
     default:
       return -1;
@@ -4870,6 +4913,9 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
   gdb_assert (annex != NULL);
   gdb_assert (readbuf != NULL);
 
+  buf2 = alloca (rs->remote_packet_size);
+  p2 = &buf2[0];
+
   *p2++ = 'q';
   *p2++ = query_type;
 
@@ -5221,6 +5267,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_xfer_partial = remote_xfer_partial;
   remote_ops.to_rcmd = remote_rcmd;
   remote_ops.to_get_thread_local_address = remote_get_thread_local_address;
+  remote_ops.to_available_features = available_features_from_target_object;
   remote_ops.to_stratum = process_stratum;
   remote_ops.to_has_all_memory = 1;
   remote_ops.to_has_memory = 1;
@@ -5346,6 +5393,8 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
   remote_async_ops.to_stop = remote_stop;
   remote_async_ops.to_xfer_partial = remote_xfer_partial;
   remote_async_ops.to_rcmd = remote_rcmd;
+  remote_async_ops.to_available_features
+    = available_features_from_target_object;
   remote_async_ops.to_stratum = process_stratum;
   remote_async_ops.to_has_all_memory = 1;
   remote_async_ops.to_has_memory = 1;
@@ -5635,6 +5684,13 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
                         &remote_set_cmdlist, &remote_show_cmdlist,
                         0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qPart_features],
+                        "qPart_features", "target-features",
+                        set_remote_protocol_packet_cmd,
+                        show_remote_protocol_packet_cmd,
+                        &remote_set_cmdlist, &remote_show_cmdlist,
+                        0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
                         "qGetTLSAddr", "get-thread-local-storage-address",
                         set_remote_protocol_packet_cmd,
index dc6c5347a55de2dd527404366251d5501de5e5c9..aacdaa652e1e4b4e1c8b8b5fd4dd118fe115158d 100644 (file)
@@ -157,7 +157,7 @@ sparc_fetch_wcookie (void)
   gdb_byte buf[8];
   int len;
 
-  len = target_read_partial (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8);
+  len = target_read (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8);
   if (len == -1)
     return 0;
 
index 0cbd1fc5764c55f5521751ea4e75e701371a95a5..10361e795d9189dceedc57cf170c56550a2c66c2 100644 (file)
@@ -25,6 +25,8 @@
 
 /* This file requires that you first include "bfd.h".  */
 
+#include "symtab.h"
+
 /* Opaque declarations.  */
 struct section_table;
 struct objfile;
index 3da3e651311693fced34f065c8fec404be33ae5e..80b7b7111429825a1d497e0c0cb2b65c11de6a33 100644 (file)
@@ -457,6 +457,7 @@ update_current_target (void)
       INHERIT (to_find_memory_regions, t);
       INHERIT (to_make_corefile_notes, t);
       INHERIT (to_get_thread_local_address, t);
+      /* Do not inherit to_available_features.  */
       INHERIT (to_magic, t);
     }
 #undef INHERIT
@@ -634,6 +635,7 @@ update_current_target (void)
   de_fault (to_async, 
            (void (*) (void (*) (enum inferior_event_type, void*), void*)) 
            tcomplain);
+  current_target.to_available_features = NULL;
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
@@ -1378,8 +1380,9 @@ target_read (struct target_ops *ops,
                                          (gdb_byte *) buf + xfered,
                                          offset + xfered, len - xfered);
       /* Call an observer, notifying them of the xfer progress?  */
-      if (xfer <= 0)
-       /* Call memory_error?  */
+      if (xfer == 0)
+       return xfered;
+      if (xfer < 0)
        return -1;
       xfered += xfer;
       QUIT;
@@ -1400,8 +1403,9 @@ target_write (struct target_ops *ops,
                                           (gdb_byte *) buf + xfered,
                                           offset + xfered, len - xfered);
       /* Call an observer, notifying them of the xfer progress?  */
-      if (xfer <= 0)
-       /* Call memory_error?  */
+      if (xfer == 0)
+       return xfered;
+      if (xfer < 0)
        return -1;
       xfered += xfer;
       QUIT;
@@ -1409,6 +1413,45 @@ target_write (struct target_ops *ops,
   return len;
 }
 
+/* Perform a full target read of unknown size.  */
+
+LONGEST
+target_read_whole (struct target_ops *ops,
+                  enum target_object object,
+                  const char *annex, gdb_byte **buf_p)
+{
+  size_t buf_alloc = 512, buf_pos = 0;
+  gdb_byte *buf = xmalloc (buf_alloc);
+  LONGEST n, total;
+
+  total = 0;
+  while (1)
+    {
+      n = target_read (ops, object, annex, &buf[buf_pos],
+                      buf_pos, buf_alloc - buf_pos);
+      if (n < 0)
+       {
+         /* An error occurred.  */
+         xfree (buf);
+         return -1;
+       }
+
+      buf_pos += n;
+      if (buf_pos < buf_alloc)
+       {
+         /* Read all there was.  */
+         if (buf_pos == 0)
+           xfree (buf);
+         else
+           *buf_p = buf;
+         return buf_pos;
+       }
+
+      buf_alloc *= 2;
+      buf = xrealloc (buf, buf_alloc);
+    }
+}
+
 /* Memory transfer methods.  */
 
 void
@@ -1526,6 +1569,28 @@ target_follow_fork (int follow_child)
                  "could not find a target to follow fork");
 }
 
+/* Look for a target which can report architectural features, starting
+   from TARGET.  If we find one, return its features, using OBSTACK
+   for any temporary allocation.  */
+
+struct gdb_feature_set *
+target_available_features (struct target_ops *target, struct obstack *obstack)
+{
+  struct target_ops *t;
+
+  for (t = target; t != NULL; t = t->beneath)
+    if (t->to_available_features != NULL)
+      {
+       struct gdb_feature_set *features;
+
+       features = t->to_available_features (t, obstack);
+       if (features)
+         return features;
+      }
+
+  return NULL;
+}
+
 /* Look through the list of possible targets for a target that can
    execute a run or attach command without any other data.  This is
    used to locate the default process stratum.
index b804b05df4359a5c8158369023c4595fcb90d9f0..76d53d81c1a1ce3cdf60f133ccc6eae01dd94e59 100644 (file)
@@ -30,6 +30,7 @@ struct objfile;
 struct ui_file;
 struct mem_attrib;
 struct target_ops;
+struct gdb_feature_set;
 
 /* This include file defines the interface between the main part
    of the debugger, and the part which is target-specific, or
@@ -230,7 +231,12 @@ enum target_object
   /* Transfer auxilliary vector.  */
   TARGET_OBJECT_AUXV,
   /* StackGhost cookie.  See "sparc-tdep.c".  */
-  TARGET_OBJECT_WCOOKIE
+  TARGET_OBJECT_WCOOKIE,
+  /* Available target-specific features, e.g. registers and coprocessors.
+     See "available.c".  With an empty ANNEX this fetches a list of
+     features; with a comma-separated list of features in ANNEX this
+     fetches the details of the listed features.  */
+  TARGET_OBJECT_AVAILABLE_FEATURES
 
   /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
 };
@@ -245,7 +251,10 @@ extern LONGEST target_write_partial (struct target_ops *ops,
                                     const char *annex, const gdb_byte *buf,
                                     ULONGEST offset, LONGEST len);
 
-/* Wrappers to perform the full transfer.  */
+/* Wrappers to perform a full transfer.  These functions take the
+   same arguments as the partial versions, above, but a return
+   value of a positive number less than LEN implies that no more
+   data can be read or written.  */
 extern LONGEST target_read (struct target_ops *ops,
                            enum target_object object,
                            const char *annex, gdb_byte *buf,
@@ -256,6 +265,22 @@ extern LONGEST target_write (struct target_ops *ops,
                             const char *annex, const gdb_byte *buf,
                             ULONGEST offset, LONGEST len);
 
+/* Wrappers to perform a full read of unknown size.  OBJECT/ANNEX will
+   be read using OPS.  The return value will be -1 if the transfer
+   fails or is not supported; 0 if the object is empty; and the length
+   of the object otherwise.  If a positive value is returned, a
+   sufficiently large buffer will be allocated using xmalloc and
+   returned in *BUF_P containing the contents of the object.
+
+   This method should be used for objects sufficiently small to store
+   in a single xmalloced buffer, when no fixed bound on the object's
+   size is known in advance.  Don't try to read TARGET_OBJECT_MEMORY
+   through this function.  */
+
+extern LONGEST target_read_whole (struct target_ops *ops,
+                                 enum target_object object,
+                                 const char *annex, gdb_byte **buf_p);
+
 /* Wrappers to target read/write that perform memory transfers.  They
    throw an error if the memory transfer fails.
 
@@ -423,6 +448,13 @@ struct target_ops
                                gdb_byte *readbuf, const gdb_byte *writebuf,
                                ULONGEST offset, LONGEST len);
 
+    /* Describe the architecture-specific features of this target.
+       Returns the features found.  All pointers refer either to
+       constants or temporary memory allocated on the provided
+       obstack.  */
+    struct gdb_feature_set *(*to_available_features) (struct target_ops *ops,
+                                                     struct obstack *obstack);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1074,6 +1106,9 @@ extern int target_stopped_data_address_p (struct target_ops *);
 #define target_stopped_data_address_p(CURRENT_TARGET) (1)
 #endif
 
+extern struct gdb_feature_set *target_available_features (struct target_ops *,
+                                                         struct obstack *);
+
 /* This will only be defined by a target that supports catching vfork events,
    such as HP-UX.