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; };
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; };
maybe-configure-diff \
maybe-configure-dosutils \
maybe-configure-etc \
+ maybe-configure-expat \
maybe-configure-fastjar \
maybe-configure-fileutils \
maybe-configure-findutils \
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
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
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
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
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
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
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
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
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
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
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
maybe-check-diff \
maybe-check-dosutils \
maybe-check-etc \
+ maybe-check-expat \
maybe-check-fastjar \
maybe-check-fileutils \
maybe-check-findutils \
maybe-install-diff \
maybe-install-dosutils \
maybe-install-etc \
+ maybe-install-expat \
maybe-install-fastjar \
maybe-install-fileutils \
maybe-install-findutils \
maybe-install-diff \
maybe-install-dosutils \
maybe-install-etc \
+ maybe-install-expat \
maybe-install-fastjar \
maybe-install-fileutils \
maybe-install-findutils \
+.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
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
# 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
# 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
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)
$(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)
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)
LINT=/usr/5bin/lint
LINTFLAGS= $(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) \
- $(INTL_CFLAGS)
+ $(INTL_CFLAGS) $(EXPAT_CFLAGS)
RUNTEST = runtest
RUNTESTFLAGS=
# 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 \
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 \
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
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
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 \
$(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) \
$(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) \
$(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) \
$(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)
$(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) \
#include "trad-frame.h"
#include "objfiles.h"
#include "dwarf2-frame.h"
+#include "available.h"
#include "arm-tdep.h"
#include "gdb/sim-arm.h"
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)
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)
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];
}
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);
_("arm_gdbarch_init: bad byte order for float format"));
}
+ set_gdbarch_available_features_support (gdbarch, 1);
+
return gdbarch;
}
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.
{
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;
{
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;
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.
--- /dev/null
+/* 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 = ®->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;
+}
--- /dev/null
+/* 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 */
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 (¤t_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 (¤t_target, TARGET_OBJECT_AVR, query, buf, 0,
- bufsiz);
+ bufsiz = target_read_whole (¤t_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;
}
{
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);
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 (¤t_target, TARGET_OBJECT_AVR, query, buf,
- 0, bufsiz);
+ bufsiz = target_read_whole (¤t_target, TARGET_OBJECT_AVR, query,
+ &buf);
p = buf;
for (k = i; k < (i + j); k++)
break;
}
}
+
+ xfree (buf);
}
}
--- /dev/null
+<!-- 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>
#include "gdbcmd.h"
#include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
#include "symcat.h"
+#include "available.h"
#include "floatformat.h"
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;
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;
};
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 */
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() */
};
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 */
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",
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",
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);
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)
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)
{
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. */
}
-/* 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,
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;
struct disassemble_info;
struct target_ops;
struct obstack;
+struct gdb_feature_set;
extern struct gdbarch *current_gdbarch;
#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).
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.
/* 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);
/* 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. */
# 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
# 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
}
struct disassemble_info;
struct target_ops;
struct obstack;
+struct gdb_feature_set;
extern struct gdbarch *current_gdbarch;
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.
/* 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);
/* 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. */
#include "gdbcmd.h"
#include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
#include "symcat.h"
+#include "available.h"
#include "floatformat.h"
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
}
-/* 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,
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;
}
/* 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;
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 (¤t_target, TARGET_OBJECT_UNWIND_TABLE, NULL,
- buf, 0, len);
- return (int)x;
+ x = target_read_whole (¤t_target, TARGET_OBJECT_UNWIND_TABLE,
+ NULL, buf_p);
+
+ return x;
}
/* Get the kernel unwind table. */
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;
}
#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: */
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
note_data = thread_args.note_data;
}
- auxv_len = target_auxv_read (¤t_target, &auxv);
+ auxv_len = target_read_whole (¤t_target, TARGET_OBJECT_AUXV, NULL,
+ &auxv);
if (auxv_len > 0)
{
note_data = elfcore_write_note (obfd, note_data, note_size,
--- /dev/null
+/* 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 = ®->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, ®->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, ®->readonly) < 0)
+ data->unhandled++;
+ }
+
+ else if (strcmp (name, "save-restore") == 0)
+ {
+ if (xml_parse_one_boolean (val, ®->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;
+}
note_data = thread_args.note_data;
}
- auxv_len = target_auxv_read (¤t_target, &auxv);
+ auxv_len = target_read_whole (¤t_target, TARGET_OBJECT_AUXV, NULL,
+ &auxv);
if (auxv_len > 0)
{
note_data = elfcore_write_note (obfd, note_data, note_size,
#include "solib.h"
#include "cli/cli-decode.h"
#include "cli/cli-setshow.h"
+#include "available.h"
#include <ctype.h>
#include <sys/time.h>
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''
{
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);
}
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
{
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)
PACKET_Z3,
PACKET_Z4,
PACKET_qPart_auxv,
+ PACKET_qPart_features,
PACKET_qGetTLSAddr,
PACKET_MAX
};
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);
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);
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)
}
}
+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. */
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)
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. */
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,
{
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. */
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;
gdb_assert (annex != NULL);
gdb_assert (readbuf != NULL);
+ buf2 = alloca (rs->remote_packet_size);
+ p2 = &buf2[0];
+
*p2++ = 'q';
*p2++ = query_type;
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;
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;
&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,
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;
/* This file requires that you first include "bfd.h". */
+#include "symtab.h"
+
/* Opaque declarations. */
struct section_table;
struct objfile;
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
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
(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;
(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;
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
"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.
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
/* 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, ... */
};
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,
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.
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?
*/
#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.